2 * Copyright (C) 2006-2009 Stig Venaas <venaas@uninett.no>
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.
9 #if defined HAVE_CONFIG_H
13 #include <sys/types.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
25 #include <sys/select.h>
28 #include <arpa/inet.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"
41 #include "../hostport_types.h"
42 #include "../radsecproxy.h"
44 static struct hash *tlsconfs = NULL;
50 SSL_load_error_strings();
53 while (!RAND_status()) {
56 RAND_seed((unsigned char *)&t, sizeof(time_t));
57 RAND_seed((unsigned char *)&pid, sizeof(pid));
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 */
65 memcpy(buf, userdata, pwdlen);
69 static int verify_cb(int ok, X509_STORE_CTX *ctx) {
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);
78 if (depth > MAX_CERT_DEPTH) {
80 err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
81 X509_STORE_CTX_set_error(ctx, err);
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 : "");
92 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
94 buf = X509_NAME_oneline(X509_get_issuer_name(err_cert), NULL, 0);
96 debug(DBG_WARN, "\tIssuer=%s", buf);
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");
106 case X509_V_ERR_CERT_HAS_EXPIRED:
107 debug(DBG_WARN, "Certificate has expired");
109 case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
110 debug(DBG_WARN, "Certificate no longer valid (after notAfter)");
112 case X509_V_ERR_NO_EXPLICIT_POLICY:
113 debug(DBG_WARN, "No Explicit Certificate Policy");
121 static void ssl_info_callback(const SSL *ssl, int where, int ret) {
125 w = where & ~SSL_ST_MASK;
127 if (w & SSL_ST_CONNECT)
129 else if (w & SSL_ST_ACCEPT)
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));
140 else if (where & SSL_CB_EXIT) {
142 debug(DBG_DBG, "%s:failed in %s\n", s, SSL_state_string_long(ssl));
144 debug(DBG_DBG, "%s:error in %s\n", s, SSL_state_string_long(ssl));
149 static X509_VERIFY_PARAM *createverifyparams(char **poids) {
150 X509_VERIFY_PARAM *pm;
151 ASN1_OBJECT *pobject;
154 pm = X509_VERIFY_PARAM_new();
158 for (i = 0; poids[i]; i++) {
159 pobject = OBJ_txt2obj(poids[i], 0);
161 X509_VERIFY_PARAM_free(pm);
164 X509_VERIFY_PARAM_add0_policy(pm, pobject);
167 X509_VERIFY_PARAM_set_flags(pm, X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY);
171 static int tlsaddcacrl(SSL_CTX *ctx, struct tls *conf) {
172 STACK_OF(X509_NAME) *calist;
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);
183 calist = conf->cacertfile ? SSL_load_client_CA_file(conf->cacertfile) : NULL;
185 if (!conf->cacertfile || calist) {
186 if (conf->cacertpath) {
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);
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);
201 ERR_clear_error(); /* add_dir_cert_subj returns errors on success */
202 SSL_CTX_set_client_CA_list(ctx, calist);
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);
207 if (conf->crlcheck || conf->vpm) {
208 x509_s = SSL_CTX_get_cert_store(ctx);
210 X509_STORE_set_flags(x509_s, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
212 X509_STORE_set1_param(x509_s, conf->vpm);
215 debug(DBG_DBG, "tlsaddcacrl: updated TLS context %s", conf->name);
219 static SSL_CTX *tlscreatectx(uint8_t type, struct tls *conf) {
226 ctx = SSL_CTX_new(TLSv1_method());
231 ctx = SSL_CTX_new(DTLSv1_method());
232 SSL_CTX_set_read_ahead(ctx, 1);
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));
243 SSL_CTX_set_info_callback(ctx, ssl_info_callback);
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);
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);
262 if (conf->policyoids) {
264 conf->vpm = createverifyparams(conf->policyoids);
266 debug(DBG_ERR, "tlscreatectx: Failed to add policyOIDs in TLS context %s", conf->name);
273 if (conf->cacertfile != NULL || conf->cacertpath != NULL)
274 if (!tlsaddcacrl(ctx, conf)) {
276 X509_VERIFY_PARAM_free(conf->vpm);
283 debug(DBG_DBG, "tlscreatectx: created TLS context %s", conf->name);
287 struct tls *tlsgettls(char *alt1, char *alt2) {
290 t = hash_read(tlsconfs, alt1, strlen(alt1));
292 t = hash_read(tlsconfs, alt2, strlen(alt2));
296 SSL_CTX *tlsgetctx(uint8_t type, struct tls *t) {
301 gettimeofday(&now, NULL);
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);
313 t->tlsctx = tlscreatectx(RAD_TLS, t);
315 t->tlsexpiry = now.tv_sec + t->cacheexpiry;
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);
328 t->dtlsctx = tlscreatectx(RAD_DTLS, t);
330 t->dtlsexpiry = now.tv_sec + t->cacheexpiry;
338 X509 *verifytlscert(SSL *ssl) {
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));
349 cert = SSL_get_peer_certificate(ssl);
351 debug(DBG_ERR, "verifytlscert: failed to obtain certificate");
355 int subjectaltnameaddr(X509 *cert, int family, const struct in6_addr *addr) {
356 int loc, i, l, n, r = 0;
359 STACK_OF(GENERAL_NAME) *alt;
362 debug(DBG_DBG, "subjectaltnameaddr");
364 loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
368 ex = X509_get_ext(cert, loc);
369 alt = X509V3_EXT_d2i(ex);
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)
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)) {
387 GENERAL_NAMES_free(alt);
391 int subjectaltnameregexp(X509 *cert, int type, const char *exact, const regex_t *regex) {
392 int loc, i, l, n, r = 0;
395 STACK_OF(GENERAL_NAME) *alt;
398 debug(DBG_DBG, "subjectaltnameregexp");
400 loc = X509_get_ext_by_NID(cert, NID_subject_alt_name, -1);
404 ex = X509_get_ext(cert, loc);
405 alt = X509V3_EXT_d2i(ex);
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)
415 v = (char *)ASN1_STRING_data(gn->d.ia5);
416 l = ASN1_STRING_length(gn->d.ia5);
420 printfchars(NULL, gn->type == GEN_DNS ? "dns" : "uri", NULL, v, l);
423 if (memcmp(v, exact, l))
426 s = stringcopy((char *)v, l);
428 debug(DBG_ERR, "malloc failed");
431 if (regexec(regex, s, 0, NULL, 0)) {
440 GENERAL_NAMES_free(alt);
444 int cnregexp(X509 *cert, const char *exact, const regex_t *regex) {
451 nm = X509_get_subject_name(cert);
454 loc = X509_NAME_get_index_by_NID(nm, NID_commonName, loc);
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);
464 if (l == strlen(exact) && !strncasecmp(exact, v, l))
467 s = stringcopy((char *)v, l);
469 debug(DBG_ERR, "malloc failed");
472 if (regexec(regex, s, 0, NULL, 0)) {
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;
488 uint8_t type = 0; /* 0 for DNS, AF_INET for IPv4, AF_INET6 for IPv6 */
489 struct in6_addr addr;
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 */
497 if (inet_pton(AF_INET, hp->host, &addr))
499 else if (inet_pton(AF_INET6, hp->host, &addr))
504 r = type ? subjectaltnameaddr(cert, type, &addr) : subjectaltnameregexp(cert, GEN_DNS, hp->host, NULL);
507 debug(DBG_DBG, "certnamecheck: Found subjectaltname matching %s %s", type ? "address" : "host", hp->host);
510 debug(DBG_WARN, "certnamecheck: No subjectaltname matching %s %s", type ? "address" : "host", hp->host);
512 if (cnregexp(cert, hp->host, NULL)) {
513 debug(DBG_DBG, "certnamecheck: Found cn matching host %s", hp->host);
516 debug(DBG_WARN, "certnamecheck: cn not matching host %s", hp->host);
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");
528 debug(DBG_WARN, "verifyconfcert: certificate name check ok");
530 if (conf->certcnregex) {
531 if (cnregexp(cert, NULL, conf->certcnregex) < 1) {
532 debug(DBG_WARN, "verifyconfcert: CN not matching regex");
535 debug(DBG_DBG, "verifyconfcert: CN matching regex");
537 if (conf->certuriregex) {
538 if (subjectaltnameregexp(cert, GEN_URI, NULL, conf->certuriregex) < 1) {
539 debug(DBG_WARN, "verifyconfcert: subjectaltname URI not matching regex");
542 debug(DBG_DBG, "verifyconfcert: subjectaltname URI matching regex");
547 /* Local Variables: */
548 /* c-file-style: "stroustrup" */