0389f21408733c64c716988c8d8bdb176cc030a2
[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/x509v3.h>
34 #include "debug.h"
35 #include "list.h"
36 #include "hash.h"
37 #include "util.h"
38 #include "radsecproxy.h"
39
40 static struct hash *tlsconfs = NULL;
41
42 static int pem_passwd_cb(char *buf, int size, int rwflag, void *userdata) {
43     int pwdlen = strlen(userdata);
44     if (rwflag != 0 || pwdlen > size) /* not for decryption or too large */
45         return 0;
46     memcpy(buf, userdata, pwdlen);
47     return pwdlen;
48 }
49
50 static int verify_cb(int ok, X509_STORE_CTX *ctx) {
51     char *buf = NULL;
52     X509 *err_cert;
53     int err, depth;
54
55     err_cert = X509_STORE_CTX_get_current_cert(ctx);
56     err = X509_STORE_CTX_get_error(ctx);
57     depth = X509_STORE_CTX_get_error_depth(ctx);
58
59     if (depth > MAX_CERT_DEPTH) {
60         ok = 0;
61         err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
62         X509_STORE_CTX_set_error(ctx, err);
63     }
64
65     if (!ok) {
66         if (err_cert)
67             buf = X509_NAME_oneline(X509_get_subject_name(err_cert), NULL, 0);
68         debug(DBG_WARN, "verify error: num=%d:%s:depth=%d:%s", err, X509_verify_cert_error_string(err), depth, buf ? buf : "");
69         free(buf);
70         buf = NULL;
71         
72         switch (err) {
73         case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
74             if (err_cert) {
75                 buf = X509_NAME_oneline(X509_get_issuer_name(err_cert), NULL, 0);
76                 if (buf) {
77                     debug(DBG_WARN, "\tIssuer=%s", buf);
78                     free(buf);
79                     buf = NULL;
80                 }
81             }
82             break;
83         case X509_V_ERR_CERT_NOT_YET_VALID:
84         case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
85             debug(DBG_WARN, "\tCertificate not yet valid");
86             break;
87         case X509_V_ERR_CERT_HAS_EXPIRED:
88             debug(DBG_WARN, "Certificate has expired");
89             break;
90         case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
91             debug(DBG_WARN, "Certificate no longer valid (after notAfter)");
92             break;
93         case X509_V_ERR_NO_EXPLICIT_POLICY:
94             debug(DBG_WARN, "No Explicit Certificate Policy");
95             break;
96         }
97     }
98 #ifdef DEBUG  
99     printf("certificate verify returns %d\n", ok);
100 #endif  
101     return ok;
102 }
103
104 #ifdef DEBUG
105 static void ssl_info_callback(const SSL *ssl, int where, int ret) {
106     const char *s;
107     int w;
108
109     w = where & ~SSL_ST_MASK;
110
111     if (w & SSL_ST_CONNECT)
112         s = "SSL_connect";
113     else if (w & SSL_ST_ACCEPT)
114         s = "SSL_accept";
115     else
116         s = "undefined";
117
118     if (where & SSL_CB_LOOP)
119         debug(DBG_DBG, "%s:%s\n", s, SSL_state_string_long(ssl));
120     else if (where & SSL_CB_ALERT) {
121         s = (where & SSL_CB_READ) ? "read" : "write";
122         debug(DBG_DBG, "SSL3 alert %s:%s:%s\n", s, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
123     }
124     else if (where & SSL_CB_EXIT) {
125         if (ret == 0)
126             debug(DBG_DBG, "%s:failed in %s\n", s, SSL_state_string_long(ssl));
127         else if (ret < 0)
128             debug(DBG_DBG, "%s:error in %s\n", s, SSL_state_string_long(ssl));
129     }
130 }
131 #endif
132
133 static X509_VERIFY_PARAM *createverifyparams(char **poids) {
134     X509_VERIFY_PARAM *pm;
135     ASN1_OBJECT *pobject;
136     int i;
137     
138     pm = X509_VERIFY_PARAM_new();
139     if (!pm)
140         return NULL;
141     
142     for (i = 0; poids[i]; i++) {
143         pobject = OBJ_txt2obj(poids[i], 0);
144         if (!pobject) {
145             X509_VERIFY_PARAM_free(pm);
146             return NULL;
147         }
148         X509_VERIFY_PARAM_add0_policy(pm, pobject);
149     }
150
151     X509_VERIFY_PARAM_set_flags(pm, X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY);
152     return pm;
153 }
154
155 static int tlsaddcacrl(SSL_CTX *ctx, struct tls *conf) {
156     STACK_OF(X509_NAME) *calist;
157     X509_STORE *x509_s;
158     unsigned long error;
159
160     if (!SSL_CTX_load_verify_locations(ctx, conf->cacertfile, conf->cacertpath)) {
161         while ((error = ERR_get_error()))
162             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
163         debug(DBG_ERR, "tlsaddcacrl: Error updating TLS context %s", conf->name);
164         return 0;
165     }
166
167     calist = conf->cacertfile ? SSL_load_client_CA_file(conf->cacertfile) : NULL;
168     if (!conf->cacertfile || calist) {
169         if (conf->cacertpath) {
170             if (!calist)
171                 calist = sk_X509_NAME_new_null();
172             if (!SSL_add_dir_cert_subjects_to_stack(calist, conf->cacertpath)) {
173                 sk_X509_NAME_free(calist);
174                 calist = NULL;
175             }
176         }
177     }
178     if (!calist) {
179         while ((error = ERR_get_error()))
180             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
181         debug(DBG_ERR, "tlsaddcacrl: Error adding CA subjects in TLS context %s", conf->name);
182         return 0;
183     }
184     ERR_clear_error(); /* add_dir_cert_subj returns errors on success */
185     SSL_CTX_set_client_CA_list(ctx, calist);
186
187     SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);
188     SSL_CTX_set_verify_depth(ctx, MAX_CERT_DEPTH + 1);
189
190     if (conf->crlcheck || conf->vpm) {
191         x509_s = SSL_CTX_get_cert_store(ctx);
192         if (conf->crlcheck)
193             X509_STORE_set_flags(x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
194         if (conf->vpm)
195             X509_STORE_set1_param(x509_s, conf->vpm);
196     }
197
198     debug(DBG_DBG, "tlsaddcacrl: updated TLS context %s", conf->name);
199     return 1;
200 }
201
202 static SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
203     SSL_CTX *ctx = NULL;
204     unsigned long error;
205
206     switch (type) {
207 #ifdef RADPROT_TLS      
208     case RAD_TLS:
209         ctx = SSL_CTX_new(TLSv1_method());
210 #ifdef DEBUG    
211         SSL_CTX_set_info_callback(ctx, ssl_info_callback);
212 #endif  
213         break;
214 #endif  
215 #ifdef RADPROT_DTLS     
216     case RAD_DTLS:
217         ctx = SSL_CTX_new(DTLSv1_method());
218 #ifdef DEBUG    
219         SSL_CTX_set_info_callback(ctx, ssl_info_callback);
220 #endif  
221         SSL_CTX_set_read_ahead(ctx, 1);
222         break;
223 #endif  
224     }
225     if (!ctx) {
226         debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name);
227         return NULL;
228     }
229     
230     if (conf->certkeypwd) {
231         SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->certkeypwd);
232         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
233     }
234     if (!SSL_CTX_use_certificate_chain_file(ctx, conf->certfile) ||
235         !SSL_CTX_use_PrivateKey_file(ctx, conf->certkeyfile, SSL_FILETYPE_PEM) ||
236         !SSL_CTX_check_private_key(ctx)) {
237         while ((error = ERR_get_error()))
238             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
239         debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name);
240         SSL_CTX_free(ctx);
241         return NULL;
242     }
243
244     if (conf->policyoids) {
245         if (!conf->vpm) {
246             conf->vpm = createverifyparams(conf->policyoids);
247             if (!conf->vpm) {
248                 debug(DBG_ERR, "tlscreatectx: Failed to add policyOIDs in TLS context %s", conf->name);
249                 SSL_CTX_free(ctx);
250                 return NULL;
251             }
252         }
253     }
254
255     if (!tlsaddcacrl(ctx, conf)) {
256         if (conf->vpm) {
257             X509_VERIFY_PARAM_free(conf->vpm);
258             conf->vpm = NULL;
259         }
260         SSL_CTX_free(ctx);
261         return NULL;
262     }
263
264     debug(DBG_DBG, "tlscreatectx: created TLS context %s", conf->name);
265     return ctx;
266 }
267
268 struct tls *tlsgettls(char *alt1, char *alt2) {
269     struct tls *t;
270
271     t = hash_read(tlsconfs, alt1, strlen(alt1));
272     if (!t)
273         t = hash_read(tlsconfs, alt2, strlen(alt2));
274     return t;
275 }
276
277 SSL_CTX *tlsgetctx(uint8_t type, struct tls *t) {
278     struct timeval now;
279     
280     if (!t)
281         return NULL;
282     gettimeofday(&now, NULL);
283     
284     switch (type) {
285 #ifdef RADPROT_TLS
286     case RAD_TLS:
287         if (t->tlsexpiry && t->tlsctx) {
288             if (t->tlsexpiry < now.tv_sec) {
289                 t->tlsexpiry = now.tv_sec + t->cacheexpiry;
290                 tlsaddcacrl(t->tlsctx, t);
291             }
292         }
293         if (!t->tlsctx) {
294             t->tlsctx = tlscreatectx(RAD_TLS, t);
295             if (t->cacheexpiry)
296                 t->tlsexpiry = now.tv_sec + t->cacheexpiry;
297         }
298         return t->tlsctx;
299 #endif
300 #ifdef RADPROT_DTLS
301     case RAD_DTLS:
302         if (t->dtlsexpiry && t->dtlsctx) {
303             if (t->dtlsexpiry < now.tv_sec) {
304                 t->dtlsexpiry = now.tv_sec + t->cacheexpiry;
305                 tlsaddcacrl(t->dtlsctx, t);
306             }
307         }
308         if (!t->dtlsctx) {
309             t->dtlsctx = tlscreatectx(RAD_DTLS, t);
310             if (t->cacheexpiry)
311                 t->dtlsexpiry = now.tv_sec + t->cacheexpiry;
312         }
313         return t->dtlsctx;
314 #endif
315     }
316     return NULL;
317 }
318
319 X509 *verifytlscert(SSL *ssl) {
320     X509 *cert;
321     unsigned long error;
322     
323     if (SSL_get_verify_result(ssl) != X509_V_OK) {
324         debug(DBG_ERR, "verifytlscert: basic validation failed");
325         while ((error = ERR_get_error()))
326             debug(DBG_ERR, "verifytlscert: TLS: %s", ERR_error_string(error, NULL));
327         return NULL;
328     }
329
330     cert = SSL_get_peer_certificate(ssl);
331     if (!cert)
332         debug(DBG_ERR, "verifytlscert: failed to obtain certificate");
333     return cert;
334 }
335
336 static int subjectaltnameaddr(X509 *cert, int family, struct in6_addr *addr) {
337     int loc, i, l, n, r = 0;
338     char *v;
339     X509_EXTENSION *ex;
340     STACK_OF(GENERAL_NAME) *alt;
341     GENERAL_NAME *gn;
342     
343     debug(DBG_DBG, "subjectaltnameaddr");
344     
345     loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
346     if (loc < 0)
347         return r;
348     
349     ex = X509_get_ext(cert, loc);
350     alt = X509V3_EXT_d2i(ex);
351     if (!alt)
352         return r;
353     
354     n = sk_GENERAL_NAME_num(alt);
355     for (i = 0; i < n; i++) {
356         gn = sk_GENERAL_NAME_value(alt, i);
357         if (gn->type != GEN_IPADD)
358             continue;
359         r = -1;
360         v = (char *)ASN1_STRING_data(gn->d.ia5);
361         l = ASN1_STRING_length(gn->d.ia5);
362         if (((family == AF_INET && l == sizeof(struct in_addr)) || (family == AF_INET6 && l == sizeof(struct in6_addr)))
363             && !memcmp(v, &addr, l)) {
364             r = 1;
365             break;
366         }
367     }
368     GENERAL_NAMES_free(alt);
369     return r;
370 }
371
372 static int subjectaltnameregexp(X509 *cert, int type, char *exact,  regex_t *regex) {
373     int loc, i, l, n, r = 0;
374     char *s, *v;
375     X509_EXTENSION *ex;
376     STACK_OF(GENERAL_NAME) *alt;
377     GENERAL_NAME *gn;
378     
379     debug(DBG_DBG, "subjectaltnameregexp");
380     
381     loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
382     if (loc < 0)
383         return r;
384     
385     ex = X509_get_ext(cert, loc);
386     alt = X509V3_EXT_d2i(ex);
387     if (!alt)
388         return r;
389     
390     n = sk_GENERAL_NAME_num(alt);
391     for (i = 0; i < n; i++) {
392         gn = sk_GENERAL_NAME_value(alt, i);
393         if (gn->type != type)
394             continue;
395         r = -1;
396         v = (char *)ASN1_STRING_data(gn->d.ia5);
397         l = ASN1_STRING_length(gn->d.ia5);
398         if (l <= 0)
399             continue;
400 #ifdef DEBUG
401         printfchars(NULL, gn->type == GEN_DNS ? "dns" : "uri", NULL, v, l);
402 #endif  
403         if (exact) {
404             if (memcmp(v, exact, l))
405                 continue;
406         } else {
407             s = stringcopy((char *)v, l);
408             if (!s) {
409                 debug(DBG_ERR, "malloc failed");
410                 continue;
411             }
412             if (regexec(regex, s, 0, NULL, 0)) {
413                 free(s);
414                 continue;
415             }
416             free(s);
417         }
418         r = 1;
419         break;
420     }
421     GENERAL_NAMES_free(alt);
422     return r;
423 }
424
425 static int cnregexp(X509 *cert, char *exact, regex_t *regex) {
426     int loc, l;
427     char *v, *s;
428     X509_NAME *nm;
429     X509_NAME_ENTRY *e;
430     ASN1_STRING *t;
431
432     nm = X509_get_subject_name(cert);
433     loc = -1;
434     for (;;) {
435         loc = X509_NAME_get_index_by_NID(nm, NID_commonName, loc);
436         if (loc == -1)
437             break;
438         e = X509_NAME_get_entry(nm, loc);
439         t = X509_NAME_ENTRY_get_data(e);
440         v = (char *) ASN1_STRING_data(t);
441         l = ASN1_STRING_length(t);
442         if (l < 0)
443             continue;
444         if (exact) {
445             if (l == strlen(exact) && !strncasecmp(exact, v, l))
446                 return 1;
447         } else {
448             s = stringcopy((char *)v, l);
449             if (!s) {
450                 debug(DBG_ERR, "malloc failed");
451                 continue;
452             }
453             if (regexec(regex, s, 0, NULL, 0)) {
454                 free(s);
455                 continue;
456             }
457             free(s);
458             return 1;
459         }
460     }
461     return 0;
462 }
463
464 int verifyconfcert(X509 *cert, struct clsrvconf *conf) {
465     int r;
466     uint8_t type = 0; /* 0 for DNS, AF_INET for IPv4, AF_INET6 for IPv6 */
467     struct in6_addr addr;
468     
469     if (conf->certnamecheck && conf->prefixlen == 255) {
470         if (inet_pton(AF_INET, conf->host, &addr))
471             type = AF_INET;
472         else if (inet_pton(AF_INET6, conf->host, &addr))
473             type = AF_INET6;
474
475         r = type ? subjectaltnameaddr(cert, type, &addr) : subjectaltnameregexp(cert, GEN_DNS, conf->host, NULL);
476         if (r) {
477             if (r < 0) {
478                 debug(DBG_WARN, "verifyconfcert: No subjectaltname matching %s %s", type ? "address" : "host", conf->host);
479                 return 0;
480             }
481             debug(DBG_DBG, "verifyconfcert: Found subjectaltname matching %s %s", type ? "address" : "host", conf->host);
482         } else {
483             if (!cnregexp(cert, conf->host, NULL)) {
484                 debug(DBG_WARN, "verifyconfcert: cn not matching host %s", conf->host);
485                 return 0;
486             }           
487             debug(DBG_DBG, "verifyconfcert: Found cn matching host %s", conf->host);
488         }
489     }
490     if (conf->certcnregex) {
491         if (cnregexp(cert, NULL, conf->certcnregex) < 1) {
492             debug(DBG_WARN, "verifyconfcert: CN not matching regex");
493             return 0;
494         }
495         debug(DBG_DBG, "verifyconfcert: CN matching regex");
496     }
497     if (conf->certuriregex) {
498         if (subjectaltnameregexp(cert, GEN_URI, NULL, conf->certuriregex) < 1) {
499             debug(DBG_WARN, "verifyconfcert: subjectaltname URI not matching regex");
500             return 0;
501         }
502         debug(DBG_DBG, "verifyconfcert: subjectaltname URI matching regex");
503     }
504     return 1;
505 }
506
507 int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) {
508     struct tls *conf;
509     long int expiry = LONG_MIN;
510     
511     debug(DBG_DBG, "conftls_cb called for %s", block);
512     
513     conf = malloc(sizeof(struct tls));
514     if (!conf) {
515         debug(DBG_ERR, "conftls_cb: malloc failed");
516         return 0;
517     }
518     memset(conf, 0, sizeof(struct tls));
519     
520     if (!getgenericconfig(cf, block,
521                           "CACertificateFile", CONF_STR, &conf->cacertfile,
522                           "CACertificatePath", CONF_STR, &conf->cacertpath,
523                           "CertificateFile", CONF_STR, &conf->certfile,
524                           "CertificateKeyFile", CONF_STR, &conf->certkeyfile,
525                           "CertificateKeyPassword", CONF_STR, &conf->certkeypwd,
526                           "CacheExpiry", CONF_LINT, &expiry,
527                           "CRLCheck", CONF_BLN, &conf->crlcheck,
528                           "PolicyOID", CONF_MSTR, &conf->policyoids,
529                           NULL
530                           )) {
531         debug(DBG_ERR, "conftls_cb: configuration error in block %s", val);
532         goto errexit;
533     }
534     if (!conf->certfile || !conf->certkeyfile) {
535         debug(DBG_ERR, "conftls_cb: TLSCertificateFile and TLSCertificateKeyFile must be specified in block %s", val);
536         goto errexit;
537     }
538     if (!conf->cacertfile && !conf->cacertpath) {
539         debug(DBG_ERR, "conftls_cb: CA Certificate file or path need to be specified in block %s", val);
540         goto errexit;
541     }
542     if (expiry != LONG_MIN) {
543         if (expiry < 0) {
544             debug(DBG_ERR, "error in block %s, value of option CacheExpiry is %ld, may not be negative", val, expiry);
545             goto errexit;
546         }
547         conf->cacheexpiry = expiry;
548     }    
549
550     conf->name = stringcopy(val, 0);
551     if (!conf->name) {
552         debug(DBG_ERR, "conftls_cb: malloc failed");
553         goto errexit;
554     }
555
556     if (!tlsconfs)
557         tlsconfs = hash_create();
558     if (!hash_insert(tlsconfs, val, strlen(val), conf)) {
559         debug(DBG_ERR, "conftls_cb: malloc failed");
560         goto errexit;
561     }
562     if (!tlsgetctx(RAD_TLS, conf))
563         debug(DBG_ERR, "conftls_cb: error creating ctx for TLS block %s", val);
564     debug(DBG_DBG, "conftls_cb: added TLS block %s", val);
565     return 1;
566
567  errexit:
568     free(conf->cacertfile);
569     free(conf->cacertpath);
570     free(conf->certfile);
571     free(conf->certkeyfile);
572     free(conf->certkeypwd);
573     freegconfmstr(conf->policyoids);
574     free(conf);
575     return 0;
576 }
577
578 int addmatchcertattr(struct clsrvconf *conf) {
579     char *v;
580     regex_t **r;
581     
582     if (!strncasecmp(conf->matchcertattr, "CN:/", 4)) {
583         r = &conf->certcnregex;
584         v = conf->matchcertattr + 4;
585     } else if (!strncasecmp(conf->matchcertattr, "SubjectAltName:URI:/", 20)) {
586         r = &conf->certuriregex;
587         v = conf->matchcertattr + 20;
588     } else
589         return 0;
590     if (!*v)
591         return 0;
592     /* regexp, remove optional trailing / if present */
593     if (v[strlen(v) - 1] == '/')
594         v[strlen(v) - 1] = '\0';
595     if (!*v)
596         return 0;
597
598     *r = malloc(sizeof(regex_t));
599     if (!*r) {
600         debug(DBG_ERR, "malloc failed");
601         return 0;
602     }
603     if (regcomp(*r, v, REG_EXTENDED | REG_ICASE | REG_NOSUB)) {
604         free(*r);
605         *r = NULL;
606         debug(DBG_ERR, "failed to compile regular expression %s", v);
607         return 0;
608     }
609     return 1;
610 }
611 #else
612 /* Just to makes file non-empty, should rather avoid compiling this file when not needed */
613 static void tlsdummy() {
614 }
615 #endif