Skip to content

Commit

Permalink
Introduce SHA2-256 as a peer certificate hash and make it the default
Browse files Browse the repository at this point in the history
That is, generate and print a SHA256 hash by default, while also
accept the old 'sha1:' type of certificate hashes.

Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
Nikos Mavrogiannopoulos authored and dwmw2 committed Dec 13, 2016
1 parent b8d3971 commit bb8e67d
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 27 deletions.
15 changes: 15 additions & 0 deletions dtls.c
Expand Up @@ -66,6 +66,21 @@
#define DTLS_RECV gnutls_record_recv
#endif

char *openconnect_bin2hex(const char *prefix, const uint8_t *data, unsigned len)
{
char *v;
unsigned plen = strlen(prefix);
unsigned i;

v = malloc(len*2+plen+1);
if (v) {
snprintf(v, plen+1, "%s", prefix);
for (i = 0; i < len; i++)
sprintf(&v[i*2 + plen], "%02x", data[i]);
}
return v;
}

static int connect_dtls_socket(struct openconnect_info *vpninfo)
{
int dtls_fd, ret;
Expand Down
43 changes: 31 additions & 12 deletions gnutls.c
Expand Up @@ -1927,11 +1927,11 @@ int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,

static int set_peer_cert_hash(struct openconnect_info *vpninfo)
{
unsigned char sha1[SHA1_SIZE];
unsigned char hash[SHA256_SIZE];
size_t shalen;
gnutls_pubkey_t pkey;
gnutls_datum_t d;
int i, err;
int err;

err = gnutls_pubkey_init(&pkey);
if (err)
Expand Down Expand Up @@ -1969,23 +1969,27 @@ static int set_peer_cert_hash(struct openconnect_info *vpninfo)
}
#endif
gnutls_pubkey_deinit(pkey);
shalen = SHA1_SIZE;
shalen = SHA256_SIZE;

err = gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, sha1, &shalen);
err = gnutls_fingerprint(GNUTLS_DIG_SHA256, &d, hash, &shalen);
if (err) {
gnutls_free(d.data);
return err;
}

gnutls_free(d.data);
vpninfo->peer_cert_sha256 = openconnect_bin2hex("sha256:", hash, shalen);

vpninfo->peer_cert_hash = malloc(SHA1_SIZE * 2 + 6);
if (vpninfo->peer_cert_hash) {
snprintf(vpninfo->peer_cert_hash, 6, "sha1:");
for (i = 0; i < shalen; i++)
sprintf(&vpninfo->peer_cert_hash[i*2 + 5], "%02x", sha1[i]);
shalen = SHA1_SIZE;
err = gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, hash, &shalen);
if (err) {
gnutls_free(d.data);
return err;
}

gnutls_free(d.data);

vpninfo->peer_cert_sha1 = openconnect_bin2hex("sha1:", hash, shalen);

return 0;
}

Expand Down Expand Up @@ -2217,8 +2221,10 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
gnutls_x509_crt_deinit(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
}
free(vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = NULL;
free(vpninfo->peer_cert_sha1);
vpninfo->peer_cert_sha1 = NULL;
free(vpninfo->peer_cert_sha256);
vpninfo->peer_cert_sha256 = NULL;
gnutls_free(vpninfo->cstp_cipher);
vpninfo->cstp_cipher = NULL;

Expand Down Expand Up @@ -2695,6 +2701,19 @@ int openconnect_sha1(unsigned char *result, void *data, int datalen)
return 0;
}

int openconnect_sha256(unsigned char *result, void *data, int datalen)
{
gnutls_datum_t d;
size_t shalen = SHA256_SIZE;

d.data = data;
d.size = datalen;
if (gnutls_fingerprint(GNUTLS_DIG_SHA256, &d, result, &shalen))
return -1;

return 0;
}

int openconnect_md5(unsigned char *result, void *data, int datalen)
{
gnutls_datum_t d;
Expand Down
15 changes: 12 additions & 3 deletions library.c
Expand Up @@ -339,7 +339,8 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
free(cache);
}

