Improve initialisation of OpenSSL PRNG.
[radsecproxy.git] / lib / tls.c
1 /* Copyright 2010-2013 NORDUnet A/S. All rights reserved.
2    See LICENSE for licensing information. */
3
4 #if defined HAVE_CONFIG_H
5 #include <config.h>
6 #endif
7
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <assert.h>
11 #include <fcntl.h>
12 #include <limits.h>
13 #include <openssl/ssl.h>
14 #include <openssl/err.h>
15 #include <openssl/bn.h>
16 #include <openssl/x509v3.h>
17 #include <openssl/rand.h>
18 #include <radsec/radsec.h>
19 #include <radsec/radsec-impl.h>
20
21 #include <regex.h>
22 #include "radsecproxy/list.h"
23 #include "radsecproxy/radsecproxy.h"
24
25 #include "tls.h"
26
27 static struct tls *
28 _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm)
29 {
30   struct tls *c = rs_malloc (conn->ctx, sizeof (struct tls));
31
32   if (c)
33     {
34       memset (c, 0, sizeof (struct tls));
35       /* TODO: Make sure old radsecproxy code doesn't free these all
36          of a sudden, or strdup them.  */
37       c->name = realm->name;
38       c->cacertfile = realm->cacertfile;
39       c->cacertpath = NULL;     /* NYI */
40       c->certfile = realm->certfile;
41       c->certkeyfile = realm->certkeyfile;
42       c->certkeypwd = NULL;     /* NYI */
43       c->cacheexpiry = 0;       /* NYI */
44       c->crlcheck = 0;          /* NYI */
45       c->policyoids = (char **) NULL; /* NYI */
46     }
47     else
48       rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
49
50   return c;
51 }
52
53 #if defined RS_ENABLE_TLS_PSK
54 static unsigned int
55 psk_client_cb (SSL *ssl,
56                const char *hint,
57                char *identity,
58                unsigned int max_identity_len,
59                unsigned char *psk,
60                unsigned int max_psk_len)
61 {
62   struct rs_connection *conn = NULL;
63   struct rs_credentials *cred = NULL;
64
65   conn = SSL_get_ex_data (ssl, 0);
66   assert (conn != NULL);
67   cred = conn->active_peer->realm->transport_cred;
68   assert (cred != NULL);
69   /* NOTE: Ignoring identity hint from server.  */
70
71   if (strlen (cred->identity) + 1 > max_identity_len)
72     {
73       rs_err_conn_push (conn, RSE_CRED, "PSK identity longer than max %d",
74                         max_identity_len - 1);
75       return 0;
76     }
77   strcpy (identity, cred->identity);
78
79   switch (cred->secret_encoding)
80     {
81     case RS_KEY_ENCODING_UTF8:
82       cred->secret_len = strlen (cred->secret);
83       if (cred->secret_len > max_psk_len)
84         {
85           rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
86                             max_psk_len);
87           return 0;
88         }
89       memcpy (psk, cred->secret, cred->secret_len);
90       break;
91     case RS_KEY_ENCODING_ASCII_HEX:
92       {
93         BIGNUM *bn = NULL;
94
95         if (BN_hex2bn (&bn, cred->secret) == 0)
96           {
97             rs_err_conn_push (conn, RSE_CRED, "Unable to convert pskhexstr");
98             if (bn != NULL)
99               BN_clear_free (bn);
100             return 0;
101           }
102         if ((unsigned int) BN_num_bytes (bn) > max_psk_len)
103           {
104             rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
105                              max_psk_len);
106             BN_clear_free (bn);
107             return 0;
108           }
109         cred->secret_len = BN_bn2bin (bn, psk);
110         BN_clear_free (bn);
111       }
112       break;
113     default:
114       assert (!"unknown psk encoding");
115     }
116
117   return cred->secret_len;
118 }
119 #endif  /* RS_ENABLE_TLS_PSK */
120
121 /** Read \a buf_len bytes from one of the random devices into \a
122     buf. Return 0 on success and -1 on failure. */
123 static int
124 load_rand_ (uint8_t *buf, size_t buf_len)
125 {
126   static const char *fns[] = {"/dev/urandom", "/dev/random", NULL};
127   int i;
128
129   if (buf_len > SSIZE_MAX)
130     return -1;
131
132   for (i = 0; fns[i] != NULL; i++)
133     {
134       size_t nread = 0;
135       int fd = open (fns[i], O_RDONLY);
136       if (fd < 0)
137         continue;
138       while (nread != buf_len)
139         {
140           ssize_t r = read (fd, buf + nread, buf_len - nread);
141           if (r < 0)
142             return -1;
143           if (r == 0)
144             break;
145           nread += r;
146         }
147       close (fd);
148       if (nread != buf_len)
149         return -1;
150       return 0;
151     }
152   return -1;
153 }
154
155 /** Initialise OpenSSL's PRNG by possibly invoking RAND_poll() and by
156     feeding RAND_seed() data from one of the random devices. If either
157     succeeds, we're happy and return 0. */
158 static int
159 init_openssl_rand_ (void)
160 {
161   long openssl_version = 0;
162   int openssl_random_init_flag = 0;
163   int our_random_init_flag = 0;
164   uint8_t buf[32];
165
166   /* Older OpenSSL has a crash bug in RAND_poll (when a file it opens
167      gets a file descriptor with a number higher than FD_SETSIZE) so
168      use it only for newer versions. */
169   openssl_version = SSLeay ();
170   if (openssl_version >= OPENSSL_V (0,9,8,'c'))
171     openssl_random_init_flag = RAND_poll ();
172
173   our_random_init_flag = !load_rand_ (buf, sizeof(buf));
174   if (our_random_init_flag)
175     RAND_seed (buf, sizeof(buf));
176   memset (buf, 0, sizeof(buf)); /* FIXME: What if memset() is optimised out? */
177
178   if (!openssl_random_init_flag && !our_random_init_flag)
179     return -1;
180   if (!RAND_bytes (buf, sizeof(buf)))
181     return -1;
182   return 0;
183 }
184
185 /** Initialise the TLS library. Return 0 on success, -1 on failure. */
186 int
187 tls_init (void)
188 {
189   SSL_load_error_strings ();
190   SSL_library_init ();
191   return init_openssl_rand_ ();
192 }
193
194 int
195 tls_init_conn (struct rs_connection *conn)
196 {
197   struct rs_context *ctx = NULL;
198   struct tls *tlsconf = NULL;
199   SSL_CTX *ssl_ctx = NULL;
200   SSL *ssl = NULL;
201   unsigned long sslerr = 0;
202
203   assert (conn->ctx);
204   ctx = conn->ctx;
205
206   tlsconf = _get_tlsconf (conn, conn->active_peer->realm);
207   if (!tlsconf)
208     return -1;
209   ssl_ctx = tlsgetctx (RAD_TLS, tlsconf);
210   if (!ssl_ctx)
211     {
212       for (sslerr = ERR_get_error (); sslerr; sslerr = ERR_get_error ())
213          rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
214                               ERR_error_string (sslerr, NULL));
215       return -1;
216     }
217   ssl = SSL_new (ssl_ctx);
218   if (!ssl)
219     {
220       for (sslerr = ERR_get_error (); sslerr; sslerr = ERR_get_error ())
221         rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
222                              ERR_error_string (sslerr, NULL));
223       return -1;
224     }
225
226 #if defined RS_ENABLE_TLS_PSK
227   if (conn->active_peer->realm->transport_cred != NULL)
228     {
229       SSL_set_psk_client_callback (ssl, psk_client_cb);
230       SSL_set_ex_data (ssl, 0, conn);
231     }
232 #endif  /* RS_ENABLE_TLS_PSK */
233
234   conn->tls_ctx = ssl_ctx;
235   conn->tls_ssl = ssl;
236   rs_free (ctx, tlsconf);
237   return RSE_OK;
238 }
239
240 /* draft-ietf-radext-radsec-11.txt
241
242        *  Certificate validation MUST include the verification rules as
243           per [RFC5280].
244
245        *  Implementations SHOULD indicate their acceptable Certification
246           Authorities as per section 7.4.4 (server side) and x.y.z
247           ["Trusted CA Indication"] (client side) of [RFC5246] (see
248           Section 3.2)
249
250        *  Implementations SHOULD allow to configure a list of acceptable
251           certificates, identified via certificate fingerprint.  When a
252           fingerprint configured, the fingerprint is prepended with an
253           ASCII label identifying the hash function followed by a colon.
254           Implementations MUST support SHA-1 as the hash algorithm and
255           use the ASCII label "sha-1" to identify the SHA-1 algorithm.
256           The length of a SHA-1 hash is 20 bytes and the length of the
257           corresponding fingerprint string is 65 characters.  An example
258           certificate fingerprint is: sha-
259           1:E1:2D:53:2B:7C:6B:8A:29:A2:76:C8:64:36:0B:08:4B:7A:F1:9E:9D
260
261        *  Peer validation always includes a check on whether the locally
262           configured expected DNS name or IP address of the server that
263           is contacted matches its presented certificate.  DNS names and
264           IP addresses can be contained in the Common Name (CN) or
265           subjectAltName entries.  For verification, only one of these
266           entries is to be considered.  The following precedence
267           applies: for DNS name validation, subjectAltName:DNS has
268           precedence over CN; for IP address validation, subjectAltName:
269           iPAddr has precedence over CN.
270
271        *  Implementations SHOULD allow to configure a set of acceptable
272           values for subjectAltName:URI.
273  */
274 int
275 tls_verify_cert (struct rs_connection *conn)
276 {
277   int err = 0;
278   int success = 0;
279   X509 *peer_cert = NULL;
280   struct in6_addr addr;
281   const char *hostname = NULL;
282
283   assert (conn->active_peer->conn == conn);
284   assert (conn->active_peer->hostname != NULL);
285   hostname = conn->active_peer->hostname;
286
287   /* verifytlscert() performs basic verification as described by
288      OpenSSL VERIFY(1), i.e. verification of the certificate chain.  */
289   peer_cert = verifytlscert (conn->tls_ssl);
290   if (peer_cert == NULL)
291     {
292       err = rs_err_conn_push (conn, RSE_SSLERR,
293                               "basic certificate validation failed");
294       goto out;
295     }
296
297   if (inet_pton (AF_INET, hostname, &addr))
298     success = (subjectaltnameaddr (peer_cert, AF_INET, &addr) == 1);
299   else if (inet_pton (AF_INET6, hostname, &addr))
300     success = (subjectaltnameaddr (peer_cert, AF_INET6, &addr) == 1);
301   else
302     success = (subjectaltnameregexp (peer_cert, GEN_DNS, hostname, NULL) == 1);
303
304   if (!success)
305     success = (cnregexp (peer_cert, hostname, NULL) == 1);
306
307   if (conn->realm->disable_hostname_check)
308     success = 1;
309   if (!success)
310     err = rs_err_conn_push (conn, RSE_CERT, "server certificate doesn't "
311                             "match configured hostname \"%s\"", hostname);
312
313  out:
314   if (peer_cert != NULL)
315     X509_free (peer_cert);
316   return err;
317 }