d934269c144b4eecc5bcd8b6354582767da33225
[radsecproxy.git] / tlscommon.c
1 /*
2  * Copyright (C) 2006-2008 Stig Venaas <venaas@uninett.no>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  */
8
9 #if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
10 #include <signal.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <netdb.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <limits.h>
17 #ifdef SYS_SOLARIS9
18 #include <fcntl.h>
19 #endif
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <sys/select.h>
23 #include <ctype.h>
24 #include <sys/wait.h>
25 #include <arpa/inet.h>
26 #include <regex.h>
27 #include <libgen.h>
28 #include <pthread.h>
29 #include <openssl/ssl.h>
30 #include <openssl/rand.h>
31 #include <openssl/err.h>
32 #include <openssl/md5.h>
33 #include <openssl/hmac.h>
34 #include <openssl/x509v3.h>
35 #include "debug.h"
36 #include "list.h"
37 #include "hash.h"
38 #include "util.h"
39 #include "gconfig.h"
40 #include "radsecproxy.h"
41
42 struct tls {
43     char *name;
44     char *cacertfile;
45     char *cacertpath;
46     char *certfile;
47     char *certkeyfile;
48     char *certkeypwd;
49     uint8_t crlcheck;
50     char **policyoids;
51     uint32_t cacheexpiry;
52     uint32_t tlsexpiry;
53     uint32_t dtlsexpiry;
54     X509_VERIFY_PARAM *vpm;
55     SSL_CTX *tlsctx;
56     SSL_CTX *dtlsctx;
57 };
58
59 static struct hash *tlsconfs = NULL;
60
61 static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) {
62     int pwdlen = strlen(userdata);
63     if (rwflag != 0 || pwdlen > size) /* not for decryption or too large */
64         return 0;
65     memcpy(buf, userdata, pwdlen);
66     return pwdlen;
67 }
68
69 static int verify_cb(int ok, X509_STORE_CTX *ctx) {
70     char *buf = NULL;
71     X509 *err_cert;
72     int err, depth;
73
74     err_cert = X509_STORE_CTX_get_current_cert(ctx);
75     err = X509_STORE_CTX_get_error(ctx);
76     depth = X509_STORE_CTX_get_error_depth(ctx);
77
78     if (depth > MAX_CERT_DEPTH) {
79         ok = 0;
80         err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
81         X509_STORE_CTX_set_error(ctx, err);
82     }
83
84     if (!ok) {
85         if (err_cert)
86             buf = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
87         debug(DBG_WARN, "verify error: num=%d:%s:depth=%d:%s", err, X509_verify_cert_error_string(err), depth, buf ? buf : "");
88         free(buf);
89         buf = NULL;
90         
91         switch (err) {
92         case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
93             if (err_cert) {
94                 buf = X509_NAME_oneline(X509_get_issuer_name(err_cert), NULL, 0);
95                 if (buf) {
96                     debug(DBG_WARN, "\tIssuer=%s", buf);
97                     free(buf);
98                     buf = NULL;
99                 }
100             }
101             break;
102         case X509_V_ERR_CERT_NOT_YET_VALID:
103         case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
104             debug(DBG_WARN, "\tCertificate not yet valid");
105             break;
106         case X509_V_ERR_CERT_HAS_EXPIRED:
107             debug(DBG_WARN, "Certificate has expired");
108             break;
109         case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
110             debug(DBG_WARN, "Certificate no longer valid (after notAfter)");
111             break;
112         case X509_V_ERR_NO_EXPLICIT_POLICY:
113             debug(DBG_WARN, "No Explicit Certificate Policy");
114             break;
115         }
116     }
117 #ifdef DEBUG  
118     printf("certificate verify returns %d\n", ok);
119 #endif  
120     return ok;
121 }
122
123 #ifdef DEBUG
124 static void ssl_info_callback(const SSL *ssl, int where, int ret) {
125     const char *s;
126     int w;
127
128     w = where & ~SSL_ST_MASK;
129
130     if (w & SSL_ST_CONNECT)
131         s = "SSL_connect";
132     else if (w & SSL_ST_ACCEPT)
133         s = "SSL_accept";
134     else
135         s = "undefined";
136
137     if (where & SSL_CB_LOOP)
138         debug(DBG_DBG, "%s:%s\n", s, SSL_state_string_long(ssl));
139     else if (where & SSL_CB_ALERT) {
140         s = (where & SSL_CB_READ) ? "read" : "write";
141         debug(DBG_DBG, "SSL3 alert %s:%s:%s\n", s, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
142     }
143     else if (where & SSL_CB_EXIT) {
144         if (ret == 0)
145             debug(DBG_DBG, "%s:failed in %s\n", s, SSL_state_string_long(ssl));
146         else if (ret < 0)
147             debug(DBG_DBG, "%s:error in %s\n", s, SSL_state_string_long(ssl));
148     }
149 }
150 #endif
151
152 static X509_VERIFY_PARAM *createverifyparams(char **poids) {
153     X509_VERIFY_PARAM *pm;
154     ASN1_OBJECT *pobject;
155     int i;
156     
157     pm = X509_VERIFY_PARAM_new();
158     if (!pm)
159         return NULL;
160     
161     for (i = 0; poids[i]; i++) {
162         pobject = OBJ_txt2obj(poids[i], 0);
163         if (!pobject) {
164             X509_VERIFY_PARAM_free(pm);
165             return NULL;
166         }
167         X509_VERIFY_PARAM_add0_policy(pm, pobject);
168     }
169
170     X509_VERIFY_PARAM_set_flags(pm, X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY);
171     return pm;
172 }
173
174 static int tlsaddcacrl(SSL_CTX *ctx, struct tls *conf) {
175     STACK_OF(X509_NAME) *calist;
176     X509_STORE *x509_s;
177     unsigned long error;
178
179     if (!SSL_CTX_load_verify_locations(ctx, conf->cacertfile, conf->cacertpath)) {
180         while ((error = ERR_get_error()))
181             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
182         debug(DBG_ERR, "tlsaddcacrl: Error updating TLS context %s", conf->name);
183         return 0;
184     }
185
186     calist = conf->cacertfile ? SSL_load_client_CA_file(conf->cacertfile) : NULL;
187     if (!conf->cacertfile || calist) {
188         if (conf->cacertpath) {
189             if (!calist)
190                 calist = sk_X509_NAME_new_null();
191             if (!SSL_add_dir_cert_subjects_to_stack(calist, conf->cacertpath)) {
192                 sk_X509_NAME_free(calist);
193                 calist = NULL;
194             }
195         }
196     }
197     if (!calist) {
198         while ((error = ERR_get_error()))
199             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
200         debug(DBG_ERR, "tlsaddcacrl: Error adding CA subjects in TLS context %s", conf->name);
201         return 0;
202     }
203     ERR_clear_error(); /* add_dir_cert_subj returns errors on success */
204     SSL_CTX_set_client_CA_list(ctx, calist);
205
206     SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);
207     SSL_CTX_set_verify_depth(ctx, MAX_CERT_DEPTH + 1);
208
209     if (conf->crlcheck || conf->vpm) {
210         x509_s = SSL_CTX_get_cert_store(ctx);
211         if (conf->crlcheck)
212             X509_STORE_set_flags(x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
213         if (conf->vpm)
214             X509_STORE_set1_param(x509_s, conf->vpm);
215     }
216
217     debug(DBG_DBG, "tlsaddcacrl: updated TLS context %s", conf->name);
218     return 1;
219 }
220
221 static SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
222     SSL_CTX *ctx = NULL;
223     unsigned long error;
224
225     switch (type) {
226 #ifdef RADPROT_TLS      
227     case RAD_TLS:
228         ctx = SSL_CTX_new(TLSv1_method());
229 #ifdef DEBUG    
230         SSL_CTX_set_info_callback(ctx, ssl_info_callback);
231 #endif  
232         break;
233 #endif  
234 #ifdef RADPROT_DTLS     
235     case RAD_DTLS:
236         ctx = SSL_CTX_new(DTLSv1_method());
237 #ifdef DEBUG    
238         SSL_CTX_set_info_callback(ctx, ssl_info_callback);
239 #endif  
240         SSL_CTX_set_read_ahead(ctx, 1);
241         break;
242 #endif  
243     }
244     if (!ctx) {
245         debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name);
246         return NULL;
247     }
248     
249     if (conf->certkeypwd) {
250         SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->certkeypwd);
251         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
252     }
253     if (!SSL_CTX_use_certificate_chain_file(ctx, conf->certfile) ||
254         !SSL_CTX_use_PrivateKey_file(ctx, conf->certkeyfile, SSL_FILETYPE_PEM) ||
255         !SSL_CTX_check_private_key(ctx)) {
256         while ((error = ERR_get_error()))
257             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
258         debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name);
259         SSL_CTX_free(ctx);
260         return NULL;
261     }
262
263     if (conf->policyoids) {
264         if (!conf->vpm) {
265             conf->vpm = createverifyparams(conf->policyoids);
266             if (!conf->vpm) {
267                 debug(DBG_ERR, "tlscreatectx: Failed to add policyOIDs in TLS context %s", conf->name);
268                 SSL_CTX_free(ctx);
269                 return NULL;
270             }
271         }
272     }
273
274     if (!tlsaddcacrl(ctx, conf)) {
275         if (conf->vpm) {
276             X509_VERIFY_PARAM_free(conf->vpm);
277             conf->vpm = NULL;
278         }
279         SSL_CTX_free(ctx);
280         return NULL;
281     }
282
283     debug(DBG_DBG, "tlscreatectx: created TLS context %s", conf->name);
284     return ctx;
285 }
286
287 struct tls *tlsgettls(char *alt1, char *alt2) {
288     struct tls *t;
289
290     t = hash_read(tlsconfs, alt1, strlen(alt1));
291     if (!t)
292         t = hash_read(tlsconfs, alt2, strlen(alt2));
293     return t;
294 }
295
296 SSL_CTX *tlsgetctx(uint8_t type, struct tls *t) {
297     struct timeval now;
298     
299     if (!t)
300         return NULL;
301     gettimeofday(&now, NULL);
302     
303     switch (type) {
304 #ifdef RADPROT_TLS
305     case RAD_TLS:
306         if (t->tlsexpiry && t->tlsctx) {
307             if (t->tlsexpiry < now.tv_sec) {
308                 t->tlsexpiry = now.tv_sec + t->cacheexpiry;
309                 tlsaddcacrl(t->tlsctx, t);
310             }
311         }
312         if (!t->tlsctx) {
313             t->tlsctx = tlscreatectx(RAD_TLS, t);
314             if (t->cacheexpiry)
315                 t->tlsexpiry = now.tv_sec + t->cacheexpiry;
316         }
317         return t->tlsctx;
318 #endif
319 #ifdef RADPROT_DTLS
320     case RAD_DTLS:
321         if (t->dtlsexpiry && t->dtlsctx) {
322             if (t->dtlsexpiry < now.tv_sec) {
323                 t->dtlsexpiry = now.tv_sec + t->cacheexpiry;
324                 tlsaddcacrl(t->dtlsctx, t);
325             }
326         }
327         if (!t->dtlsctx) {
328             t->dtlsctx = tlscreatectx(RAD_DTLS, t);
329             if (t->cacheexpiry)
330                 t->dtlsexpiry = now.tv_sec + t->cacheexpiry;
331         }
332         return t->dtlsctx;
333 #endif
334     }
335     return NULL;
336 }
337
338 int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
339     struct tls *conf;
340     long int expiry = LONG_MIN;
341     
342     debug(DBG_DBG, "conftls_cb called for %s", block);
343     
344     conf = malloc(sizeof(struct tls));
345     if (!conf) {
346         debug(DBG_ERR, "conftls_cb: malloc failed");
347         return 0;
348     }
349     memset(conf, 0, sizeof(struct tls));
350     
351     if (!getgenericconfig(cf, block,
352                           "CACertificateFile", CONF_STR, &conf->cacertfile,
353                           "CACertificatePath", CONF_STR, &conf->cacertpath,
354                           "CertificateFile", CONF_STR, &conf->certfile,
355                           "CertificateKeyFile", CONF_STR, &conf->certkeyfile,
356                           "CertificateKeyPassword", CONF_STR, &conf->certkeypwd,
357                           "CacheExpiry", CONF_LINT, &expiry,
358                           "CRLCheck", CONF_BLN, &conf->crlcheck,
359                           "PolicyOID", CONF_MSTR, &conf->policyoids,
360                           NULL
361                           )) {
362         debug(DBG_ERR, "conftls_cb: configuration error in block %s", val);
363         goto errexit;
364     }
365     if (!conf->certfile || !conf->certkeyfile) {
366         debug(DBG_ERR, "conftls_cb: TLSCertificateFile and TLSCertificateKeyFile must be specified in block %s", val);
367         goto errexit;
368     }
369     if (!conf->cacertfile && !conf->cacertpath) {
370         debug(DBG_ERR, "conftls_cb: CA Certificate file or path need to be specified in block %s", val);
371         goto errexit;
372     }
373     if (expiry != LONG_MIN) {
374         if (expiry < 0) {
375             debug(DBG_ERR, "error in block %s, value of option CacheExpiry is %ld, may not be negative", val, expiry);
376             goto errexit;
377         }
378         conf->cacheexpiry = expiry;
379     }    
380
381     conf->name = stringcopy(val, 0);
382     if (!conf->name) {
383         debug(DBG_ERR, "conftls_cb: malloc failed");
384         goto errexit;
385     }
386
387     if (!tlsconfs)
388         tlsconfs = hash_create();
389     if (!hash_insert(tlsconfs, val, strlen(val), conf)) {
390         debug(DBG_ERR, "conftls_cb: malloc failed");
391         goto errexit;
392     }
393     if (!tlsgetctx(RAD_TLS, conf))
394         debug(DBG_ERR, "conftls_cb: error creating ctx for TLS block %s", val);
395     debug(DBG_DBG, "conftls_cb: added TLS block %s", val);
396     return 1;
397
398  errexit:
399     free(conf->cacertfile);
400     free(conf->cacertpath);
401     free(conf->certfile);
402     free(conf->certkeyfile);
403     free(conf->certkeypwd);
404     freegconfmstr(conf->policyoids);
405     free(conf);
406     return 0;
407 }
408 #else
409 /* Just to makes file non-empty, should rather avoid compiling this file when not needed */
410 static void tlsdummy() {
411 }
412 #endif