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.
This commit is contained in:
Elizabeth Myers 2015-05-27 16:46:46 -05:00 committed by William Pitcock
parent 653e3ca512
commit e6bbb41030
7 changed files with 116 additions and 26 deletions

View file

@ -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);

View file

@ -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

View file

@ -536,18 +536,35 @@ 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;
default:
return 0;
}
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 +574,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;
}

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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)