free(vpninfo->peer_cert_hash);
free(vpninfo->peer_cert_sha1);
free(vpninfo->peer_cert_sha256);
free(vpninfo->localname);
free(vpninfo->useragent);
free(vpninfo->authgroup);
Expand Down Expand Up @@ -942,7 +943,15 @@ int openconnect_check_peer_cert_hash(struct openconnect_info *vpninfo,
const char *fingerprint;

if (strchr(old_hash, ':')) {
fingerprint = openconnect_get_peer_cert_hash(vpninfo);
if (strncmp(old_hash, "sha1:", 5) == 0) {
fingerprint = vpninfo->peer_cert_sha1;
} else if (strncmp(old_hash, "sha256:", 7) == 0) {
fingerprint = vpninfo->peer_cert_sha256;
} else {
vpn_progress(vpninfo, PRG_ERR, _("Unknown certificate hash: %s.\n"), old_hash);
return -EIO;
}

if (!fingerprint)
return -EIO;
} else {
Expand Down Expand Up @@ -976,7 +985,7 @@ const char *openconnect_get_cstp_cipher(struct openconnect_info *vpninfo)

const char *openconnect_get_peer_cert_hash(struct openconnect_info *vpninfo)
{
return vpninfo->peer_cert_hash;
return vpninfo->peer_cert_sha256;
}

int openconnect_set_compression_mode(struct openconnect_info *vpninfo,
Expand Down
6 changes: 5 additions & 1 deletion openconnect-internal.h
Expand Up @@ -114,6 +114,7 @@

#include <libxml/tree.h>

#define SHA256_SIZE 32
#define SHA1_SIZE 20
#define MD5_SIZE 16

Expand Down Expand Up @@ -454,7 +455,8 @@ struct openconnect_info {
void *tok_cbdata;

void *peer_cert;
char *peer_cert_hash;
char *peer_cert_sha1;
char *peer_cert_sha256;
void *cert_list_handle;
int cert_list_size;

Expand Down Expand Up @@ -819,6 +821,7 @@ void append_dtls_ciphers(struct openconnect_info *vpninfo, struct oc_text_buf *b
void dtls_detect_mtu(struct openconnect_info *vpninfo);
int openconnect_dtls_read(struct openconnect_info *vpninfo, void *buf, size_t len, unsigned ms);
int openconnect_dtls_write(struct openconnect_info *vpninfo, void *buf, size_t len);
char *openconnect_bin2hex(const char *prefix, const uint8_t *data, unsigned len);

/* cstp.c */
void cstp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
Expand Down Expand Up @@ -900,6 +903,7 @@ int cstp_handshake(struct openconnect_info *vpninfo, unsigned init);
int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, void *cert,
char *buf);
int openconnect_sha1(unsigned char *result, void *data, int len);
int openconnect_sha256(unsigned char *result, void *data, int len);
int openconnect_md5(unsigned char *result, void *data, int len);
int openconnect_random(void *bytes, int len);
int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
Expand Down
34 changes: 23 additions & 11 deletions openssl.c
Expand Up @@ -62,6 +62,19 @@ int openconnect_sha1(unsigned char *result, void *data, int len)
return 0;
}

int openconnect_sha256(unsigned char *result, void *data, int len)
{
EVP_MD_CTX *c = EVP_MD_CTX_new();

if (!c)
return -ENOMEM;

EVP_Digest(data, len, result, NULL, EVP_sha256(), NULL);
EVP_MD_CTX_free(c);

return 0;
}

int openconnect_md5(unsigned char *result, void *data, int len)
{
EVP_MD_CTX *c = EVP_MD_CTX_new();
Expand Down Expand Up @@ -1086,11 +1099,11 @@ int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,

static int set_peer_cert_hash(struct openconnect_info *vpninfo)
{
unsigned char sha1[SHA1_SIZE];
unsigned char sha256_hash[SHA256_SIZE];
unsigned char sha1_hash[SHA1_SIZE];
EVP_PKEY *pkey;
BIO *bp = BIO_new(BIO_s_mem());
BUF_MEM *keyinfo;
int i;

/* We can't use X509_pubkey_digest() because it only hashes the
subjectPublicKey BIT STRING, and not the whole of the
Expand All @@ -1106,16 +1119,13 @@ static int set_peer_cert_hash(struct openconnect_info *vpninfo)

BIO_get_mem_ptr(bp, &keyinfo);

openconnect_sha1(sha1, keyinfo->data, keyinfo->length);
openconnect_sha256(sha256_hash, keyinfo->data, keyinfo->length);
openconnect_sha1(sha1_hash, keyinfo->data, keyinfo->length);

BIO_free(bp);

vpninfo->peer_cert_hash = malloc(SHA1_SIZE * 2 + 6);
if (vpninfo->peer_cert_hash) {
snprintf(vpninfo->peer_cert_hash, 6, "sha1:");
for (i = 0; i < sizeof(sha1); i++)
sprintf(&vpninfo->peer_cert_hash[i*2 + 5], "%02x", sha1[i]);
}
vpninfo->peer_cert_sha1 = openconnect_bin2hex("sha1:", sha1_hash, sizeof(sha1_hash));
vpninfo->peer_cert_sha256 = openconnect_bin2hex("sha256:", sha256_hash, sizeof(sha256_hash));

return 0;
}
Expand Down Expand Up @@ -1648,8 +1658,10 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
X509_free(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
}
free (vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = NULL;
free (vpninfo->peer_cert_sha1);
vpninfo->peer_cert_sha1 = NULL;
free (vpninfo->peer_cert_sha256);
vpninfo->peer_cert_sha256 = NULL;
vpninfo->cstp_cipher = NULL;

ssl_sock = connect_https_socket(vpninfo);
Expand Down

0 comments on commit bb8e67d

Please sign in to comment.