acc2f9194ed4a455b7049dca32480e64922c74ae
[libradsec.git] / lib / tls.c
1 /* Copyright 2010, 2011 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 <assert.h>
9 #include <openssl/ssl.h>
10 #include <openssl/err.h>
11 #include <openssl/bn.h>
12 #include <openssl/x509v3.h>
13 #include <radsec/radsec.h>
14 #include <radsec/radsec-impl.h>
15
16 #include <regex.h>
17 #include "rsp_list.h"
18 #include "../radsecproxy.h"
19
20 static struct tls *
21 _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm)
22 {
23   struct tls *c = rs_malloc (conn->ctx, sizeof (struct tls));
24
25   if (c)
26     {
27       memset (c, 0, sizeof (struct tls));
28       /* TODO: Make sure old radsecproxy code doesn't free these all
29          of a sudden, or strdup them.  */
30       c->name = realm->name;
31       c->cacertfile = realm->cacertfile;
32       c->cacertpath = NULL;     /* NYI */
33       c->certfile = realm->certfile;
34       c->certkeyfile = realm->certkeyfile;
35       c->certkeypwd = NULL;     /* NYI */
36       c->cacheexpiry = 0;       /* NYI */
37       c->crlcheck = 0;          /* NYI */
38       c->policyoids = (char **) NULL; /* NYI */
39     }
40     else
41       rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
42
43   return c;
44 }
45
46 #if defined RS_ENABLE_TLS_PSK
47 static unsigned int
48 psk_client_cb (SSL *ssl,
49                const char *hint,
50                char *identity,
51                unsigned int max_identity_len,
52                unsigned char *psk,
53                unsigned int max_psk_len)
54 {
55   struct rs_connection *conn = NULL;
56   struct rs_credentials *cred = NULL;
57
58   conn = SSL_get_ex_data (ssl, 0);
59   assert (conn != NULL);
60   cred = conn->active_peer->realm->transport_cred;
61   assert (cred != NULL);
62   /* NOTE: Ignoring identity hint from server.  */
63
64   if (strlen (cred->identity) + 1 > max_identity_len)
65     {
66       rs_err_conn_push (conn, RSE_CRED, "PSK identity longer than max %d",
67                         max_identity_len - 1);
68       return 0;
69     }
70   strcpy (identity, cred->identity);
71
72   switch (cred->secret_encoding)
73     {
74     case RS_KEY_ENCODING_UTF8:
75       cred->secret_len = strlen (cred->secret);
76       if (cred->secret_len > max_psk_len)
77         {
78           rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
79                             max_psk_len);
80           return 0;
81         }
82       memcpy (psk, cred->secret, cred->secret_len);
83       break;
84     case RS_KEY_ENCODING_ASCII_HEX:
85       {
86         BIGNUM *bn = NULL;
87
88         if (BN_hex2bn (&bn, cred->secret) == 0)
89           {
90             rs_err_conn_push (conn, RSE_CRED, "Unable to convert pskhexstr");
91             if (bn != NULL)
92               BN_clear_free (bn);
93             return 0;
94           }
95         if ((unsigned int) BN_num_bytes (bn) > max_psk_len)
96           {
97             rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
98                              max_psk_len);
99             BN_clear_free (bn);
100             return 0;
101           }
102         cred->secret_len = BN_bn2bin (bn, psk);
103         BN_clear_free (bn);
104       }
105       break;
106     default:
107       assert (!"unknown psk encoding");
108     }
109
110   return cred->secret_len;
111 }
112 #endif  /* RS_ENABLE_TLS_PSK */
113
114 int
115 rs_tls_init (struct rs_connection *conn)
116 {
117   struct rs_context *ctx = NULL;
118   struct tls *tlsconf = NULL;
119   SSL_CTX *ssl_ctx = NULL;
120   SSL *ssl = NULL;
121   unsigned long sslerr = 0;
122
123   assert (conn->ctx);
124   ctx = conn->ctx;
125
126   tlsconf = _get_tlsconf (conn, conn->active_peer->realm);
127   if (!tlsconf)
128     return -1;
129   ssl_ctx = tlsgetctx (RAD_TLS, tlsconf);
130   if (!ssl_ctx)
131     {
132       for (sslerr = ERR_get_error (); sslerr; sslerr = ERR_get_error ())
133          rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
134                               ERR_error_string (sslerr, NULL));
135       return -1;
136     }
137   ssl = SSL_new (ssl_ctx);
138   if (!ssl)
139     {
140       for (sslerr = ERR_get_error (); sslerr; sslerr = ERR_get_error ())
141         rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
142                              ERR_error_string (sslerr, NULL));
143       return -1;
144     }
145
146 #if defined RS_ENABLE_TLS_PSK
147   if (conn->active_peer->realm->transport_cred != NULL)
148     {
149       SSL_set_psk_client_callback (ssl, psk_client_cb);
150       SSL_set_ex_data (ssl, 0, conn);
151     }
152 #endif  /* RS_ENABLE_TLS_PSK */
153
154   conn->tls_ctx = ssl_ctx;
155   conn->tls_ssl = ssl;
156   rs_free (ctx, tlsconf);
157   return RSE_OK;
158 }
159
160 /* draft-ietf-radext-radsec-11.txt
161
162        *  Certificate validation MUST include the verification rules as
163           per [RFC5280].
164
165        *  Implementations SHOULD indicate their acceptable Certification
166           Authorities as per section 7.4.4 (server side) and x.y.z
167           ["Trusted CA Indication"] (client side) of [RFC5246] (see
168           Section 3.2)
169
170        *  Implementations SHOULD allow to configure a list of acceptable
171           certificates, identified via certificate fingerprint.  When a
172           fingerprint configured, the fingerprint is prepended with an
173           ASCII label identifying the hash function followed by a colon.
174           Implementations MUST support SHA-1 as the hash algorithm and
175           use the ASCII label "sha-1" to identify the SHA-1 algorithm.
176           The length of a SHA-1 hash is 20 bytes and the length of the
177           corresponding fingerprint string is 65 characters.  An example
178           certificate fingerprint is: sha-
179           1:E1:2D:53:2B:7C:6B:8A:29:A2:76:C8:64:36:0B:08:4B:7A:F1:9E:9D
180
181        *  Peer validation always includes a check on whether the locally
182           configured expected DNS name or IP address of the server that
183           is contacted matches its presented certificate.  DNS names and
184           IP addresses can be contained in the Common Name (CN) or
185           subjectAltName entries.  For verification, only one of these
186           entries is to be considered.  The following precedence
187           applies: for DNS name validation, subjectAltName:DNS has
188           precedence over CN; for IP address validation, subjectAltName:
189           iPAddr has precedence over CN.
190
191        *  Implementations SHOULD allow to configure a set of acceptable
192           values for subjectAltName:URI.
193  */
194 int
195 tls_verify_cert (struct rs_connection *conn)
196 {
197   int err = 0;
198   int success = 0;
199   X509 *peer_cert = NULL;
200   struct in6_addr addr;
201   const char *hostname = NULL;
202
203   assert (conn->active_peer->conn == conn);
204   assert (conn->active_peer->hostname != NULL);
205   hostname = conn->active_peer->hostname;
206
207   /* verifytlscert() performs basic verification as described by
208      OpenSSL VERIFY(1), i.e. verification of the certificate chain.  */
209   peer_cert = verifytlscert (conn->tls_ssl);
210   if (peer_cert == NULL)
211     {
212       err = rs_err_conn_push (conn, RSE_SSLERR,
213                               "basic certificate validation failed");
214       goto out;
215     }
216
217   if (inet_pton (AF_INET, hostname, &addr))
218     success = (subjectaltnameaddr (peer_cert, AF_INET, &addr) == 1);
219   else if (inet_pton (AF_INET6, hostname, &addr))
220     success = (subjectaltnameaddr (peer_cert, AF_INET6, &addr) == 1);
221   else
222     success = (subjectaltnameregexp (peer_cert, GEN_DNS, hostname, NULL) == 1);
223
224   if (!success)
225     success = (cnregexp (peer_cert, hostname, NULL) == 1);
226
227   if (!success)
228     err = rs_err_conn_push (conn, RSE_CERT, "server certificate doesn't "
229                             "match configured hostname \"%s\"", hostname);
230
231  out:
232   if (peer_cert != NULL)
233     X509_free (peer_cert);
234   return err;
235 }