Commit b91b4a9f authored by David Woodhouse's avatar David Woodhouse

Fix lifetime of cstp_cipher and peer_cert_hash strings

Just calculate these during the handshake and keep them around until
the next connection is opened. We don't want to kill them in
openconnect_close_https() because we might want to know what they were
even after a HTTP/1.0 fetch or Connection: Close.
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 5b9c521a
......@@ -1653,49 +1653,48 @@ int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
return get_cert_fingerprint(vpninfo, cert, GNUTLS_DIG_MD5, buf);
}
const char *openconnect_get_peer_cert_hash(struct openconnect_info *vpninfo)
int set_peer_cert_hash(struct openconnect_info *vpninfo)
{
if (!vpninfo->peer_cert)
return NULL;
if (!vpninfo->peer_cert_hash) {
unsigned char sha1[SHA1_SIZE];
size_t shalen = SHA1_SIZE;
gnutls_pubkey_t pkey;
gnutls_datum_t d;
int i;
if (gnutls_pubkey_init(&pkey))
return NULL;
unsigned char sha1[SHA1_SIZE];
size_t shalen = SHA1_SIZE;
gnutls_pubkey_t pkey;
gnutls_datum_t d;
int i, err;
if (gnutls_pubkey_import_x509(pkey, vpninfo->peer_cert, 0)) {
gnutls_pubkey_deinit(pkey);
return NULL;
}
err = gnutls_pubkey_init(&pkey);
if (err)
return err;
if (gnutls_pubkey_export2(pkey, GNUTLS_X509_FMT_DER, &d)) {
gnutls_pubkey_deinit(pkey);
return NULL;
}
err = gnutls_pubkey_import_x509(pkey, vpninfo->peer_cert, 0);
if (err) {
gnutls_pubkey_deinit(pkey);
return err;
}
err = gnutls_pubkey_export2(pkey, GNUTLS_X509_FMT_DER, &d);
if (err) {
gnutls_pubkey_deinit(pkey);
return err;
}
if (gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, sha1, &shalen)) {
gnutls_free(d.data);
return NULL;
}
gnutls_pubkey_deinit(pkey);
err = gnutls_fingerprint(GNUTLS_DIG_SHA1, &d, sha1, &shalen);
if (err) {
gnutls_free(d.data);
return err;
}
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]);
}
gnutls_free(d.data);
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]);
}
return vpninfo->peer_cert_hash;
return 0;
}
char *openconnect_get_peer_cert_details(struct openconnect_info *vpninfo)
......@@ -1746,11 +1745,6 @@ static int verify_peer(gnutls_session_t session)
const char *reason = NULL;
int err = 0;
if (vpninfo->peer_cert) {
gnutls_x509_crt_deinit(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
}
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
if (!cert_list) {
vpn_progress(vpninfo, PRG_ERR, _("Server presented no certificate\n"));
......@@ -1771,8 +1765,11 @@ static int verify_peer(gnutls_session_t session)
}
vpninfo->peer_cert = cert;
free(vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = 0;
err = set_peer_cert_hash(vpninfo);
if (err < 0) {
vpn_progress(vpninfo, PRG_ERR,
_("Could not calculate hash of server's certificate\n"));
}
if (vpninfo->servercert) {
err = openconnect_check_peer_cert_hash(vpninfo, vpninfo->servercert);
......@@ -1903,6 +1900,15 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
if (vpninfo->https_sess)
return 0;
if (vpninfo->peer_cert) {
gnutls_x509_crt_deinit(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
}
free(vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = 0;
gnutls_free(vpninfo->cstp_cipher);
vpninfo->cstp_cipher = NULL;
ssl_sock = connect_https_socket(vpninfo);
if (ssl_sock < 0)
return ssl_sock;
......@@ -2048,6 +2054,9 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
if (err)
return err;
gnutls_free(vpninfo->cstp_cipher);
vpninfo->cstp_cipher = get_gnutls_cipher(vpninfo->https_sess);
vpninfo->ssl_fd = ssl_sock;
vpninfo->ssl_read = openconnect_gnutls_read;
......@@ -2114,13 +2123,6 @@ int cstp_handshake(struct openconnect_info *vpninfo, unsigned init)
void openconnect_close_https(struct openconnect_info *vpninfo, int final)
{
if (vpninfo->peer_cert) {
gnutls_x509_crt_deinit(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
}
free(vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = NULL;
if (vpninfo->https_sess) {
gnutls_deinit(vpninfo->https_sess);
vpninfo->https_sess = NULL;
......@@ -2222,15 +2224,6 @@ char *get_gnutls_cipher(gnutls_session_t session)
return str;
}
const char *openconnect_get_cstp_cipher(struct openconnect_info *vpninfo)
{
if (vpninfo->gnutls_cstp_cipher)
gnutls_free(vpninfo->gnutls_cstp_cipher);
vpninfo->gnutls_cstp_cipher = get_gnutls_cipher(vpninfo->https_sess);
return vpninfo->gnutls_cstp_cipher;
}
int openconnect_sha1(unsigned char *result, void *data, int datalen)
{
gnutls_datum_t d;
......
......@@ -198,7 +198,7 @@ void openconnect_vpninfo_free(struct openconnect_info *vpninfo)
free(vpninfo->ifname);
free(vpninfo->dtls_cipher);
#if defined(OPENCONNECT_GNUTLS)
gnutls_free(vpninfo->gnutls_cstp_cipher);
gnutls_free(vpninfo->cstp_cipher); /* In OpenSSL this is const */
gnutls_free(vpninfo->gnutls_dtls_cipher);
#endif
free(vpninfo->dtls_addr);
......@@ -757,3 +757,13 @@ int openconnect_check_peer_cert_hash(struct openconnect_info *vpninfo,
return 0;
}
const char *openconnect_get_cstp_cipher(struct openconnect_info *vpninfo)
{
return vpninfo->cstp_cipher;
}
const char *openconnect_get_peer_cert_hash(struct openconnect_info *vpninfo)
{
return vpninfo->peer_cert_hash;
}
......@@ -348,8 +348,9 @@ struct openconnect_info {
have fewer ifdefs and accessor macros for it. */
gnutls_session_t dtls_ssl;
char *gnutls_dtls_cipher; /* cached for openconnect_get_dtls_cipher() */
char *gnutls_cstp_cipher;
#endif
char *cstp_cipher;
int dtls_state;
struct keepalive_info dtls_times;
unsigned char dtls_session_id[32];
......
......@@ -891,44 +891,40 @@ int get_cert_md5_fingerprint(struct openconnect_info *vpninfo,
return get_cert_fingerprint(vpninfo, cert, EVP_md5(), buf);
}
const char *openconnect_get_peer_cert_hash(struct openconnect_info *vpninfo)
static int set_peer_cert_hash(struct openconnect_info *vpninfo)
{
if (!vpninfo->peer_cert)
return NULL;
if (!vpninfo->peer_cert_hash) {
unsigned char sha1[SHA1_SIZE];
EVP_PKEY *pkey;
BIO *bp = BIO_new(BIO_s_mem());
BUF_MEM *keyinfo;
int i;
unsigned char sha1[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
SubjectPublicKeyInfo SEQUENCE. */
pkey = X509_get_pubkey(vpninfo->peer_cert);
/* We can't use X509_pubkey_digest() because it only hashes the
subjectPublicKey BIT STRING, and not the whole of the
SubjectPublicKeyInfo SEQUENCE. */
pkey = X509_get_pubkey(vpninfo->peer_cert);
if (!i2d_PUBKEY_bio(bp, pkey)) {
EVP_PKEY_free(pkey);
BIO_free(bp);
return NULL;
}
if (!i2d_PUBKEY_bio(bp, pkey)) {
EVP_PKEY_free(pkey);
BIO_free(bp);
return -ENOMEM;
}
EVP_PKEY_free(pkey);
BIO_get_mem_ptr(bp, &keyinfo);
BIO_get_mem_ptr(bp, &keyinfo);
openconnect_sha1(sha1, keyinfo->data, keyinfo->length);
openconnect_sha1(sha1, keyinfo->data, keyinfo->length);
BIO_free(bp);
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_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]);
}
return vpninfo->peer_cert_hash;
return 0;
}
static int match_hostname_elem(const char *hostname, int helem_len,
......@@ -1338,6 +1334,7 @@ static int check_certificate_expiry(struct openconnect_info *vpninfo)
}
return 0;
}
int openconnect_open_https(struct openconnect_info *vpninfo)
{
method_const SSL_METHOD *ssl3_method;
......@@ -1355,6 +1352,7 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
}
free (vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = NULL;
vpninfo->cstp_cipher = NULL;
ssl_sock = connect_https_socket(vpninfo);
if (ssl_sock < 0)
......@@ -1512,7 +1510,9 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
}
}
vpninfo->cstp_cipher = (char *)SSL_get_cipher_name(https_ssl);
vpninfo->peer_cert = SSL_get_peer_certificate(https_ssl);
set_peer_cert_hash(vpninfo);
if (verify_peer(vpninfo, https_ssl)) {
SSL_free(https_ssl);
......@@ -1541,13 +1541,6 @@ int cstp_handshake(struct openconnect_info *vpninfo, unsigned init)
void openconnect_close_https(struct openconnect_info *vpninfo, int final)
{
if (vpninfo->peer_cert) {
X509_free(vpninfo->peer_cert);
vpninfo->peer_cert = NULL;
}
free (vpninfo->peer_cert_hash);
vpninfo->peer_cert_hash = NULL;
if (vpninfo->https_ssl) {
SSL_free(vpninfo->https_ssl);
vpninfo->https_ssl = NULL;
......@@ -1620,8 +1613,3 @@ int openconnect_local_cert_md5(struct openconnect_info *vpninfo,
return 0;
}
const char *openconnect_get_cstp_cipher(struct openconnect_info *vpninfo)
{
return SSL_get_cipher_name(vpninfo->https_ssl);
}
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