]> jfr.im git - solanum.git/commitdiff
ssld: Add new certfp_methods spki_sha256 and spki_sha512
authorSimon Arlott <sa.me.uk>
Sat, 23 Apr 2016 21:51:05 +0000 (22:51 +0100)
committerSimon Arlott <sa.me.uk>
Sat, 23 Apr 2016 21:51:05 +0000 (22:51 +0100)
These operate on the SubjectPublicKeyInfo of the certificate, which does
change unless the private key is changed. This allows the fingerprint to
stay constant even if the certificate is reissued.

(The same fingerprint is also used by DANE)

doc/reference.conf
ircd/newconf.c
ircd/s_conf.c
librb/include/rb_commio.h
librb/src/gnutls.c
librb/src/mbedtls.c
librb/src/openssl.c
ssld/ssld.c

index b9d1e644346289a018444a4d506ceabe41b63e36..aff7787c0fc65e6a0dac8df3c84678394d35c69c 100644 (file)
@@ -1405,8 +1405,12 @@ general {
        away_interval = 30;
 
        /* certfp_method: the method that should be used for computing certificate fingerprints.
-        * Acceptable options are sha1, sha256 and sha512.  Networks running versions of charybdis
-        * prior to charybdis 3.5 MUST use sha1 for certfp_method.
+        * Acceptable options are sha1, sha256, spki_sha256, sha512 and spki_sha512.  Networks
+        * running versions of charybdis prior to charybdis 3.5 MUST use sha1 for certfp_method.
+        *
+        * The spki_* variants operate on the SubjectPublicKeyInfo of the certificate, which does
+        * not change unless the private key is changed.  This allows the fingerprint to stay
+        * constant even if the certificate is reissued.
         */
        certfp_method = sha1;
 
index 01af2eb70f02afc961616574a3f9689efcede912..253d02b6ef514a680e9d549db010ba9c65138c07 100644 (file)
@@ -1668,14 +1668,18 @@ conf_set_general_certfp_method(void *data)
        char *method = data;
 
        if (!rb_strcasecmp(method, "sha1"))
-               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_SHA1;
+               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_CERT_SHA1;
        else if (!rb_strcasecmp(method, "sha256"))
-               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_SHA256;
+               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_CERT_SHA256;
        else if (!rb_strcasecmp(method, "sha512"))
-               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_SHA512;
+               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_CERT_SHA512;
+       else if (!rb_strcasecmp(method, "spki_sha256"))
+               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_SPKI_SHA256;
+       else if (!rb_strcasecmp(method, "spki_sha512"))
+               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_SPKI_SHA512;
        else
        {
-               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_SHA1;
+               ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_CERT_SHA1;
                conf_report_error("Ignoring general::certfp_method -- bogus certfp method %s", method);
        }
 }
index 36f336a4bf9d8daa0eb0d0d4e178b1bbab4fc532..dcb4911f08c7ba96968ddf2611688a5a999f8cff 100644 (file)
@@ -813,7 +813,7 @@ set_default_conf(void)
        ServerInfo.default_max_clients = MAXCONNECTIONS;
 
        ConfigFileEntry.nicklen = NICKLEN;
-       ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_SHA1;
+       ConfigFileEntry.certfp_method = RB_SSL_CERTFP_METH_CERT_SHA1;
        ConfigFileEntry.hide_opers_in_whois = 0;
 
        if (!alias_dict)
index 7123a9812ab1abf939977597d2afc8d97937f212..5c15b0a224114c022b477e205ec62766dc736c6d 100644 (file)
@@ -102,9 +102,13 @@ void rb_note(rb_fde_t *, const char *);
 #define RB_SSL_CERTFP_LEN      64
 
 /* Methods for certfp */
-#define RB_SSL_CERTFP_METH_SHA1                0
-#define RB_SSL_CERTFP_METH_SHA256      1
-#define RB_SSL_CERTFP_METH_SHA512      2
+/* Digest of full X.509 certificate */
+#define RB_SSL_CERTFP_METH_CERT_SHA1   0x0000
+#define RB_SSL_CERTFP_METH_CERT_SHA256 0x0001
+#define RB_SSL_CERTFP_METH_CERT_SHA512 0x0002
+/* Digest of SubjectPublicKeyInfo (RFC 5280), used by DANE (RFC 6698) */
+#define RB_SSL_CERTFP_METH_SPKI_SHA256 0x1001
+#define RB_SSL_CERTFP_METH_SPKI_SHA512 0x1002
 
 #define RB_SSL_CERTFP_LEN_SHA1         20
 #define RB_SSL_CERTFP_LEN_SHA256       32
index 4038dc3dd2a978f4b7ec872d8d09dde354185ad6..efff9757a57177cbaa1eccc64c365c79759b4934 100644 (file)
 #include <rb_lib.h>
 #include <commio-int.h>
 #include <commio-ssl.h>
