Implement TLS-PSK.
[libradsec.git] / lib / tls.c
1 /* Copyright 2010, 2011 NORDUnet A/S. All rights reserved.
2    See the file COPYING 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 <radsec/radsec.h>
13 #include <radsec/radsec-impl.h>
14
15 #include <regex.h>
16 #include "rsp_list.h"
17 #include "../radsecproxy.h"
18
19 static struct tls *
20 _get_tlsconf (struct rs_connection *conn, const struct rs_realm *realm)
21 {
22   struct tls *c = rs_malloc (conn->ctx, sizeof (struct tls));
23
24   if (c)
25     {
26       memset (c, 0, sizeof (struct tls));
27       /* TODO: Make sure old radsecproxy code doesn't free these all
28          of a sudden, or strdup them.  */
29       c->name = realm->name;
30       c->cacertfile = realm->cacertfile;
31       c->cacertpath = NULL;     /* NYI */
32       c->certfile = realm->certfile;
33       c->certkeyfile = realm->certkeyfile;
34       c->certkeypwd = NULL;     /* NYI */
35       c->cacheexpiry = 0;       /* NYI */
36       c->crlcheck = 0;          /* NYI */
37       c->policyoids = (char **) NULL; /* NYI */
38     }
39     else
40       rs_err_conn_push_fl (conn, RSE_NOMEM, __FILE__, __LINE__, NULL);
41
42   return c;
43 }
44
45 static unsigned int
46 psk_client_cb (SSL *ssl,
47                const char *hint,
48                char *identity,
49                unsigned int max_identity_len,
50                unsigned char *psk,
51                unsigned int max_psk_len)
52 {
53   struct rs_connection *conn = NULL;
54   struct rs_credentials *cred = NULL;
55
56   conn = SSL_get_ex_data (ssl, 0);
57   assert (conn != NULL);
58   cred = conn->active_peer->realm->transport_cred;
59   assert (cred != NULL);
60   /* NOTE: Ignoring identity hint from server.  */
61
62   if (strlen (cred->identity) + 1 > max_identity_len)
63     {
64       rs_err_conn_push (conn, RSE_CRED, "PSK identity longer than max %d",
65                         max_identity_len - 1);
66       return 0;
67     }
68   strcpy (identity, cred->identity);
69
70   switch (cred->secret_encoding)
71     {
72     case RS_KEY_ENCODING_UTF8:
73       cred->secret_len = strlen (cred->secret);
74       if (cred->secret_len > max_psk_len)
75         {
76           rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
77                             max_psk_len);
78           return 0;
79         }
80       memcpy (psk, cred->secret, cred->secret_len);
81       break;
82     case RS_KEY_ENCODING_ASCII_HEX:
83       {
84         BIGNUM *bn = NULL;
85
86         if (BN_hex2bn (&bn, cred->secret) == 0)
87           {
88             rs_err_conn_push (conn, RSE_CRED, "Unable to convert pskhexstr");
89             if (bn != NULL)
90               BN_clear_free (bn);
91             return 0;
92           }
93         if ((unsigned int) BN_num_bytes (bn) > max_psk_len)
94           {
95             rs_err_conn_push (conn, RSE_CRED, "PSK secret longer than max %d",
96                              max_psk_len);
97             BN_clear_free (bn);
98             return 0;
99           }
100         cred->secret_len = BN_bn2bin (bn, psk);
101         BN_clear_free (bn);
102       }
103       break;
104     default:
105       assert (!"unknown psk encoding");
106     }
107
108   return cred->secret_len;
109 }
110
111 int
112 rs_tls_init (struct rs_connection *conn)
113 {
114   struct rs_context *ctx = NULL;
115   struct tls *tlsconf = NULL;
116   SSL_CTX *ssl_ctx = NULL;
117   SSL *ssl = NULL;
118   unsigned long sslerr = 0;
119
120   assert (conn->ctx);
121   ctx = conn->ctx;
122
123   tlsconf = _get_tlsconf (conn, conn->active_peer->realm);
124   if (!tlsconf)
125     return -1;
126   ssl_ctx = tlsgetctx (RADPROT_TLS, tlsconf);
127   if (!ssl_ctx)
128     {
129       for (sslerr = ERR_get_error (); sslerr; sslerr = ERR_get_error ())
130          rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
131                               ERR_error_string (sslerr, NULL));
132       return -1;
133     }
134   ssl = SSL_new (ssl_ctx);
135   if (!ssl)
136     {
137       for (sslerr = ERR_get_error (); sslerr; sslerr = ERR_get_error ())
138         rs_err_conn_push_fl (conn, RSE_SSLERR, __FILE__, __LINE__,
139                              ERR_error_string (sslerr, NULL));
140       return -1;
141     }
142
143   if (conn->active_peer->realm->transport_cred != NULL)
144     {
145       SSL_set_psk_client_callback (ssl, psk_client_cb);
146       SSL_set_ex_data (ssl, 0, conn);
147     }
148   conn->tls_ctx = ssl_ctx;
149   conn->tls_ssl = ssl;
150   rs_free (ctx, tlsconf);
151   return RSE_OK;
152 }