From c33349ec21180b3bf70485f92a8609c2530f28af Mon Sep 17 00:00:00 2001 From: Elizabeth Myers Date: Wed, 27 May 2015 16:46:46 -0500 Subject: [PATCH] Add ability to change CertFP hash. Presently this only supports SHA1, as the machinery to actually change the cipher is not hooked up to anything yet. --- libratbox/include/rb_commio.h | 17 +++++++++++++---- libratbox/src/gnutls.c | 28 +++++++++++++++++++++++---- libratbox/src/mbedtls.c | 21 +++++++++++++++++--- libratbox/src/nossl.c | 2 +- libratbox/src/openssl.c | 28 +++++++++++++++++++++++---- src/sslproc.c | 8 +++++--- ssld/ssld.c | 36 ++++++++++++++++++++++++++++------- 7 files changed, 114 insertions(+), 26 deletions(-) diff --git a/libratbox/include/rb_commio.h b/libratbox/include/rb_commio.h index 016c2d27..f37677a4 100644 --- a/libratbox/include/rb_commio.h +++ b/libratbox/include/rb_commio.h @@ -97,10 +97,19 @@ void rb_note(rb_fde_t *, const char *); #define RB_SELECT_READ 0x1 #define RB_SELECT_WRITE 0x2 -#define RB_SELECT_ACCEPT RB_SELECT_READ -#define RB_SELECT_CONNECT RB_SELECT_WRITE +#define RB_SELECT_ACCEPT RB_SELECT_READ +#define RB_SELECT_CONNECT RB_SELECT_WRITE -#define RB_SSL_CERTFP_LEN 20 +#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 + +#define RB_SSL_CERTFP_LEN_SHA1 20 +#define RB_SSL_CERTFP_LEN_SHA256 32 +#define RB_SSL_CERTFP_LEN_SHA512 64 int rb_set_nb(rb_fde_t *); int rb_set_buffers(rb_fde_t *, int); @@ -143,7 +152,7 @@ int rb_select(unsigned long); int rb_fd_ssl(rb_fde_t *F); int rb_get_fd(rb_fde_t *F); const char *rb_get_ssl_strerror(rb_fde_t *F); -int rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]); +int rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method); rb_fde_t *rb_get_fde(int fd); diff --git a/libratbox/src/gnutls.c b/libratbox/src/gnutls.c index ff3e1324..77ad47ef 100644 --- a/libratbox/src/gnutls.c +++ b/libratbox/src/gnutls.c @@ -559,13 +559,15 @@ rb_get_ssl_strerror(rb_fde_t *F) } int -rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) +rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { gnutls_x509_crt_t cert; + gnutls_digest_algorithm_t algo; unsigned int cert_list_size; const gnutls_datum_t *cert_list; uint8_t digest[RB_SSL_CERTFP_LEN * 2]; size_t digest_size; + int len; if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509) return 0; @@ -587,16 +589,34 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) return 0; } - if (gnutls_x509_crt_get_fingerprint(cert, GNUTLS_DIG_SHA1, digest, &digest_size) < 0) + switch(method) + { + case RB_SSL_CERTFP_METH_SHA1: + algo = GNUTLS_DIG_SHA1; + len = RB_SSL_CERTFP_LEN_SHA1; + break; + case RB_SSL_CERTFP_METH_SHA256: + algo = GNUTLS_DIG_SHA256; + len = RB_SSL_CERTFP_LEN_SHA256; + break; + case RB_SSL_CERTFP_METH_SHA512: + algo = GNUTLS_DIG_SHA512; + len = RB_SSL_CERTFP_LEN_SHA512; + break; + default: + return 0; + } + + if (gnutls_x509_crt_get_fingerprint(cert, algo, digest, &digest_size) < 0) { gnutls_x509_crt_deinit(cert); return 0; } - memcpy(certfp, digest, RB_SSL_CERTFP_LEN); + memcpy(certfp, digest, len); gnutls_x509_crt_deinit(cert); - return 1; + return len; } int diff --git a/libratbox/src/mbedtls.c b/libratbox/src/mbedtls.c index 297151da..082f0acc 100644 --- a/libratbox/src/mbedtls.c +++ b/libratbox/src/mbedtls.c @@ -536,18 +536,33 @@ rb_get_ssl_strerror(rb_fde_t *F) } int -rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) +rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { const mbedtls_x509_crt *peer_cert; uint8_t hash[RB_SSL_CERTFP_LEN]; + size_t hashlen; const mbedtls_md_info_t *md_info; + mbedtls_md_type_t md_type; int ret; + switch (method) + { + case RB_SSL_CERTFP_METH_SHA1: + md_type = MBEDTLS_MD_SHA1; + hashlen = RB_SSL_CERTFP_LEN_SHA1; + case RB_SSL_CERTFP_METH_SHA256: + md_type = MBEDTLS_MD_SHA256; + hashlen = RB_SSL_CERTFP_LEN_SHA256; + case RB_SSL_CERTFP_METH_SHA512: + md_type = MBEDTLS_MD_SHA512; + hashlen = RB_SSL_CERTFP_LEN_SHA512; + } + peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F)); if (peer_cert == NULL) return 0; - md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + md_info = mbedtls_md_info_from_type(md_type); if (md_info == NULL) return 0; @@ -557,7 +572,7 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) return 0; } - memcpy(certfp, hash, RB_SSL_CERTFP_LEN); + memcpy(certfp, hash, hashlen); return 1; } diff --git a/libratbox/src/nossl.c b/libratbox/src/nossl.c index 2d0d1462..2133800f 100644 --- a/libratbox/src/nossl.c +++ b/libratbox/src/nossl.c @@ -94,7 +94,7 @@ rb_get_ssl_strerror(rb_fde_t *F) } int -rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) +rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { return 0; } diff --git a/libratbox/src/openssl.c b/libratbox/src/openssl.c index d088f7bb..59e4a16f 100644 --- a/libratbox/src/openssl.c +++ b/libratbox/src/openssl.c @@ -681,7 +681,7 @@ rb_get_ssl_strerror(rb_fde_t *F) } int -rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) +rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN], int method) { X509 *cert; int res; @@ -700,10 +700,30 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN]) res == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT || res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { - unsigned int certfp_length = RB_SSL_CERTFP_LEN; - X509_digest(cert, EVP_sha1(), certfp, &certfp_length); + const EVP_MD *evp; + unsigned int len; + + switch(method) + { + case RB_SSL_CERTFP_METH_SHA1: + evp = EVP_sha1(); + len = RB_SSL_CERTFP_LEN_SHA1; + break; + case RB_SSL_CERTFP_METH_SHA256: + evp = EVP_sha256(); + len = RB_SSL_CERTFP_LEN_SHA256; + break; + case RB_SSL_CERTFP_METH_SHA512: + evp = EVP_sha512(); + len = RB_SSL_CERTFP_LEN_SHA512; + break; + default: + return 0; + } + + X509_digest(cert, evp, certfp, &len); X509_free(cert); - return 1; + return len; } X509_free(cert); } diff --git a/src/sslproc.c b/src/sslproc.c index f7d0b9c6..ff38c282 100644 --- a/src/sslproc.c +++ b/src/sslproc.c @@ -384,6 +384,7 @@ ssl_process_certfp(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf) { struct Client *client_p; int32_t fd; + int32_t len; uint8_t *certfp; char *certfp_string; int i; @@ -392,13 +393,14 @@ ssl_process_certfp(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf) return; /* bogus message..drop it.. XXX should warn here */ fd = buf_to_int32(&ctl_buf->buf[1]); - certfp = (uint8_t *)&ctl_buf->buf[5]; + len = buf_to_int32(&ctl_buf->buf[5]); + certfp = (uint8_t *)&ctl_buf->buf[9]; client_p = find_cli_fd_hash(fd); if(client_p == NULL) return; rb_free(client_p->certfp); - certfp_string = rb_malloc(RB_SSL_CERTFP_LEN * 2 + 1); - for(i = 0; i < RB_SSL_CERTFP_LEN; i++) + certfp_string = rb_malloc(len * 2 + 1); + for(i = 0; i < len; i++) rb_snprintf(certfp_string + 2 * i, 3, "%02x", certfp[i]); client_p->certfp = certfp_string; diff --git a/ssld/ssld.c b/ssld/ssld.c index cad491c2..37c9e060 100644 --- a/ssld/ssld.c +++ b/ssld/ssld.c @@ -159,6 +159,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 int ssl_ok; +static int certfp_method = RB_SSL_CERTFP_METH_SHA1; #ifdef HAVE_LIBZ static int zlib_ok = 1; #else @@ -663,15 +664,18 @@ static void ssl_process_accept_cb(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data) { conn_t *conn = data; - uint8_t buf[5 + RB_SSL_CERTFP_LEN]; + uint8_t buf[9 + RB_SSL_CERTFP_LEN]; if(status == RB_OK) { - if(rb_get_ssl_certfp(F, &buf[5])) + int len = rb_get_ssl_certfp(F, &buf[9], certfp_method); + if(len) { + lrb_assert(len <= RB_SSL_CERTFP_LEN); buf[0] = 'F'; int32_to_buf(&buf[1], conn->id); - mod_cmd_write_queue(conn->ctl, buf, sizeof buf); + int32_to_buf(&buf[5], certfp_method); + mod_cmd_write_queue(conn->ctl, buf, 9 + len); } conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); @@ -686,15 +690,18 @@ static void ssl_process_connect_cb(rb_fde_t *F, int status, void *data) { conn_t *conn = data; - uint8_t buf[5 + RB_SSL_CERTFP_LEN]; + uint8_t buf[9 + RB_SSL_CERTFP_LEN]; if(status == RB_OK) { - if(rb_get_ssl_certfp(F, &buf[5])) + int len = rb_get_ssl_certfp(F, &buf[9], certfp_method); + if(len) { + lrb_assert(len <= RB_SSL_CERTFP_LEN); buf[0] = 'F'; int32_to_buf(&buf[1], conn->id); - mod_cmd_write_queue(conn->ctl, buf, sizeof buf); + int32_to_buf(&buf[5], certfp_method); + mod_cmd_write_queue(conn->ctl, buf, 9 + len); } conn_mod_read_cb(conn->mod_fd, conn); conn_plain_read_cb(conn->plain_fd, conn); @@ -743,6 +750,12 @@ ssl_process_accept(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) rb_ssl_start_accepted(ctlb->F[0], ssl_process_accept_cb, conn, 10); } +static void +ssl_change_certfp_method(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) +{ + certfp_method = buf_to_int32(&ctlb->buf[1]); +} + static void ssl_process_connect(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb) { @@ -988,7 +1001,16 @@ mod_process_cmd_recv(mod_ctl_t * ctl) ssl_process_connect(ctl, ctl_buf); break; } - + case 'F': + { + if (ctl_buf->nfds != 2 || ctl_buf->buflen != 5) + { + cleanup_bad_message(ctl, ctl_buf); + break; + } + ssl_change_certfp_method(ctl, ctl_buf); + break; + } case 'K': { if(!ssl_ok)