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