1 /* Copyright 2010-2013 NORDUnet A/S. All rights reserved.
2 See LICENSE for licensing information. */
4 #if defined HAVE_CONFIG_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>
22 #include "radsecproxy/list.h"
23 #include "radsecproxy/radsecproxy.h"
28 _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm)
30 struct tls *c = rs_malloc (conn->ctx, sizeof (struct tls));
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 */
48 rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
53 #if defined RS_ENABLE_TLS_PSK
55 psk_client_cb (SSL *ssl,
58 unsigned int max_identity_len,
60 unsigned int max_psk_len)
62 struct rs_connection *conn = NULL;
63 struct rs_credentials *cred = NULL;
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. */
71 if (strlen (cred->identity) + 1 > max_identity_len)
73 rs_err_conn_push (conn, RSE_CRED, "PSK identity longer than max %d",
74 max_identity_len - 1);
77 strcpy (identity, cred->identity);
79 switch (cred->secret_encoding)
81 case RS_KEY_ENCODING_UTF8:
82 cred->secret_len = strlen (cred->secret);
83 if (cred->secret_len > max_psk_len)
85 rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
89 memcpy (psk, cred->secret, cred->secret_len);
91 case RS_KEY_ENCODING_ASCII_HEX:
95 if (BN_hex2bn (&bn, cred->secret) == 0)
97 rs_err_conn_push (conn, RSE_CRED, "Unable to convert pskhexstr");
102 if ((unsigned int) BN_num_bytes (bn) > max_psk_len)
104 rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
109 cred->secret_len = BN_bn2bin (bn, psk);
114 assert (!"unknown psk encoding");
117 return cred->secret_len;
119 #endif /* RS_ENABLE_TLS_PSK */
121 /** Read \a buf_len bytes from one of the random devices into \a
122 buf. Return 0 on success and -1 on failure. */
124 load_rand_ (uint8_t *buf, size_t buf_len)
126 static const char *fns[] = {"/dev/urandom", "/dev/random", NULL};
129 if (buf_len > SSIZE_MAX)
132 for (i = 0; fns[i] != NULL; i++)
135 int fd = open (fns[i], O_RDONLY);
138 while (nread != buf_len)
140 ssize_t r = read (fd, buf + nread, buf_len - nread);
148 if (nread != buf_len)
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. */
159 init_openssl_rand_ (void)
161 long openssl_version = 0;
162 int openssl_random_init_flag = 0;
163 int our_random_init_flag = 0;
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 ();
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? */
178 if (!openssl_random_init_flag && !our_random_init_flag)
180 if (!RAND_bytes (buf, sizeof(buf)))
185 /** Initialise the TLS library. Return 0 on success, -1 on failure. */
189 SSL_load_error_strings ();
191 return init_openssl_rand_ ();
195 tls_init_conn (struct rs_connection *conn)
197 struct rs_context *ctx = NULL;
198 struct tls *tlsconf = NULL;
199 SSL_CTX *ssl_ctx = NULL;
201 unsigned long sslerr = 0;
206 tlsconf = _get_tlsconf (conn, conn->active_peer->realm);
209 ssl_ctx = tlsgetctx (RAD_TLS, tlsconf);
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));
217 ssl = SSL_new (ssl_ctx);
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));
226 #if defined RS_ENABLE_TLS_PSK
227 if (conn->active_peer->realm->transport_cred != NULL)
229 SSL_set_psk_client_callback (ssl, psk_client_cb);
230 SSL_set_ex_data (ssl, 0, conn);
232 #endif /* RS_ENABLE_TLS_PSK */
234 conn->tls_ctx = ssl_ctx;
236 rs_free (ctx, tlsconf);
240 /* draft-ietf-radext-radsec-11.txt
242 * Certificate validation MUST include the verification rules as
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
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
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.
271 * Implementations SHOULD allow to configure a set of acceptable
272 values for subjectAltName:URI.
275 tls_verify_cert (struct rs_connection *conn)
279 X509 *peer_cert = NULL;
280 struct in6_addr addr;
281 const char *hostname = NULL;
283 assert (conn->active_peer->conn == conn);
284 assert (conn->active_peer->hostname != NULL);
285 hostname = conn->active_peer->hostname;
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)
292 err = rs_err_conn_push (conn, RSE_SSLERR,
293 "basic certificate validation failed");
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);
302 success = (subjectaltnameregexp (peer_cert, GEN_DNS, hostname, NULL) == 1);
305 success = (cnregexp (peer_cert, hostname, NULL) == 1);
307 if (conn->realm->disable_hostname_check)
310 err = rs_err_conn_push (conn, RSE_CERT, "server certificate doesn't "
311 "match configured hostname \"%s\"", hostname);
314 if (peer_cert != NULL)
315 X509_free (peer_cert);