{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result;
DEBUGASSERT(data);
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
+ blen, nwritten, result);
+ backend->gtls.io_result = result;
if(nwritten < 0) {
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nwritten = -1;
{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result;
DEBUGASSERT(data);
+ if(!backend->gtls.trust_setup) {
+ result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
+ if(result) {
+ gnutls_transport_set_errno(backend->gtls.session, EINVAL);
+ backend->gtls.io_result = result;
+ return -1;
+ }
+ }
+
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %zd, err=%d",
+ blen, nread, result);
+ backend->gtls.io_result = result;
if(nread < 0) {
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nread = -1;
/* socket is readable or writable */
}
+ backend->gtls.io_result = CURLE_OK;
rc = gnutls_handshake(session);
+ if(!backend->gtls.trust_setup) {
+ /* After having send off the ClientHello, we prepare the trust
+ * store to verify the coming certificate from the server */
+ CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
+ if(result)
+ return result;
+ }
+
if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
connssl->connecting_state =
gnutls_record_get_direction(session)?
infof(data, "gnutls_handshake() warning: %s", strerr);
continue;
}
+ else if((rc < 0) && backend->gtls.io_result) {
+ return backend->gtls.io_result;
+ }
else if(rc < 0) {
const char *strerr = NULL;
return CURLE_SSL_CONNECT_ERROR;
}
-static CURLcode gtls_client_init(struct Curl_easy *data,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- struct gtls_ctx *gtls,
- long *pverifyresult)
+CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct gtls_ctx *gtls)
{
- unsigned int init_flags;
+ struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
int rc;
- bool sni = TRUE; /* default is SNI enabled */
- const char *prioritylist;
- const char *err = NULL;
- const char *tls13support;
- CURLcode result;
-
- if(!gtls_inited)
- gtls_init();
-
- *pverifyresult = 0;
-
- if(config->version == CURL_SSLVERSION_SSLv2) {
- failf(data, "GnuTLS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(config->version == CURL_SSLVERSION_SSLv3)
- sni = FALSE; /* SSLv3 has no SNI */
-
- /* allocate a cred struct */
- rc = gnutls_certificate_allocate_credentials(>ls->cred);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
-#ifdef USE_GNUTLS_SRP
- if(config->username && Curl_auth_allowed_to_host(data)) {
- infof(data, "Using TLS-SRP username: %s", config->username);
-
- rc = gnutls_srp_allocate_client_credentials(>ls->srp_client_cred);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_OUT_OF_MEMORY;
- }
-
- rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
- config->username,
- config->password);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_set_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- }
-#endif
+ CURL_TRC_CF(data, cf, "setup trust anchors and CRLs");
if(config->verifypeer) {
bool imported_native_ca = false;
config->CAfile, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- *pverifyresult = rc;
+ ssl_config->certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
config->CApath, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- *pverifyresult = rc;
+ ssl_config->certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
infof(data, "found %d CRL in %s", rc, config->CRLfile);
}
+ gtls->trust_setup = TRUE;
+ return CURLE_OK;
+}
+
+static CURLcode gtls_client_init(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ struct gtls_ctx *gtls)
+{
+ struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ unsigned int init_flags;
+ int rc;
+ bool sni = TRUE; /* default is SNI enabled */
+ const char *prioritylist;
+ const char *err = NULL;
+ const char *tls13support;
+ CURLcode result;
+
+ if(!gtls_inited)
+ gtls_init();
+
+ if(config->version == CURL_SSLVERSION_SSLv2) {
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(config->version == CURL_SSLVERSION_SSLv3)
+ sni = FALSE; /* SSLv3 has no SNI */
+
+ /* allocate a cred struct */
+ rc = gnutls_certificate_allocate_credentials(>ls->cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef USE_GNUTLS_SRP
+ if(config->username && Curl_auth_allowed_to_host(data)) {
+ infof(data, "Using TLS-SRP username: %s", config->username);
+
+ rc = gnutls_srp_allocate_client_credentials(>ls->srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
+ config->username,
+ config->password);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_set_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+#endif
+
+ ssl_config->certverifyresult = 0;
+
/* Initialize TLS session as a client */
init_flags = GNUTLS_CLIENT;
}
if(config->clientcert) {
+ if(!gtls->trust_setup) {
+ result = Curl_gtls_client_trust_setup(cf, data, gtls);
+ if(result)
+ return result;
+ }
if(ssl_config->key_passwd) {
const unsigned int supported_key_encryption_algorithms =
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
void *ssl_user_data)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- long * const pverifyresult = &ssl_config->certverifyresult;
CURLcode result;
DEBUGASSERT(gctx);
- result = gtls_client_init(data, conn_config, ssl_config, peer,
- gctx, pverifyresult);
+ result = gtls_client_init(cf, data, peer, gctx);
if(result)
return result;
(void)data;
DEBUGASSERT(backend);
+ backend->gtls.io_result = CURLE_OK;
rc = gnutls_record_send(backend->gtls.session, mem, len);
if(rc < 0) {
- *curlcode = (rc == GNUTLS_E_AGAIN)
- ? CURLE_AGAIN
- : CURLE_SEND_ERROR;
+ *curlcode = (rc == GNUTLS_E_AGAIN)?
+ CURLE_AGAIN :
+ (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
rc = -1;
}
(void)data;
DEBUGASSERT(backend);
+ backend->gtls.io_result = CURLE_OK;
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
failf(data, "GnuTLS recv error (%d): %s",
(int)ret, gnutls_strerror((int)ret));
- *curlcode = CURLE_RECV_ERROR;
+ *curlcode = backend->gtls.io_result?
+ backend->gtls.io_result : CURLE_RECV_ERROR;
ret = -1;
goto out;
}