Implement cert verification.
[radsecproxy.git] / lib / rsp_tlscommon.c
1 /*
2  * Copyright (C) 2006-2009 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 HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <sys/types.h>
14 #include <signal.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <netdb.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <limits.h>
21 #ifdef SYS_SOLARIS9
22 #include <fcntl.h>
23 #endif
24 #include <sys/time.h>
25 #include <sys/select.h>
26 #include <ctype.h>
27 #include <sys/wait.h>
28 #include <arpa/inet.h>
29 #include <regex.h>
30 #include <libgen.h>
31 #include <pthread.h>
32 #include <openssl/ssl.h>
33 #include <openssl/rand.h>
34 #include <openssl/err.h>
35 #include <openssl/md5.h>
36 #include <openssl/x509v3.h>
37 #include "rsp_debug.h"
38 #include "rsp_list.h"
39 #include "rsp_hash.h"
40 #include "rsp_util.h"
41 #include "../hostport_types.h"
42 #include "../radsecproxy.h"
43
44 static struct hash *tlsconfs = NULL;
45
46 void ssl_init(void) {
47     time_t t;
48     pid_t pid;
49
50     SSL_load_error_strings();
51     SSL_library_init();
52
53     while (!RAND_status()) {
54         t = time(NULL);
55         pid = getpid();
56         RAND_seed((unsigned char *)&t, sizeof(time_t));
57         RAND_seed((unsigned char *)&pid, sizeof(pid));
58     }
59 }
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     return ok;
118 }
119
120 #ifdef DEBUG
121 static void ssl_info_callback(const SSL *ssl, int where, int ret) {
122     const char *s;
123     int w;
124
125     w = where & ~SSL_ST_MASK;
126
127     if (w & SSL_ST_CONNECT)
128         s = "SSL_connect";
129     else if (w & SSL_ST_ACCEPT)
130         s = "SSL_accept";
131     else
132         s = "undefined";
133
134     if (where & SSL_CB_LOOP)
135         debug(DBG_DBG, "%s:%s\n", s, SSL_state_string_long(ssl));
136     else if (where & SSL_CB_ALERT) {
137         s = (where & SSL_CB_READ) ? "read" : "write";
138         debug(DBG_DBG, "SSL3 alert %s:%s:%s\n", s, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
139     }
140     else if (where & SSL_CB_EXIT) {
141         if (ret == 0)
142             debug(DBG_DBG, "%s:failed in %s\n", s, SSL_state_string_long(ssl));
143         else if (ret < 0)
144             debug(DBG_DBG, "%s:error in %s\n", s, SSL_state_string_long(ssl));
145     }
146 }
147 #endif
148
149 static X509_VERIFY_PARAM *createverifyparams(char **poids) {
150     X509_VERIFY_PARAM *pm;
151     ASN1_OBJECT *pobject;
152     int i;
153
154     pm = X509_VERIFY_PARAM_new();
155     if (!pm)
156         return NULL;
157
158     for (i = 0; poids[i]; i++) {
159         pobject = OBJ_txt2obj(poids[i], 0);
160         if (!pobject) {
161             X509_VERIFY_PARAM_free(pm);
162             return NULL;
163         }
164         X509_VERIFY_PARAM_add0_policy(pm, pobject);
165     }
166
167     X509_VERIFY_PARAM_set_flags(pm, X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY);
168     return pm;
169 }
170
171 static int tlsaddcacrl(SSL_CTX *ctx, struct tls *conf) {
172     STACK_OF(X509_NAME) *calist;
173     X509_STORE *x509_s;
174     unsigned long error;
175
176     if (!SSL_CTX_load_verify_locations(ctx, conf->cacertfile, conf->cacertpath)) {
177         while ((error = ERR_get_error()))
178             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
179         debug(DBG_ERR, "tlsaddcacrl: Error updating TLS context %s", conf->name);
180         return 0;
181     }
182
183         calist = conf->cacertfile ? SSL_load_client_CA_file(conf->cacertfile) : NULL;
184
185     if (!conf->cacertfile || calist) {
186         if (conf->cacertpath) {
187             if (!calist)
188                 calist = sk_X509_NAME_new_null();
189             if (!SSL_add_dir_cert_subjects_to_stack(calist, conf->cacertpath)) {
190                 sk_X509_NAME_free(calist);
191                 calist = NULL;
192             }
193         }
194     }
195     if (!calist) {
196         while ((error = ERR_get_error()))
197             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
198         debug(DBG_ERR, "tlsaddcacrl: Error adding CA subjects in TLS context %s", conf->name);
199         return 0;
200     }
201     ERR_clear_error(); /* add_dir_cert_subj returns errors on success */
202     SSL_CTX_set_client_CA_list(ctx, calist);
203
204     SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);
205     SSL_CTX_set_verify_depth(ctx, MAX_CERT_DEPTH + 1);
206
207     if (conf->crlcheck || conf->vpm) {
208         x509_s = SSL_CTX_get_cert_store(ctx);
209         if (conf->crlcheck)
210             X509_STORE_set_flags(x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
211         if (conf->vpm)
212             X509_STORE_set1_param(x509_s, conf->vpm);
213     }
214
215     debug(DBG_DBG, "tlsaddcacrl: updated TLS context %s", conf->name);
216     return 1;
217 }
218
219 static SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
220     SSL_CTX *ctx = NULL;
221     unsigned long error;
222
223     switch (type) {
224 #ifdef RADPROT_TLS
225     case RAD_TLS:
226         ctx = SSL_CTX_new(TLSv1_method());
227         break;
228 #endif
229 #ifdef RADPROT_DTLS
230     case RAD_DTLS:
231         ctx = SSL_CTX_new(DTLSv1_method());
232         SSL_CTX_set_read_ahead(ctx, 1);
233         break;
234 #endif
235     }
236     if (!ctx) {
237         debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS in TLS context %s", conf->name);
238         while ((error = ERR_get_error()))
239             debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
240         return NULL;
241     }
242 #ifdef DEBUG
243         SSL_CTX_set_info_callback(ctx, ssl_info_callback);
244 #endif
245
246     if (conf->certkeypwd) {
247         SSL_CTX_set_default_passwd_cb_userdata(ctx, conf->certkeypwd);
248         SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_cb);
249     }
250     if (conf->certfile || conf->certkeyfile) {
251         if (!SSL_CTX_use_certificate_chain_file(ctx, conf->certfile) ||
252             !SSL_CTX_use_PrivateKey_file(ctx, conf->certkeyfile, SSL_FILETYPE_PEM) ||
253             !SSL_CTX_check_private_key(ctx)) {
254             while ((error = ERR_get_error()))
255                 debug(DBG_ERR, "SSL: %s", ERR_error_string(error, NULL));
256             debug(DBG_ERR, "tlscreatectx: Error initialising SSL/TLS (certfile issues) in TLS context %s", conf->name);
257             SSL_CTX_free(ctx);
258             return NULL;
259         }
260     }
261
262     if (conf->policyoids) {
263         if (!conf->vpm) {
264             conf->vpm = createverifyparams(conf->policyoids);
265             if (!conf->vpm) {
266                 debug(DBG_ERR, "tlscreatectx: Failed to add policyOIDs in TLS context %s", conf->name);
267                 SSL_CTX_free(ctx);
268                 return NULL;
269             }
270         }
271     }
272
273     if (conf->cacertfile != NULL || conf->cacertpath != NULL)
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 X509 *verifytlscert(SSL *ssl) {
339     X509 *cert;
340     unsigned long error;
341
342     if (SSL_get_verify_result(ssl) != X509_V_OK) {
343         debug(DBG_ERR, "verifytlscert: basic validation failed");
344         while ((error = ERR_get_error()))
345             debug(DBG_ERR, "verifytlscert: TLS: %s", ERR_error_string(error, NULL));
346         return NULL;
347     }
348
349     cert = SSL_get_peer_certificate(ssl);
350     if (!cert)
351         debug(DBG_ERR, "verifytlscert: failed to obtain certificate");
352     return cert;
353 }
354
355 int subjectaltnameaddr(X509 *cert, int family, const struct in6_addr *addr) {
356     int loc, i, l, n, r = 0;
357     char *v;
358     X509_EXTENSION *ex;
359     STACK_OF(GENERAL_NAME) *alt;
360     GENERAL_NAME *gn;
361
362     debug(DBG_DBG, "subjectaltnameaddr");
363
364     loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
365     if (loc < 0)
366         return r;
367
368     ex = X509_get_ext(cert, loc);
369     alt = X509V3_EXT_d2i(ex);
370     if (!alt)
371         return r;
372
373     n = sk_GENERAL_NAME_num(alt);
374     for (i = 0; i < n; i++) {
375         gn = sk_GENERAL_NAME_value(alt, i);
376         if (gn->type != GEN_IPADD)
377             continue;
378         r = -1;
379         v = (char *)ASN1_STRING_data(gn->d.ia5);
380         l = ASN1_STRING_length(gn->d.ia5);
381         if (((family == AF_INET && l == sizeof(struct in_addr)) || (family == AF_INET6 && l == sizeof(struct in6_addr)))
382             && !memcmp(v, &addr, l)) {
383             r = 1;
384             break;
385         }
386     }
387     GENERAL_NAMES_free(alt);
388     return r;
389 }
390
391 int subjectaltnameregexp(X509 *cert, int type, const char *exact,  const regex_t *regex) {
392     int loc, i, l, n, r = 0;
393     char *s, *v;
394     X509_EXTENSION *ex;
395     STACK_OF(GENERAL_NAME) *alt;
396     GENERAL_NAME *gn;
397
398     debug(DBG_DBG, "subjectaltnameregexp");
399
400     loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
401     if (loc < 0)
402         return r;
403
404     ex = X509_get_ext(cert, loc);
405     alt = X509V3_EXT_d2i(ex);
406     if (!alt)
407         return r;
408
409     n = sk_GENERAL_NAME_num(alt);
410     for (i = 0; i < n; i++) {
411         gn = sk_GENERAL_NAME_value(alt, i);
412         if (gn->type != type)
413             continue;
414         r = -1;
415         v = (char *)ASN1_STRING_data(gn->d.ia5);
416         l = ASN1_STRING_length(gn->d.ia5);
417         if (l <= 0)
418             continue;
419 #ifdef DEBUG
420         printfchars(NULL, gn->type == GEN_DNS ? "dns" : "uri", NULL, v, l);
421 #endif
422         if (exact) {
423             if (memcmp(v, exact, l))
424                 continue;
425         } else {
426             s = stringcopy((char *)v, l);
427             if (!s) {
428                 debug(DBG_ERR, "malloc failed");
429                 continue;
430             }
431             if (regexec(regex, s, 0, NULL, 0)) {
432                 free(s);
433                 continue;
434             }
435             free(s);
436         }
437         r = 1;
438         break;
439     }
440     GENERAL_NAMES_free(alt);
441     return r;
442 }
443
444 int cnregexp(X509 *cert, const char *exact, const regex_t *regex) {
445     int loc, l;
446     char *v, *s;
447     X509_NAME *nm;
448     X509_NAME_ENTRY *e;
449     ASN1_STRING *t;
450
451     nm = X509_get_subject_name(cert);
452     loc = -1;
453     for (;;) {
454         loc = X509_NAME_get_index_by_NID(nm, NID_commonName, loc);
455         if (loc == -1)
456             break;
457         e = X509_NAME_get_entry(nm, loc);
458         t = X509_NAME_ENTRY_get_data(e);
459         v = (char *) ASN1_STRING_data(t);
460         l = ASN1_STRING_length(t);
461         if (l < 0)
462             continue;
463         if (exact) {
464             if (l == strlen(exact) && !strncasecmp(exact, v, l))
465                 return 1;
466         } else {
467             s = stringcopy((char *)v, l);
468             if (!s) {
469                 debug(DBG_ERR, "malloc failed");
470                 continue;
471             }
472             if (regexec(regex, s, 0, NULL, 0)) {
473                 free(s);
474                 continue;
475             }
476             free(s);
477             return 1;
478         }
479     }
480     return 0;
481 }
482
483 /* this is a bit sloppy, should not always accept match to any */
484 int certnamecheck(X509 *cert, struct list *hostports) {
485     struct list_node *entry;
486     struct hostportres *hp;
487     int r;
488     uint8_t type = 0; /* 0 for DNS, AF_INET for IPv4, AF_INET6 for IPv6 */
489     struct in6_addr addr;
490
491     for (entry = list_first(hostports); entry; entry = list_next(entry)) {
492         hp = (struct hostportres *)entry->data;
493         if (hp->prefixlen != 255) {
494             /* we disable the check for prefixes */
495             return 1;
496         }
497         if (inet_pton(AF_INET, hp->host, &addr))
498             type = AF_INET;
499         else if (inet_pton(AF_INET6, hp->host, &addr))
500             type = AF_INET6;
501         else
502             type = 0;
503
504         r = type ? subjectaltnameaddr(cert, type, &addr) : subjectaltnameregexp(cert, GEN_DNS, hp->host, NULL);
505         if (r) {
506             if (r > 0) {
507                 debug(DBG_DBG, "certnamecheck: Found subjectaltname matching %s %s", type ? "address" : "host", hp->host);
508                 return 1;
509             }
510             debug(DBG_WARN, "certnamecheck: No subjectaltname matching %s %s", type ? "address" : "host", hp->host);
511         } else {
512             if (cnregexp(cert, hp->host, NULL)) {
513                 debug(DBG_DBG, "certnamecheck: Found cn matching host %s", hp->host);
514                 return 1;
515             }
516             debug(DBG_WARN, "certnamecheck: cn not matching host %s", hp->host);
517         }
518     }
519     return 0;
520 }
521
522 int verifyconfcert(X509 *cert, struct clsrvconf *conf) {
523     if (conf->certnamecheck) {
524         if (!certnamecheck(cert, conf->hostports)) {
525             debug(DBG_WARN, "verifyconfcert: certificate name check failed");
526             return 0;
527         }
528         debug(DBG_WARN, "verifyconfcert: certificate name check ok");
529     }
530     if (conf->certcnregex) {
531         if (cnregexp(cert, NULL, conf->certcnregex) < 1) {
532             debug(DBG_WARN, "verifyconfcert: CN not matching regex");
533             return 0;
534         }
535         debug(DBG_DBG, "verifyconfcert: CN matching regex");
536     }
537     if (conf->certuriregex) {
538         if (subjectaltnameregexp(cert, GEN_URI, NULL, conf->certuriregex) < 1) {
539             debug(DBG_WARN, "verifyconfcert: subjectaltname URI not matching regex");
540             return 0;
541         }
542         debug(DBG_DBG, "verifyconfcert: subjectaltname URI matching regex");
543     }
544     return 1;
545 }
546
547 /* Local Variables: */
548 /* c-file-style: "stroustrup" */
549 /* End: */