From: Stefan Eissing Date: Wed, 16 Jul 2025 10:22:30 +0000 (+0200) Subject: gnutls: some small cleanups X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=044de8e19b4a8e759323aed9944c0b55f41815c6;p=thirdparty%2Fcurl.git gnutls: some small cleanups - de-complex Curl_gtls_verifyserver() by splitting of static functions for parts of it. - follow the `goto out` style with common deallocation code Closes #17941 --- diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index f5e02975a0..8aa073e8cc 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -1329,6 +1329,190 @@ void Curl_gtls_report_handshake(struct Curl_easy *data, #endif } +static void gtls_msg_verify_result(struct Curl_easy *data, + struct ssl_peer *peer, + gnutls_x509_crt_t x509_cert, + bool was_verified, + bool needs_verified) +{ + char certname[65] = ""; /* limited to 64 chars by ASN.1 */ + size_t size = sizeof(certname); + int rc; + + rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, + 0, /* the first and only one */ + FALSE, certname, &size); + if(rc) { + infof(data, "error fetching CN from cert:%s", gnutls_strerror(rc)); + certname[0] = 0; + } + + if(!was_verified) { + if(needs_verified) { + failf(data, "SSL: certificate subject name (%s) does not match " + "target hostname '%s'", certname, peer->dispname); + } + else + infof(data, " common name: %s (does not match '%s')", + certname, peer->dispname); + } + else + infof(data, " common name: %s (matched)", certname); +} + +static void gtls_infof_cert(struct Curl_easy *data, + gnutls_x509_crt_t x509_cert) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_is_verbose(data)) { + gnutls_datum_t certfields; + int rc, algo; + time_t tstamp; + unsigned int bits; + + /* public key algorithm's parameters */ + algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); + infof(data, " certificate public key: %s", + gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo)); + + /* version of the X.509 certificate. */ + infof(data, " certificate version: #%d", + gnutls_x509_crt_get_version(x509_cert)); + + rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); + if(rc) + infof(data, "Failed to get certificate name"); + else { + infof(data, " subject: %s", certfields.data); + + tstamp = gnutls_x509_crt_get_activation_time(x509_cert); + showtime(data, "start date", tstamp); + + tstamp = gnutls_x509_crt_get_expiration_time(x509_cert); + showtime(data, "expire date", tstamp); + + gnutls_free(certfields.data); + } + + rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); + if(rc) + infof(data, "Failed to get certificate issuer"); + else { + infof(data, " issuer: %s", certfields.data); + + gnutls_free(certfields.data); + } + } +#else + (void)data; + (void)x509_cert; +#endif +} + +static CURLcode gtls_verify_ocsp_status(struct Curl_easy *data, + gnutls_session_t session) +{ + gnutls_ocsp_resp_t ocsp_resp = NULL; + gnutls_datum_t status_request; + gnutls_ocsp_cert_status_t status; + gnutls_x509_crl_reason_t reason; + CURLcode result = CURLE_OK; + int rc; + + rc = gnutls_ocsp_status_request_get(session, &status_request); + + if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + failf(data, "No OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto out; + } + else if(rc < 0) { + failf(data, "Invalid OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto out; + } + + gnutls_ocsp_resp_init(&ocsp_resp); + + rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto out; + } + + (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, + &status, NULL, NULL, NULL, &reason); + + switch(status) { + case GNUTLS_OCSP_CERT_GOOD: + break; + + case GNUTLS_OCSP_CERT_REVOKED: { + const char *crl_reason; + + switch(reason) { + default: + case GNUTLS_X509_CRLREASON_UNSPECIFIED: + crl_reason = "unspecified reason"; + break; + + case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: + crl_reason = "private key compromised"; + break; + + case GNUTLS_X509_CRLREASON_CACOMPROMISE: + crl_reason = "CA compromised"; + break; + + case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: + crl_reason = "affiliation has changed"; + break; + + case GNUTLS_X509_CRLREASON_SUPERSEDED: + crl_reason = "certificate superseded"; + break; + + case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: + crl_reason = "operation has ceased"; + break; + + case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: + crl_reason = "certificate is on hold"; + break; + + case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: + crl_reason = "will be removed from delta CRL"; + break; + + case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: + crl_reason = "privilege withdrawn"; + break; + + case GNUTLS_X509_CRLREASON_AACOMPROMISE: + crl_reason = "AA compromised"; + break; + } + + failf(data, "Server certificate was revoked: %s", crl_reason); + break; + } + + default: + case GNUTLS_OCSP_CERT_UNKNOWN: + failf(data, "Server certificate status is unknown"); + break; + } + + result = (status != GNUTLS_OCSP_CERT_GOOD) ? + CURLE_SSL_INVALIDCERTSTATUS : CURLE_OK; + +out: + if(ocsp_resp) + gnutls_ocsp_resp_deinit(ocsp_resp); + return result; +} + CURLcode Curl_gtls_verifyserver(struct Curl_easy *data, gnutls_session_t session, @@ -1340,18 +1524,10 @@ Curl_gtls_verifyserver(struct Curl_easy *data, unsigned int cert_list_size; const gnutls_datum_t *chainp; unsigned int verify_status = 0; - gnutls_x509_crt_t x509_cert, x509_issuer; - gnutls_datum_t issuerp; - gnutls_datum_t certfields; - char certname[65] = ""; /* limited to 64 chars by ASN.1 */ - size_t size; + gnutls_x509_crt_t x509_cert = NULL, x509_issuer = NULL; time_t certclock; int rc; CURLcode result = CURLE_OK; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - int algo; - unsigned int bits; -#endif long * const certverifyresult = &ssl_config->certverifyresult; /* This function will return the peer's raw certificate (chain) as sent by @@ -1375,7 +1551,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, #endif failf(data, "failed to get server cert"); *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND; - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; #ifdef USE_GNUTLS_SRP } #endif @@ -1388,7 +1565,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = Curl_ssl_init_certinfo(data, (int)cert_list_size); if(result) - return result; + goto out; for(i = 0; i < cert_list_size; i++) { const char *beg = (const char *) chainp[i].data; @@ -1396,7 +1573,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = Curl_extract_certinfo(data, (int)i, beg, end); if(result) - return result; + goto out; } } @@ -1412,7 +1589,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(rc < 0) { failf(data, "server cert verify failed: %d", rc); *certverifyresult = rc; - return CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; + goto out; } *certverifyresult = verify_status; @@ -1434,7 +1612,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, config->CAfile ? config->CAfile : "none", ssl_config->primary.CRLfile ? ssl_config->primary.CRLfile : "none"); - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; } else infof(data, " server certificate verification FAILED"); @@ -1446,97 +1625,9 @@ Curl_gtls_verifyserver(struct Curl_easy *data, infof(data, " server certificate verification SKIPPED"); if(config->verifystatus) { - gnutls_datum_t status_request; - gnutls_ocsp_resp_t ocsp_resp; - gnutls_ocsp_cert_status_t status; - gnutls_x509_crl_reason_t reason; - - rc = gnutls_ocsp_status_request_get(session, &status_request); - - if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - failf(data, "No OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - gnutls_ocsp_resp_init(&ocsp_resp); - - rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, - &status, NULL, NULL, NULL, &reason); - - switch(status) { - case GNUTLS_OCSP_CERT_GOOD: - break; - - case GNUTLS_OCSP_CERT_REVOKED: { - const char *crl_reason; - - switch(reason) { - default: - case GNUTLS_X509_CRLREASON_UNSPECIFIED: - crl_reason = "unspecified reason"; - break; - - case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: - crl_reason = "private key compromised"; - break; - - case GNUTLS_X509_CRLREASON_CACOMPROMISE: - crl_reason = "CA compromised"; - break; - - case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: - crl_reason = "affiliation has changed"; - break; - - case GNUTLS_X509_CRLREASON_SUPERSEDED: - crl_reason = "certificate superseded"; - break; - - case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: - crl_reason = "operation has ceased"; - break; - - case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: - crl_reason = "certificate is on hold"; - break; - - case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: - crl_reason = "will be removed from delta CRL"; - break; - - case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: - crl_reason = "privilege withdrawn"; - break; - - case GNUTLS_X509_CRLREASON_AACOMPROMISE: - crl_reason = "AA compromised"; - break; - } - - failf(data, "Server certificate was revoked: %s", crl_reason); - break; - } - - default: - case GNUTLS_OCSP_CERT_UNKNOWN: - failf(data, "Server certificate status is unknown"); - break; - } - - gnutls_ocsp_resp_deinit(ocsp_resp); - if(status != GNUTLS_OCSP_CERT_GOOD) - return CURLE_SSL_INVALIDCERTSTATUS; + result = gtls_verify_ocsp_status(data, session); + if(result) + goto out; } else infof(data, " server certificate status verification SKIPPED"); @@ -1550,33 +1641,22 @@ Curl_gtls_verifyserver(struct Curl_easy *data, gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); if(config->issuercert) { + gnutls_datum_t issuerp; gnutls_x509_crt_init(&x509_issuer); issuerp = load_file(config->issuercert); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); rc = (int)gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); - gnutls_x509_crt_deinit(x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", config->issuercert ? config->issuercert : "none"); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_ISSUER_ERROR; + result = CURLE_SSL_ISSUER_ERROR; + goto out; } infof(data, " server certificate issuer check OK (Issuer Cert: %s)", config->issuercert ? config->issuercert : "none"); } - size = sizeof(certname); - rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, - 0, /* the first and only one */ - FALSE, - certname, - &size); - if(rc) { - infof(data, "error fetching CN from cert:%s", - gnutls_strerror(rc)); - } - /* This function will check if the given certificate's subject matches the given hostname. This is a basic implementation of the matching described in RFC2818 (HTTPS), which takes into account wildcards, and the subject @@ -1631,19 +1711,12 @@ Curl_gtls_verifyserver(struct Curl_easy *data, } } #endif - if(!rc) { - if(config->verifyhost) { - failf(data, "SSL: certificate subject name (%s) does not match " - "target hostname '%s'", certname, peer->dispname); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, " common name: %s (does not match '%s')", - certname, peer->dispname); - } - else - infof(data, " common name: %s (matched)", certname); + + result = (!rc && config->verifyhost) ? + CURLE_PEER_FAILED_VERIFICATION : CURLE_OK; + gtls_msg_verify_result(data, peer, x509_cert, rc, config->verifyhost); + if(result) + goto out; /* Check for time-based validity */ certclock = gnutls_x509_crt_get_expiration_time(x509_cert); @@ -1652,8 +1725,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server cert expiration date verify failed"); *certverifyresult = GNUTLS_CERT_EXPIRED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; + goto out; } else infof(data, " server certificate expiration date verify FAILED"); @@ -1663,8 +1736,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server certificate expiration date has passed."); *certverifyresult = GNUTLS_CERT_EXPIRED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; } else infof(data, " server certificate expiration date FAILED"); @@ -1679,8 +1752,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server cert activation date verify failed"); *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; + goto out; } else infof(data, " server certificate activation date verify FAILED"); @@ -1690,8 +1763,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server certificate not activated yet."); *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; } else infof(data, " server certificate activation date FAILED"); @@ -1704,59 +1777,17 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key); if(result != CURLE_OK) { failf(data, "SSL: public key does not match pinned public key"); - gnutls_x509_crt_deinit(x509_cert); - return result; + goto out; } } - /* Show: - - - subject - - start date - - expire date - - common name - - issuer - - */ - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - /* public key algorithm's parameters */ - algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); - infof(data, " certificate public key: %s", - gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo)); - - /* version of the X.509 certificate. */ - infof(data, " certificate version: #%d", - gnutls_x509_crt_get_version(x509_cert)); - - - rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); - if(rc) - infof(data, "Failed to get certificate name"); - else { - infof(data, " subject: %s", certfields.data); - - certclock = gnutls_x509_crt_get_activation_time(x509_cert); - showtime(data, "start date", certclock); - - certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - showtime(data, "expire date", certclock); - - gnutls_free(certfields.data); - } - - rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); - if(rc) - infof(data, "Failed to get certificate issuer"); - else { - infof(data, " issuer: %s", certfields.data); - - gnutls_free(certfields.data); - } -#endif - - gnutls_x509_crt_deinit(x509_cert); + gtls_infof_cert(data, x509_cert); +out: + if(x509_issuer) + gnutls_x509_crt_deinit(x509_issuer); + if(x509_cert) + gnutls_x509_crt_deinit(x509_cert); return result; }