Commit bb8e67dd authored by Nikos Mavrogiannopoulos's avatar Nikos Mavrogiannopoulos Committed by David Woodhouse

Introduce SHA2-256 as a peer certificate hash and make it the default

That is, generate and print a SHA256 hash by default, while also
accept the old 'sha1:' type of certificate hashes.
Signed-off-by: default avatarNikos Mavrogiannopoulos <nmav@redhat.com>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent b8d39711
......@@ -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;
......
......@@ -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)
......@@ -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;
}
......@@ -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;
......@@ -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;
......
......@@ -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);
......@@ -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 {
......@@ -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,
......
......@@ -114,6 +114,7 @@
#include <libxml/tree.h>
#define SHA256_SIZE 32
#define SHA1_SIZE 20
#define MD5_SIZE 16
......@@ -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;
......@@ -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);
......@@ -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,
......
......@@ -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();
......@@ -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
......@@ -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;
}
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment