diff --git a/gnutls.c b/gnutls.c index b844f496..8031621b 100644 --- a/gnutls.c +++ b/gnutls.c @@ -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; diff --git a/library.c b/library.c index 5e4c52c8..20ff04e7 100644 --- a/library.c +++ b/library.c @@ -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; +} diff --git a/openconnect-internal.h b/openconnect-internal.h index 352b9989..9f766b33 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -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]; diff --git a/openssl.c b/openssl.c index 308d502a..f3d0dd7a 100644 --- a/openssl.c +++ b/openssl.c @@ -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); -}