+#include <stdbool.h>
 #ifdef HAVE_GNUTLS
 
 #include <gnutls/gnutls.h>
 #include <gnutls/x509.h>
+#include <gnutls/abstract.h>
 
 #if (GNUTLS_VERSION_MAJOR < 3)
 # include <gcrypt.h>
@@ -603,6 +605,7 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
        uint8_t digest[RB_SSL_CERTFP_LEN * 2];
        size_t digest_size;
        int len;
+       bool spki = false;
 
        if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509)
                return 0;
@@ -626,15 +629,19 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
 
        switch(method)
        {
-       case RB_SSL_CERTFP_METH_SHA1:
+       case RB_SSL_CERTFP_METH_CERT_SHA1:
                algo = GNUTLS_DIG_SHA1;
                len = RB_SSL_CERTFP_LEN_SHA1;
                break;
-       case RB_SSL_CERTFP_METH_SHA256:
+       case RB_SSL_CERTFP_METH_SPKI_SHA256:
+               spki = true;
+       case RB_SSL_CERTFP_METH_CERT_SHA256:
                algo = GNUTLS_DIG_SHA256;
                len = RB_SSL_CERTFP_LEN_SHA256;
                break;
-       case RB_SSL_CERTFP_METH_SHA512:
+       case RB_SSL_CERTFP_METH_SPKI_SHA512:
+               spki = true;
+       case RB_SSL_CERTFP_METH_CERT_SHA512:
                algo = GNUTLS_DIG_SHA512;
                len = RB_SSL_CERTFP_LEN_SHA512;
                break;
@@ -642,13 +649,51 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
                return 0;
        }
 
-       if (gnutls_x509_crt_get_fingerprint(cert, algo, digest, &digest_size) < 0)
+       if (!spki)
        {
-               gnutls_x509_crt_deinit(cert);
-               return 0;
+               if (gnutls_x509_crt_get_fingerprint(cert, algo, digest, &digest_size) < 0)
+                       len = 0;
+       }
+       else
+       {
+               gnutls_pubkey_t pubkey;
+               unsigned char *der_pubkey = NULL;
+               size_t der_pubkey_len = 0;
+
+               if (gnutls_pubkey_init(&pubkey) == GNUTLS_E_SUCCESS)
+               {
+                       if (gnutls_pubkey_import_x509(pubkey, cert, 0) == GNUTLS_E_SUCCESS)
+                       {
+                               if (gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_DER, der_pubkey, &der_pubkey_len) == GNUTLS_E_SHORT_MEMORY_BUFFER)
+                               {
+                                       der_pubkey = rb_malloc(der_pubkey_len);
+
+                                       if (gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_DER, der_pubkey, &der_pubkey_len) != GNUTLS_E_SUCCESS)
+                                       {
+                                               rb_free(der_pubkey);
+                                               der_pubkey = NULL;
+                                       }
+                               }
+                       }
+
+                       gnutls_pubkey_deinit(pubkey);
+               }
+
+               if (der_pubkey)
+               {
+                       if (gnutls_hash_fast(algo, der_pubkey, der_pubkey_len, digest) != 0)
+                               len = 0;
+
+                       rb_free(der_pubkey);
+               }
+               else
+               {
+                       len = 0;
+               }
        }
 
-       memcpy(certfp, digest, len);
+       if (len)
+               memcpy(certfp, digest, len);
 
        gnutls_x509_crt_deinit(cert);
        return len;
index 9d9e3f7d3eaed2ae4e1bb71ee6441cc9b3a1a25e..4fd38f177dfdc64e5cf83f7b255ed86d9df7e72f 100644 (file)
@@ -27,6 +27,7 @@
 #include <rb_lib.h>
 #include <commio-int.h>
 #include <commio-ssl.h>
+#include <stdbool.h>
 
 #ifdef HAVE_MBEDTLS
 
@@ -545,18 +546,23 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
        const mbedtls_md_info_t *md_info;
        mbedtls_md_type_t md_type;
        int ret;
