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:
parent
653e3ca512
commit
e6bbb41030
7 changed files with 116 additions and 26 deletions
|
@ -100,7 +100,16 @@ void rb_note(rb_fde_t *, const char *);
|
||||||
#define RB_SELECT_ACCEPT RB_SELECT_READ
|
#define RB_SELECT_ACCEPT RB_SELECT_READ
|
||||||
#define RB_SELECT_CONNECT RB_SELECT_WRITE
|
#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_nb(rb_fde_t *);
|
||||||
int rb_set_buffers(rb_fde_t *, int);
|
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_fd_ssl(rb_fde_t *F);
|
||||||
int rb_get_fd(rb_fde_t *F);
|
int rb_get_fd(rb_fde_t *F);
|
||||||
const char *rb_get_ssl_strerror(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);
|
rb_fde_t *rb_get_fde(int fd);
|
||||||
|
|
||||||
|
|
|
@ -559,13 +559,15 @@ rb_get_ssl_strerror(rb_fde_t *F)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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_x509_crt_t cert;
|
||||||
|
gnutls_digest_algorithm_t algo;
|
||||||
unsigned int cert_list_size;
|
unsigned int cert_list_size;
|
||||||
const gnutls_datum_t *cert_list;
|
const gnutls_datum_t *cert_list;
|
||||||
uint8_t digest[RB_SSL_CERTFP_LEN * 2];
|
uint8_t digest[RB_SSL_CERTFP_LEN * 2];
|
||||||
size_t digest_size;
|
size_t digest_size;
|
||||||
|
int len;
|
||||||
|
|
||||||
if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509)
|
if (gnutls_certificate_type_get(SSL_P(F)) != GNUTLS_CRT_X509)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -587,16 +589,34 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN])
|
||||||
return 0;
|
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);
|
gnutls_x509_crt_deinit(cert);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(certfp, digest, RB_SSL_CERTFP_LEN);
|
memcpy(certfp, digest, len);
|
||||||
|
|
||||||
gnutls_x509_crt_deinit(cert);
|
gnutls_x509_crt_deinit(cert);
|
||||||
return 1;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -536,18 +536,35 @@ rb_get_ssl_strerror(rb_fde_t *F)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
const mbedtls_x509_crt *peer_cert;
|
||||||
uint8_t hash[RB_SSL_CERTFP_LEN];
|
uint8_t hash[RB_SSL_CERTFP_LEN];
|
||||||
|
size_t hashlen;
|
||||||
const mbedtls_md_info_t *md_info;
|
const mbedtls_md_info_t *md_info;
|
||||||
|
mbedtls_md_type_t md_type;
|
||||||
int ret;
|
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));
|
peer_cert = mbedtls_ssl_get_peer_cert(SSL_P(F));
|
||||||
if (peer_cert == NULL)
|
if (peer_cert == NULL)
|
||||||
return 0;
|
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)
|
if (md_info == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -557,7 +574,7 @@ rb_get_ssl_certfp(rb_fde_t *F, uint8_t certfp[RB_SSL_CERTFP_LEN])
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(certfp, hash, RB_SSL_CERTFP_LEN);
|
memcpy(certfp, hash, hashlen);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ rb_get_ssl_strerror(rb_fde_t *F)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -681,7 +681,7 @@ rb_get_ssl_strerror(rb_fde_t *F)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
X509 *cert;
|
||||||
int res;
|
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_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||||
res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
|
res == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY)
|
||||||
{
|
{
|
||||||
unsigned int certfp_length = RB_SSL_CERTFP_LEN;
|
const EVP_MD *evp;
|
||||||
X509_digest(cert, EVP_sha1(), certfp, &certfp_length);
|
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);
|
X509_free(cert);
|
||||||
return 1;
|
return len;
|
||||||
}
|
}
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
}
|
}
|
||||||
|
|
|
@ -384,6 +384,7 @@ ssl_process_certfp(ssl_ctl_t * ctl, ssl_ctl_buf_t * ctl_buf)
|
||||||
{
|
{
|
||||||
struct Client *client_p;
|
struct Client *client_p;
|
||||||
int32_t fd;
|
int32_t fd;
|
||||||
|
int32_t len;
|
||||||
uint8_t *certfp;
|
uint8_t *certfp;
|
||||||
char *certfp_string;
|
char *certfp_string;
|
||||||
int i;
|
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 */
|
return; /* bogus message..drop it.. XXX should warn here */
|
||||||
|
|
||||||
fd = buf_to_int32(&ctl_buf->buf[1]);
|
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);
|
client_p = find_cli_fd_hash(fd);
|
||||||
if(client_p == NULL)
|
if(client_p == NULL)
|
||||||
return;
|
return;
|
||||||
rb_free(client_p->certfp);
|
rb_free(client_p->certfp);
|
||||||
certfp_string = rb_malloc(RB_SSL_CERTFP_LEN * 2 + 1);
|
certfp_string = rb_malloc(len * 2 + 1);
|
||||||
for(i = 0; i < RB_SSL_CERTFP_LEN; i++)
|
for(i = 0; i < len; i++)
|
||||||
rb_snprintf(certfp_string + 2 * i, 3, "%02x",
|
rb_snprintf(certfp_string + 2 * i, 3, "%02x",
|
||||||
certfp[i]);
|
certfp[i]);
|
||||||
client_p->certfp = certfp_string;
|
client_p->certfp = certfp_string;
|
||||||
|
|
36
ssld/ssld.c
36
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 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 const char *remote_closed = "Remote host closed the connection";
|
||||||
static int ssl_ok;
|
static int ssl_ok;
|
||||||
|
static int certfp_method = RB_SSL_CERTFP_METH_SHA1;
|
||||||
#ifdef HAVE_LIBZ
|
#ifdef HAVE_LIBZ
|
||||||
static int zlib_ok = 1;
|
static int zlib_ok = 1;
|
||||||
#else
|
#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)
|
ssl_process_accept_cb(rb_fde_t *F, int status, struct sockaddr *addr, rb_socklen_t len, void *data)
|
||||||
{
|
{
|
||||||
conn_t *conn = 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(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';
|
buf[0] = 'F';
|
||||||
int32_to_buf(&buf[1], conn->id);
|
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_mod_read_cb(conn->mod_fd, conn);
|
||||||
conn_plain_read_cb(conn->plain_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)
|
ssl_process_connect_cb(rb_fde_t *F, int status, void *data)
|
||||||
{
|
{
|
||||||
conn_t *conn = 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(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';
|
buf[0] = 'F';
|
||||||
int32_to_buf(&buf[1], conn->id);
|
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_mod_read_cb(conn->mod_fd, conn);
|
||||||
conn_plain_read_cb(conn->plain_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);
|
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
|
static void
|
||||||
ssl_process_connect(mod_ctl_t * ctl, mod_ctl_buf_t * ctlb)
|
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);
|
ssl_process_connect(ctl, ctl_buf);
|
||||||
break;
|
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':
|
case 'K':
|
||||||
{
|
{
|
||||||
if(!ssl_ok)
|
if(!ssl_ok)
|
||||||
|
|
Loading…
Reference in a new issue