Implement cert verification.
authorLinus Nordberg <linus@nordu.net>
Thu, 26 Apr 2012 08:18:33 +0000 (10:18 +0200)
committerLinus Nordberg <linus@nordu.net>
Thu, 26 Apr 2012 08:18:33 +0000 (10:18 +0200)
NOTE: Not used yet.

lib/rsp_tlscommon.c
lib/rsp_tlscommon.h
lib/tls.c
lib/tls.h

index 75aa891..abc395e 100644 (file)
@@ -11,7 +11,6 @@
 #endif
 
 #include <sys/types.h>
-#if defined(RADPROT_TLS) || defined(RADPROT_DTLS)
 #include <signal.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -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: */
index 6819cd0..0470aa7 100644 (file)
@@ -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)
index 0f07e46..610df98 100644 (file)
--- a/lib/tls.c
+++ b/lib/tls.c
@@ -9,6 +9,7 @@
 #include <openssl/ssl.h>
 #include <openssl/err.h>
 #include <openssl/bn.h>
+#include <openssl/x509v3.h>
 #include <radsec/radsec.h>
 #include <radsec/radsec-impl.h>
 
@@ -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;
+}
index d457cfd..0dc2ebd 100644 (file)
--- 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)
 }