From 6e6672cffd42def79813dbf7f1588d2ce219ca79 Mon Sep 17 00:00:00 2001 From: Linus Nordberg Date: Thu, 26 Apr 2012 10:18:33 +0200 Subject: Implement cert verification. NOTE: Not used yet. --- lib/rsp_tlscommon.c | 119 ++-------------------------------------------------- lib/rsp_tlscommon.h | 5 ++- lib/tls.c | 78 ++++++++++++++++++++++++++++++++++ lib/tls.h | 1 + 4 files changed, 85 insertions(+), 118 deletions(-) diff --git a/lib/rsp_tlscommon.c b/lib/rsp_tlscommon.c index 75aa891..abc395e 100644 --- a/lib/rsp_tlscommon.c +++ b/lib/rsp_tlscommon.c @@ -11,7 +11,6 @@ #endif #include -#if defined(RADPROT_TLS) || defined(RADPROT_DTLS) #include #include #include @@ -353,7 +352,7 @@ X509 *verifytlscert(SSL *ssl) { return cert; } -static int subjectaltnameaddr(X509 *cert, int family, struct in6_addr *addr) { +int subjectaltnameaddr(X509 *cert, int family, const struct in6_addr *addr) { int loc, i, l, n, r = 0; char *v; X509_EXTENSION *ex; @@ -389,7 +388,7 @@ static int subjectaltnameaddr(X509 *cert, int family, struct in6_addr *addr) { return r; } -static int subjectaltnameregexp(X509 *cert, int type, char *exact, regex_t *regex) { +int subjectaltnameregexp(X509 *cert, int type, const char *exact, const regex_t *regex) { int loc, i, l, n, r = 0; char *s, *v; X509_EXTENSION *ex; @@ -442,7 +441,7 @@ static int subjectaltnameregexp(X509 *cert, int type, char *exact, regex_t *reg return r; } -static int cnregexp(X509 *cert, char *exact, regex_t *regex) { +int cnregexp(X509 *cert, const char *exact, const regex_t *regex) { int loc, l; char *v, *s; X509_NAME *nm; @@ -545,118 +544,6 @@ int verifyconfcert(X509 *cert, struct clsrvconf *conf) { return 1; } -#if 0 -int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val) { - struct tls *conf; - long int expiry = LONG_MIN; - - debug(DBG_DBG, "conftls_cb called for %s", block); - - conf = malloc(sizeof(struct tls)); - if (!conf) { - debug(DBG_ERR, "conftls_cb: malloc failed"); - return 0; - } - memset(conf, 0, sizeof(struct tls)); - - if (!getgenericconfig(cf, block, - "CACertificateFile", CONF_STR, &conf->cacertfile, - "CACertificatePath", CONF_STR, &conf->cacertpath, - "CertificateFile", CONF_STR, &conf->certfile, - "CertificateKeyFile", CONF_STR, &conf->certkeyfile, - "CertificateKeyPassword", CONF_STR, &conf->certkeypwd, - "CacheExpiry", CONF_LINT, &expiry, - "CRLCheck", CONF_BLN, &conf->crlcheck, - "PolicyOID", CONF_MSTR, &conf->policyoids, - NULL - )) { - debug(DBG_ERR, "conftls_cb: configuration error in block %s", val); - goto errexit; - } - if (!conf->certfile || !conf->certkeyfile) { - debug(DBG_ERR, "conftls_cb: TLSCertificateFile and TLSCertificateKeyFile must be specified in block %s", val); - goto errexit; - } - if (!conf->cacertfile && !conf->cacertpath) { - debug(DBG_ERR, "conftls_cb: CA Certificate file or path need to be specified in block %s", val); - goto errexit; - } - if (expiry != LONG_MIN) { - if (expiry < 0) { - debug(DBG_ERR, "error in block %s, value of option CacheExpiry is %ld, may not be negative", val, expiry); - goto errexit; - } - conf->cacheexpiry = expiry; - } - - conf->name = stringcopy(val, 0); - if (!conf->name) { - debug(DBG_ERR, "conftls_cb: malloc failed"); - goto errexit; - } - - if (!tlsconfs) - tlsconfs = hash_create(); - if (!hash_insert(tlsconfs, val, strlen(val), conf)) { - debug(DBG_ERR, "conftls_cb: malloc failed"); - goto errexit; - } - if (!tlsgetctx(RAD_TLS, conf)) - debug(DBG_ERR, "conftls_cb: error creating ctx for TLS block %s", val); - debug(DBG_DBG, "conftls_cb: added TLS block %s", val); - return 1; - -errexit: - free(conf->cacertfile); - free(conf->cacertpath); - free(conf->certfile); - free(conf->certkeyfile); - free(conf->certkeypwd); - freegconfmstr(conf->policyoids); - free(conf); - return 0; -} -#endif - -int addmatchcertattr(struct clsrvconf *conf) { - char *v; - regex_t **r; - - if (!strncasecmp(conf->matchcertattr, "CN:/", 4)) { - r = &conf->certcnregex; - v = conf->matchcertattr + 4; - } else if (!strncasecmp(conf->matchcertattr, "SubjectAltName:URI:/", 20)) { - r = &conf->certuriregex; - v = conf->matchcertattr + 20; - } else - return 0; - if (!*v) - return 0; - /* regexp, remove optional trailing / if present */ - if (v[strlen(v) - 1] == '/') - v[strlen(v) - 1] = '\0'; - if (!*v) - return 0; - - *r = malloc(sizeof(regex_t)); - if (!*r) { - debug(DBG_ERR, "malloc failed"); - return 0; - } - if (regcomp(*r, v, REG_EXTENDED | REG_ICASE | REG_NOSUB)) { - free(*r); - *r = NULL; - debug(DBG_ERR, "failed to compile regular expression %s", v); - return 0; - } - return 1; -} -#else -/* Just to makes file non-empty, should rather avoid compiling this file when not needed */ -static void tlsdummy() { -} -#endif - /* Local Variables: */ /* c-file-style: "stroustrup" */ /* End: */ diff --git a/lib/rsp_tlscommon.h b/lib/rsp_tlscommon.h index 6819cd0..0470aa7 100644 --- a/lib/rsp_tlscommon.h +++ b/lib/rsp_tlscommon.h @@ -34,9 +34,10 @@ void ssl_init(); struct tls *tlsgettls(char *alt1, char *alt2); SSL_CTX *tlsgetctx(uint8_t type, struct tls *t); X509 *verifytlscert(SSL *ssl); +int subjectaltnameaddr(X509 *cert, int family, const struct in6_addr *addr); +int subjectaltnameregexp(X509 *cert, int type, const char *exact, const regex_t *regex); +int cnregexp(X509 *cert, const char *exact, const regex_t *regex); int verifyconfcert(X509 *cert, struct clsrvconf *conf); -int conftls_cb(struct gconffile **cf, void *arg, char *block, char *opt, char *val); -int addmatchcertattr(struct clsrvconf *conf); #endif #if defined (__cplusplus) diff --git a/lib/tls.c b/lib/tls.c index 0f07e46..610df98 100644 --- a/lib/tls.c +++ b/lib/tls.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -155,3 +156,80 @@ rs_tls_init (struct rs_connection *conn) rs_free (ctx, tlsconf); return RSE_OK; } + +/* draft-ietf-radext-radsec-11.txt + + * Certificate validation MUST include the verification rules as + per [RFC5280]. + + * Implementations SHOULD indicate their acceptable Certification + Authorities as per section 7.4.4 (server side) and x.y.z + ["Trusted CA Indication"] (client side) of [RFC5246] (see + Section 3.2) + + * Implementations SHOULD allow to configure a list of acceptable + certificates, identified via certificate fingerprint. When a + fingerprint configured, the fingerprint is prepended with an + ASCII label identifying the hash function followed by a colon. + Implementations MUST support SHA-1 as the hash algorithm and + use the ASCII label "sha-1" to identify the SHA-1 algorithm. + The length of a SHA-1 hash is 20 bytes and the length of the + corresponding fingerprint string is 65 characters. An example + certificate fingerprint is: sha- + 1:E1:2D:53:2B:7C:6B:8A:29:A2:76:C8:64:36:0B:08:4B:7A:F1:9E:9D + + * Peer validation always includes a check on whether the locally + configured expected DNS name or IP address of the server that + is contacted matches its presented certificate. DNS names and + IP addresses can be contained in the Common Name (CN) or + subjectAltName entries. For verification, only one of these + entries is to be considered. The following precedence + applies: for DNS name validation, subjectAltName:DNS has + precedence over CN; for IP address validation, subjectAltName: + iPAddr has precedence over CN. + + * Implementations SHOULD allow to configure a set of acceptable + values for subjectAltName:URI. + */ +int +tls_verify_cert (struct rs_connection *conn) +{ + int err = 0; + int success = 0; + X509 *peer_cert = NULL; + struct in6_addr addr; + const char *hostname = NULL; + + assert (conn->active_peer->conn == conn); + assert (conn->active_peer->hostname != NULL); + hostname = conn->active_peer->hostname; + + /* verifytlscert() performs basic verification as described by + OpenSSL VERIFY(1), i.e. verification of the certificate chain. */ + peer_cert = verifytlscert (conn->tls_ssl); + if (peer_cert == NULL) + { + err = rs_err_conn_push (conn, RSE_SSLERR, + "basic certificate validation failed"); + goto out; + } + + if (inet_pton(AF_INET, hostname, &addr)) + success = (subjectaltnameaddr (peer_cert, AF_INET, &addr) == 1); + else if (inet_pton(AF_INET6, hostname, &addr)) + success = (subjectaltnameaddr (peer_cert, AF_INET6, &addr) == 1); + else + success = (subjectaltnameregexp (peer_cert, GEN_DNS, hostname, NULL) == 1); + + if (!success) + success = (cnregexp(peer_cert, hostname, NULL) == 1); + + if (!success) + err = rs_err_conn_push (conn, RSE_CERT, "server certificate doesn't " + "match configured hostname \"%s\"", hostname); + + out: + if (peer_cert != NULL) + X509_free (peer_cert); + return err; +} diff --git a/lib/tls.h b/lib/tls.h index d457cfd..0dc2ebd 100644 --- a/lib/tls.h +++ b/lib/tls.h @@ -6,6 +6,7 @@ extern "C" { #endif int rs_tls_init (struct rs_connection *conn); +int tls_verify_cert (struct rs_connection *conn); #if defined (__cplusplus) } -- cgit v1.1