From b3e5f0021c647761f26c2e5a37f5fed705880001 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sun, 5 Mar 2017 11:37:24 +0100 Subject: [PATCH] Store only the SHA1 and SHA256 of the public key internally This will allow switching to other representation formats for output or input of public key PIN. For example to the RFC7469 key PIN. Signed-off-by: Nikos Mavrogiannopoulos Signed-off-by: David Woodhouse --- dtls.c | 3 ++- gnutls.c | 20 +++++++------------- library.c | 26 +++++++++++--------------- openconnect-internal.h | 7 +++++-- openssl.c | 15 ++++----------- 5 files changed, 29 insertions(+), 42 deletions(-) diff --git a/dtls.c b/dtls.c index 28088fb8..a10d4ed3 100644 --- a/dtls.c +++ b/dtls.c @@ -72,7 +72,8 @@ char *openconnect_bin2hex(const char *prefix, const uint8_t *data, unsigned len) char *p = NULL; buf = buf_alloc(); - buf_append(buf, "%s", prefix); + if (prefix) + buf_append(buf, "%s", prefix); buf_append_hex(buf, data, len); if (!buf_error(buf)) { diff --git a/gnutls.c b/gnutls.c index b32d497b..ea96cef5 100644 --- a/gnutls.c +++ b/gnutls.c @@ -1927,7 +1927,6 @@ int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, static int set_peer_cert_hash(struct openconnect_info *vpninfo) { - unsigned char hash[SHA256_SIZE]; size_t shalen; gnutls_pubkey_t pkey; gnutls_datum_t d; @@ -1969,18 +1968,16 @@ static int set_peer_cert_hash(struct openconnect_info *vpninfo) } #endif gnutls_pubkey_deinit(pkey); - shalen = SHA256_SIZE; - err = gnutls_fingerprint(GNUTLS_DIG_SHA256, &d, hash, &shalen); + shalen = sizeof(vpninfo->peer_cert_sha256_raw); + err = gnutls_fingerprint(GNUTLS_DIG_SHA256, &d, vpninfo->peer_cert_sha256_raw, &shalen); if (err) { gnutls_free(d.data); return err; } - vpninfo->peer_cert_sha256 = openconnect_bin2hex("sha256:", hash, shalen); - - shalen = SHA1_SIZE; - err = gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, hash, &shalen); + shalen = sizeof(vpninfo->peer_cert_sha1_raw); + err = gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, vpninfo->peer_cert_sha1_raw, &shalen); if (err) { gnutls_free(d.data); return err; @@ -1988,8 +1985,6 @@ static int set_peer_cert_hash(struct openconnect_info *vpninfo) gnutls_free(d.data); - vpninfo->peer_cert_sha1 = openconnect_bin2hex("sha1:", hash, shalen); - return 0; } @@ -2221,10 +2216,9 @@ int openconnect_open_https(struct openconnect_info *vpninfo) gnutls_x509_crt_deinit(vpninfo->peer_cert); vpninfo->peer_cert = NULL; } - free(vpninfo->peer_cert_sha1); - vpninfo->peer_cert_sha1 = NULL; - free(vpninfo->peer_cert_sha256); - vpninfo->peer_cert_sha256 = NULL; + + free(vpninfo->peer_cert_hash); + vpninfo->peer_cert_hash = NULL; gnutls_free(vpninfo->cstp_cipher); vpninfo->cstp_cipher = NULL; diff --git a/library.c b/library.c index 6ab74410..3ca1e7a5 100644 --- a/library.c +++ b/library.c @@ -368,8 +368,6 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo) free(cache); } - free(vpninfo->peer_cert_sha1); - free(vpninfo->peer_cert_sha256); free(vpninfo->localname); free(vpninfo->useragent); free(vpninfo->authgroup); @@ -968,29 +966,25 @@ int openconnect_set_csd_environ(struct openconnect_info *vpninfo, int openconnect_check_peer_cert_hash(struct openconnect_info *vpninfo, const char *old_hash) { - char sha1_text[41]; - const char *fingerprint; + char *fingerprint = NULL; unsigned min_match_len; unsigned real_min_match_len = 4; unsigned old_len, fingerprint_len; if (strchr(old_hash, ':')) { if (strncmp(old_hash, "sha1:", 5) == 0) { - fingerprint = vpninfo->peer_cert_sha1; + fingerprint = openconnect_bin2hex("sha1:", vpninfo->peer_cert_sha1_raw, sizeof(vpninfo->peer_cert_sha1_raw)); min_match_len = real_min_match_len + sizeof("sha1:")-1; } else if (strncmp(old_hash, "sha256:", 7) == 0) { - fingerprint = vpninfo->peer_cert_sha256; + fingerprint = openconnect_bin2hex("sha256:", vpninfo->peer_cert_sha256_raw, sizeof(vpninfo->peer_cert_sha256_raw)); min_match_len = real_min_match_len + sizeof("sha256:")-1; } else { vpn_progress(vpninfo, PRG_ERR, _("Unknown certificate hash: %s.\n"), old_hash); return -EIO; } - - if (!fingerprint) - return -EIO; } else { unsigned char *cert; - int len, i; + int len; unsigned char sha1_bin[SHA1_SIZE]; len = openconnect_get_peer_cert_DER(vpninfo, &cert); @@ -1000,13 +994,13 @@ int openconnect_check_peer_cert_hash(struct openconnect_info *vpninfo, if (openconnect_sha1(sha1_bin, cert, len)) return -EIO; - for (i = 0; i < sizeof(sha1_bin); i++) - sprintf(&sha1_text[i*2], "%02x", sha1_bin[i]); - - fingerprint = sha1_text; + fingerprint = openconnect_bin2hex(NULL, sha1_bin, sizeof(sha1_bin)); min_match_len = real_min_match_len; } + if (!fingerprint) + return -EIO; + old_len = strlen(old_hash); fingerprint_len = strlen(fingerprint); @@ -1033,7 +1027,9 @@ 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_sha256; + if (vpninfo->peer_cert_hash == NULL) + vpninfo->peer_cert_hash = openconnect_bin2hex("sha256:", vpninfo->peer_cert_sha256_raw, sizeof(vpninfo->peer_cert_sha256_raw)); + return vpninfo->peer_cert_hash; } int openconnect_set_compression_mode(struct openconnect_info *vpninfo, diff --git a/openconnect-internal.h b/openconnect-internal.h index 117ca19e..291eb4b7 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -458,8 +458,11 @@ struct openconnect_info { void *tok_cbdata; void *peer_cert; - char *peer_cert_sha1; - char *peer_cert_sha256; + /* The SHA1 and SHA256 hashes of the peer's public key */ + uint8_t peer_cert_sha1_raw[SHA1_SIZE]; + uint8_t peer_cert_sha256_raw[SHA256_SIZE]; + /* this value is cache for openconnect_get_peer_cert_hash */ + char *peer_cert_hash; void *cert_list_handle; int cert_list_size; diff --git a/openssl.c b/openssl.c index 20226d55..52c95484 100644 --- a/openssl.c +++ b/openssl.c @@ -1099,8 +1099,6 @@ int get_cert_md5_fingerprint(struct openconnect_info *vpninfo, static int set_peer_cert_hash(struct openconnect_info *vpninfo) { - 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; @@ -1119,14 +1117,11 @@ static int set_peer_cert_hash(struct openconnect_info *vpninfo) BIO_get_mem_ptr(bp, &keyinfo); - openconnect_sha256(sha256_hash, keyinfo->data, keyinfo->length); - openconnect_sha1(sha1_hash, keyinfo->data, keyinfo->length); + openconnect_sha256(vpninfo->peer_cert_sha256_raw, keyinfo->data, keyinfo->length); + openconnect_sha1(vpninfo->peer_cert_sha1_raw, keyinfo->data, keyinfo->length); BIO_free(bp); - 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; } @@ -1658,10 +1653,8 @@ int openconnect_open_https(struct openconnect_info *vpninfo) X509_free(vpninfo->peer_cert); vpninfo->peer_cert = NULL; } - free (vpninfo->peer_cert_sha1); - vpninfo->peer_cert_sha1 = NULL; - free (vpninfo->peer_cert_sha256); - vpninfo->peer_cert_sha256 = NULL; + free(vpninfo->peer_cert_hash); + vpninfo->peer_cert_hash = NULL; vpninfo->cstp_cipher = NULL; ssl_sock = connect_https_socket(vpninfo);