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

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: default avatarNikos Mavrogiannopoulos <nmav@gnutls.org>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent af03217b
......@@ -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)) {
......
......@@ -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;
......
......@@ -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,
......
......@@ -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;
......
......@@ -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);
......
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