+       bool spki = false;
 
        switch (method)
        {
-       case RB_SSL_CERTFP_METH_SHA1:
+       case RB_SSL_CERTFP_METH_CERT_SHA1:
                md_type = MBEDTLS_MD_SHA1;
                hashlen = RB_SSL_CERTFP_LEN_SHA1;
                break;
-       case RB_SSL_CERTFP_METH_SHA256:
+       case RB_SSL_CERTFP_METH_SPKI_SHA256:
+               spki = true;
+       case RB_SSL_CERTFP_METH_CERT_SHA256:
                md_type = MBEDTLS_MD_SHA256;
                hashlen = RB_SSL_CERTFP_LEN_SHA256;
                break;
-       case RB_SSL_CERTFP_METH_SHA512:
+       case RB_SSL_CERTFP_METH_SPKI_SHA512:
+               spki = true;
+       case RB_SSL_CERTFP_METH_CERT_SHA512:
                md_type = MBEDTLS_MD_SHA512;
                hashlen = RB_SSL_CERTFP_LEN_SHA512;
                break;
@@ -572,13 +578,37 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
        if (md_info == NULL)
                return 0;
 
-       if ((ret = mbedtls_md(md_info, peer_cert->raw.p, peer_cert->raw.len, hash)) != 0)
+       if (!spki)
        {
-               rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, -0x%x", -ret);
-               return 0;
+               if ((ret = mbedtls_md(md_info, peer_cert->raw.p, peer_cert->raw.len, hash)) != 0)
+               {
+                       rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, -0x%x", -ret);
+                       hashlen = 0;
+               }
+       }
+       else
+       {
+               const size_t der_pubkey_bufsz = 4096;
+               void *der_pubkey = rb_malloc(der_pubkey_bufsz);
+               int der_pubkey_len;
+
+               der_pubkey_len = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)&peer_cert->pk, der_pubkey, der_pubkey_bufsz);
+               if (der_pubkey_len < 0)
+               {
+                       rb_lib_log("rb_get_ssl_certfp: unable to get pubkey for F: %p, -0x%x", -der_pubkey_len);
+                       hashlen = 0;
+               }
+               else if ((ret = mbedtls_md(md_info, der_pubkey+(der_pubkey_bufsz-der_pubkey_len), der_pubkey_len, hash)) != 0)
+               {
+                       rb_lib_log("rb_get_ssl_certfp: unable to get certfp for F: %p, -0x%x", -ret);
+                       hashlen = 0;
+               }
+
+               rb_free(der_pubkey);
        }
 
-       memcpy(certfp, hash, hashlen);
+       if (hashlen)
+               memcpy(certfp, hash, hashlen);
 
        return hashlen;
 }
index a8d998c4d608ad5ce41624e19cfff8b6718bb9ef..85f07c5ef3325254991cf050a07058a38950f225 100644 (file)
@@ -706,28 +706,49 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method)
                        res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
                        res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
                {
+                       const ASN1_ITEM *it;
                        const EVP_MD *evp;
+                       void *data;
                        unsigned int len;
 
                        switch(method)
                        {
-                       case RB_SSL_CERTFP_METH_SHA1:
+                       case RB_SSL_CERTFP_METH_CERT_SHA1:
+                               it = ASN1_ITEM_rptr(X509);
                                evp = EVP_sha1();
+                               data = cert;
                                len = RB_SSL_CERTFP_LEN_SHA1;
                                break;
-                       case RB_SSL_CERTFP_METH_SHA256:
+                       case RB_SSL_CERTFP_METH_CERT_SHA256:
+                               it = ASN1_ITEM_rptr(X509);
                                evp = EVP_sha256();
+                               data = cert;
                                len = RB_SSL_CERTFP_LEN_SHA256;
                                break;
-                       case RB_SSL_CERTFP_METH_SHA512:
+                       case RB_SSL_CERTFP_METH_CERT_SHA512:
+                               it = ASN1_ITEM_rptr(X509);
                                evp = EVP_sha512();
+                               data = cert;
+                               len = RB_SSL_CERTFP_LEN_SHA512;
+                               break;
+                       case RB_SSL_CERTFP_METH_SPKI_SHA256:
+                               it = ASN1_ITEM_rptr(X509_PUBKEY);
+                               evp = EVP_sha256();
+                               data = X509_get_X509_PUBKEY(cert);
+                               len = RB_SSL_CERTFP_LEN_SHA256;
+                               break;
+                       case RB_SSL_CERTFP_METH_SPKI_SHA512:
+                               it = ASN1_ITEM_rptr(X509_PUBKEY);
+                               evp = EVP_sha512();
+                               data = X509_get_X509_PUBKEY(cert);
                                len = RB_SSL_CERTFP_LEN_SHA512;
                                break;
                        default:
                                return 0;
                        }
 
-                       X509_digest(cert, evp, certfp, &len);
+                       if (ASN1_item_digest(it, evp, data, certfp, &len) != 1)
+                               len = 0;
                        X509_free(cert);
                        return len;
                }
index e8adcb7cf8017d4c9dc33c6cc1ac7441b7f1fe6f..68f0cda3fae10990e497d4dd686542852041afd5 100644 (file)
@@ -152,7 +152,7 @@ static void conn_plain_read_shutdown_cb(rb_fde_t *fd, void *data);
 static void mod_cmd_write_queue(mod_ctl_t * ctl, const void *data, size_t len);
 static const char *remote_closed = "Remote host closed the connection";
 static bool ssld_ssl_ok;
-static int certfp_method = RB_SSL_CERTFP_METH_SHA1;
+static int certfp_method = RB_SSL_CERTFP_METH_CERT_SHA1;
 #ifdef HAVE_LIBZ
 static bool zlib_ok = true;
 #else