summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls/gtls.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vtls/gtls.c')
-rw-r--r--libs/libcurl/src/vtls/gtls.c221
1 files changed, 124 insertions, 97 deletions
diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c
index aa838b22a7..2d03712801 100644
--- a/libs/libcurl/src/vtls/gtls.c
+++ b/libs/libcurl/src/vtls/gtls.c
@@ -102,7 +102,7 @@ static ssize_t gtls_push(void *s, const void *buf, size_t blen)
CURLcode result;
DEBUGASSERT(data);
- nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
blen, nwritten, result);
backend->gtls.io_result = result;
@@ -340,7 +340,7 @@ static CURLcode handshake(struct Curl_cfilter *cf,
if(!strerr)
strerr = gnutls_strerror(rc);
- failf(data, "gnutls_handshake() failed: %s", strerr);
+ failf(data, "GnuTLS, handshake failed: %s", strerr);
return CURLE_SSL_CONNECT_ERROR;
}
@@ -350,7 +350,7 @@ static CURLcode handshake(struct Curl_cfilter *cf,
}
}
-static gnutls_x509_crt_fmt_t do_file_type(const char *type)
+static gnutls_x509_crt_fmt_t gnutls_do_file_type(const char *type)
{
if(!type || !type[0])
return GNUTLS_X509_FMT_PEM;
@@ -368,11 +368,11 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type)
#define GNUTLS_SRP "+SRP"
static CURLcode
-set_ssl_version_min_max(struct Curl_easy *data,
- struct ssl_peer *peer,
- struct ssl_primary_config *conn_config,
- const char **prioritylist,
- const char *tls13support)
+gnutls_set_ssl_version_min_max(struct Curl_easy *data,
+ struct ssl_peer *peer,
+ struct ssl_primary_config *conn_config,
+ const char **prioritylist,
+ const char *tls13support)
{
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
@@ -850,6 +850,13 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
init_flags |= GNUTLS_NO_TICKETS;
#endif
+#if defined(GNUTLS_NO_STATUS_REQUEST)
+ if(!config->verifystatus)
+ /* Disable the "status_request" TLS extension, enabled by default since
+ GnuTLS 3.8.0. */
+ init_flags |= GNUTLS_NO_STATUS_REQUEST;
+#endif
+
rc = gnutls_init(&gtls->session, init_flags);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_init() failed: %d", rc);
@@ -890,8 +897,8 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
}
/* At this point we know we have a supported TLS version, so set it */
- result = set_ssl_version_min_max(data, peer,
- config, &prioritylist, tls13support);
+ result = gnutls_set_ssl_version_min_max(data, peer,
+ config, &prioritylist, tls13support);
if(result)
return result;
@@ -939,7 +946,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
gtls->shared_creds->creds,
config->clientcert,
ssl_config->key ? ssl_config->key : config->clientcert,
- do_file_type(ssl_config->cert_type),
+ gnutls_do_file_type(ssl_config->cert_type),
ssl_config->key_passwd,
supported_key_encryption_algorithms);
if(rc != GNUTLS_E_SUCCESS) {
@@ -954,7 +961,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
gtls->shared_creds->creds,
config->clientcert,
ssl_config->key ? ssl_config->key : config->clientcert,
- do_file_type(ssl_config->cert_type) ) !=
+ gnutls_do_file_type(ssl_config->cert_type) ) !=
GNUTLS_E_SUCCESS) {
failf(data, "error reading X.509 key or certificate file");
return CURLE_SSL_CONNECT_ERROR;
@@ -1295,9 +1302,18 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* verify_status is a bitmask of gnutls_certificate_status bits */
if(verify_status & GNUTLS_CERT_INVALID) {
if(config->verifypeer) {
- failf(data, "server certificate verification failed. CAfile: %s "
- "CRLfile: %s", config->CAfile ? config->CAfile:
- "none",
+ const char *cause = "certificate error, no details available";
+ if(verify_status & GNUTLS_CERT_EXPIRED)
+ cause = "certificate has expired";
+ else if(verify_status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+ cause = "certificate signer not trusted";
+ else if(verify_status & GNUTLS_CERT_INSECURE_ALGORITHM)
+ cause = "certificate uses insecure algorithm";
+ else if(verify_status & GNUTLS_CERT_INVALID_OCSP_STATUS)
+ cause = "attached OCSP status response is invalid";
+ failf(data, "server verification failed: %s. (CAfile: %s "
+ "CRLfile: %s)", cause,
+ config->CAfile ? config->CAfile: "none",
ssl_config->primary.CRLfile ?
ssl_config->primary.CRLfile : "none");
return CURLE_PEER_FAILED_VERIFICATION;
@@ -1312,104 +1328,97 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
infof(data, " server certificate verification SKIPPED");
if(config->verifystatus) {
- if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
- gnutls_datum_t status_request;
- gnutls_ocsp_resp_t ocsp_resp;
+ gnutls_datum_t status_request;
+ gnutls_ocsp_resp_t ocsp_resp;
+ gnutls_ocsp_cert_status_t status;
+ gnutls_x509_crl_reason_t reason;
- gnutls_ocsp_cert_status_t status;
- gnutls_x509_crl_reason_t reason;
+ rc = gnutls_ocsp_status_request_get(session, &status_request);
- 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;
+ }
- infof(data, " server certificate status verification FAILED");
+ if(rc < 0) {
+ failf(data, "Invalid OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
- if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
- failf(data, "No OCSP response received");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
+ gnutls_ocsp_resp_init(&ocsp_resp);
- if(rc < 0) {
- failf(data, "Invalid OCSP response received");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
+ rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
+ if(rc < 0) {
+ failf(data, "Invalid OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
- gnutls_ocsp_resp_init(&ocsp_resp);
+ (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
+ &status, NULL, NULL, NULL, &reason);
- rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
- if(rc < 0) {
- failf(data, "Invalid OCSP response received");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
+ switch(status) {
+ case GNUTLS_OCSP_CERT_GOOD:
+ break;
- (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
- &status, NULL, NULL, NULL, &reason);
+ case GNUTLS_OCSP_CERT_REVOKED: {
+ const char *crl_reason;
- switch(status) {
- case GNUTLS_OCSP_CERT_GOOD:
+ switch(reason) {
+ default:
+ case GNUTLS_X509_CRLREASON_UNSPECIFIED:
+ crl_reason = "unspecified reason";
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_KEYCOMPROMISE:
+ crl_reason = "private key compromised";
+ break;
- case GNUTLS_X509_CRLREASON_SUPERSEDED:
- crl_reason = "certificate superseded";
- break;
+ case GNUTLS_X509_CRLREASON_CACOMPROMISE:
+ crl_reason = "CA compromised";
+ break;
- case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
- crl_reason = "operation has ceased";
- break;
+ case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
+ crl_reason = "affiliation has changed";
+ break;
- case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
- crl_reason = "certificate is on hold";
- break;
+ case GNUTLS_X509_CRLREASON_SUPERSEDED:
+ crl_reason = "certificate superseded";
+ break;
- case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
- crl_reason = "will be removed from delta CRL";
- break;
+ case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
+ crl_reason = "operation has ceased";
+ break;
- case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
- crl_reason = "privilege withdrawn";
- break;
+ case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
+ crl_reason = "certificate is on hold";
+ break;
- case GNUTLS_X509_CRLREASON_AACOMPROMISE:
- crl_reason = "AA compromised";
- break;
- }
+ case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
+ crl_reason = "will be removed from delta CRL";
+ break;
- failf(data, "Server certificate was revoked: %s", crl_reason);
+ case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
+ crl_reason = "privilege withdrawn";
break;
- }
- default:
- case GNUTLS_OCSP_CERT_UNKNOWN:
- failf(data, "Server certificate status is unknown");
+ case GNUTLS_X509_CRLREASON_AACOMPROMISE:
+ crl_reason = "AA compromised";
break;
}
- gnutls_ocsp_resp_deinit(ocsp_resp);
+ failf(data, "Server certificate was revoked: %s", crl_reason);
+ break;
+ }
- return CURLE_SSL_INVALIDCERTSTATUS;
+ default:
+ case GNUTLS_OCSP_CERT_UNKNOWN:
+ failf(data, "Server certificate status is unknown");
+ break;
}
- else
- infof(data, " server certificate status verification OK");
+
+ gnutls_ocsp_resp_deinit(ocsp_resp);
+ if(status != GNUTLS_OCSP_CERT_GOOD)
+ return CURLE_SSL_INVALIDCERTSTATUS;
}
else
infof(data, " server certificate status verification SKIPPED");
@@ -1769,28 +1778,44 @@ static bool gtls_data_pending(struct Curl_cfilter *cf,
static ssize_t gtls_send(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const void *mem,
- size_t len,
+ const void *buf,
+ size_t blen,
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
ssize_t rc;
+ size_t nwritten, total_written = 0;
(void)data;
DEBUGASSERT(backend);
- backend->gtls.io_result = CURLE_OK;
- rc = gnutls_record_send(backend->gtls.session, mem, len);
+ while(blen) {
+ backend->gtls.io_result = CURLE_OK;
+ rc = gnutls_record_send(backend->gtls.session, buf, blen);
- if(rc < 0) {
- *curlcode = (rc == GNUTLS_E_AGAIN)?
- CURLE_AGAIN :
- (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
+ if(rc < 0) {
+ if(total_written && (rc == GNUTLS_E_AGAIN)) {
+ *curlcode = CURLE_OK;
+ rc = (ssize_t)total_written;
+ goto out;
+ }
+ *curlcode = (rc == GNUTLS_E_AGAIN)?
+ CURLE_AGAIN :
+ (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
- rc = -1;
+ rc = -1;
+ goto out;
+ }
+ nwritten = (size_t)rc;
+ total_written += nwritten;
+ DEBUGASSERT(nwritten <= blen);
+ buf = (char *)buf + nwritten;
+ blen -= nwritten;
}
+ rc = total_written;
+out:
return rc;
}
@@ -1828,6 +1853,7 @@ static CURLcode gtls_shutdown(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye EAGAIN");
connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
+ backend->gtls.sent_shutdown = FALSE;
result = CURLE_OK;
goto out;
}
@@ -2019,6 +2045,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
NULL, /* disassociate_connection */
gtls_recv, /* recv decrypted data */
gtls_send, /* send data to encrypt */
+ NULL, /* get_channel_binding */
};
#endif /* USE_GNUTLS */