You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
591 lines
19 KiB
591 lines
19 KiB
From 355f7594877a62f9aa657e8a72d3f92b3c887d73 Mon Sep 17 00:00:00 2001 |
|
From: Kamil Dudka <kdudka@redhat.com> |
|
Date: Thu, 17 Apr 2014 13:12:59 +0200 |
|
Subject: [PATCH 1/4] nss: split Curl_nss_connect() into 4 functions |
|
|
|
Upstream-commit: a43bba3a34ed8912c4ca10f213590d1998ba0d29 |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/nss.c | 134 +++++++++++++++++++++++++++++++++++++++++++------------------- |
|
1 file changed, 94 insertions(+), 40 deletions(-) |
|
|
|
diff --git a/lib/nss.c b/lib/nss.c |
|
index 1381dc4..4d57a24 100644 |
|
--- a/lib/nss.c |
|
+++ b/lib/nss.c |
|
@@ -1216,9 +1216,62 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver, |
|
return CURLE_SSL_CONNECT_ERROR; |
|
} |
|
|
|
-CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
+static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, |
|
+ struct SessionHandle *data, |
|
+ CURLcode curlerr) |
|
{ |
|
+ SSLVersionRange sslver; |
|
PRErrorCode err = 0; |
|
+ |
|
+ /* reset the flag to avoid an infinite loop */ |
|
+ data->state.ssl_connect_retry = FALSE; |
|
+ |
|
+ if(is_nss_error(curlerr)) { |
|
+ /* read NSPR error code */ |
|
+ err = PR_GetError(); |
|
+ if(is_cc_error(err)) |
|
+ curlerr = CURLE_SSL_CERTPROBLEM; |
|
+ |
|
+ /* print the error number and error string */ |
|
+ infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); |
|
+ |
|
+ /* print a human-readable message describing the error if available */ |
|
+ nss_print_error_message(data, err); |
|
+ } |
|
+ |
|
+ /* cleanup on connection failure */ |
|
+ Curl_llist_destroy(connssl->obj_list, NULL); |
|
+ connssl->obj_list = NULL; |
|
+ |
|
+ if((SSL_VersionRangeGet(connssl->handle, &sslver) == SECSuccess) |
|
+ && (sslver.min == SSL_LIBRARY_VERSION_3_0) |
|
+ && (sslver.max == SSL_LIBRARY_VERSION_TLS_1_0) |
|
+ && isTLSIntoleranceError(err)) { |
|
+ /* schedule reconnect through Curl_retry_request() */ |
|
+ data->state.ssl_connect_retry = TRUE; |
|
+ infof(data, "Error in TLS handshake, trying SSLv3...\n"); |
|
+ return CURLE_OK; |
|
+ } |
|
+ |
|
+ return curlerr; |
|
+} |
|
+ |
|
+/* Switch the SSL socket into non-blocking mode. */ |
|
+static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl, |
|
+ struct SessionHandle *data) |
|
+{ |
|
+ static PRSocketOptionData sock_opt; |
|
+ sock_opt.option = PR_SockOpt_Nonblocking; |
|
+ sock_opt.value.non_blocking = PR_TRUE; |
|
+ |
|
+ if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS) |
|
+ return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); |
|
+ |
|
+ return CURLE_OK; |
|
+} |
|
+ |
|
+static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) |
|
+{ |
|
PRFileDesc *model = NULL; |
|
PRBool ssl_no_cache; |
|
PRBool ssl_cbc_random_iv; |
|
@@ -1226,9 +1279,6 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
curl_socket_t sockfd = conn->sock[sockindex]; |
|
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; |
|
CURLcode curlerr; |
|
- PRSocketOptionData sock_opt; |
|
- long time_left; |
|
- PRUint32 timeout; |
|
|
|
SSLVersionRange sslver = { |
|
SSL_LIBRARY_VERSION_3_0, /* min */ |
|
@@ -1402,16 +1452,32 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
|
|
SSL_SetURL(connssl->handle, conn->host.name); |
|
|
|
+ return CURLE_OK; |
|
+ |
|
+error: |
|
+ if(model) |
|
+ PR_Close(model); |
|
+ |
|
+ return nss_fail_connect(connssl, data, curlerr); |
|
+} |
|
+ |
|
+static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) |
|
+{ |
|
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; |
|
+ struct SessionHandle *data = conn->data; |
|
+ CURLcode curlerr = CURLE_SSL_CONNECT_ERROR; |
|
+ PRUint32 timeout; |
|
+ |
|
/* check timeout situation */ |
|
- time_left = Curl_timeleft(data, NULL, TRUE); |
|
+ const long time_left = Curl_timeleft(data, NULL, TRUE); |
|
if(time_left < 0L) { |
|
failf(data, "timed out before SSL handshake"); |
|
curlerr = CURLE_OPERATION_TIMEDOUT; |
|
goto error; |
|
} |
|
- timeout = PR_MillisecondsToInterval((PRUint32) time_left); |
|
|
|
/* Force the handshake now */ |
|
+ timeout = PR_MillisecondsToInterval((PRUint32) time_left); |
|
if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { |
|
if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) |
|
curlerr = CURLE_PEER_FAILED_VERIFICATION; |
|
@@ -1420,12 +1486,6 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
goto error; |
|
} |
|
|
|
- /* switch the SSL socket into non-blocking mode */ |
|
- sock_opt.option = PR_SockOpt_Nonblocking; |
|
- sock_opt.value.non_blocking = PR_TRUE; |
|
- if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS) |
|
- goto error; |
|
- |
|
connssl->state = ssl_connection_complete; |
|
conn->recv[sockindex] = nss_recv; |
|
conn->send[sockindex] = nss_send; |
|
@@ -1453,40 +1513,34 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
|
|
return CURLE_OK; |
|
|
|
- error: |
|
- /* reset the flag to avoid an infinite loop */ |
|
- data->state.ssl_connect_retry = FALSE; |
|
+error: |
|
+ return nss_fail_connect(connssl, data, curlerr); |
|
+} |
|
|
|
- if(is_nss_error(curlerr)) { |
|
- /* read NSPR error code */ |
|
- err = PR_GetError(); |
|
- if(is_cc_error(err)) |
|
- curlerr = CURLE_SSL_CERTPROBLEM; |
|
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
+{ |
|
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; |
|
+ struct SessionHandle *data = conn->data; |
|
+ CURLcode rv; |
|
|
|
- /* print the error number and error string */ |
|
- infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err)); |
|
+ rv = nss_setup_connect(conn, sockindex); |
|
+ if(rv) |
|
+ return rv; |
|
|
|
- /* print a human-readable message describing the error if available */ |
|
- nss_print_error_message(data, err); |
|
+ rv = nss_do_connect(conn, sockindex); |
|
+ switch(rv) { |
|
+ case CURLE_OK: |
|
+ break; |
|
+ default: |
|
+ return rv; |
|
} |
|
|
|
- if(model) |
|
- PR_Close(model); |
|
- |
|
- /* cleanup on connection failure */ |
|
- Curl_llist_destroy(connssl->obj_list, NULL); |
|
- connssl->obj_list = NULL; |
|
- |
|
- if((sslver.min == SSL_LIBRARY_VERSION_3_0) |
|
- && (sslver.max == SSL_LIBRARY_VERSION_TLS_1_0) |
|
- && isTLSIntoleranceError(err)) { |
|
- /* schedule reconnect through Curl_retry_request() */ |
|
- data->state.ssl_connect_retry = TRUE; |
|
- infof(data, "Error in TLS handshake, trying SSLv3...\n"); |
|
- return CURLE_OK; |
|
- } |
|
+ /* switch the SSL socket into non-blocking mode */ |
|
+ rv = nss_set_nonblock(connssl, data); |
|
+ if(rv) |
|
+ return rv; |
|
|
|
- return curlerr; |
|
+ return CURLE_OK; |
|
} |
|
|
|
static ssize_t nss_send(struct connectdata *conn, /* connection data */ |
|
-- |
|
2.1.0 |
|
|
|
|
|
From b5132ce96009510656e5f719c8805647c246685b Mon Sep 17 00:00:00 2001 |
|
From: Kamil Dudka <kdudka@redhat.com> |
|
Date: Thu, 17 Apr 2014 13:27:39 +0200 |
|
Subject: [PATCH 2/4] nss: implement non-blocking SSL handshake |
|
|
|
Upstream-commit: 8868a226cdad66a9a07d6e3f168884817592a1df |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/nss.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++--------- |
|
lib/nssg.h | 1 + |
|
lib/urldata.h | 1 + |
|
3 files changed, 50 insertions(+), 9 deletions(-) |
|
|
|
diff --git a/lib/nss.c b/lib/nss.c |
|
index 4d57a24..5be1058 100644 |
|
--- a/lib/nss.c |
|
+++ b/lib/nss.c |
|
@@ -1479,7 +1479,10 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) |
|
/* Force the handshake now */ |
|
timeout = PR_MillisecondsToInterval((PRUint32) time_left); |
|
if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { |
|
- if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) |
|
+ if(PR_GetError() == PR_WOULD_BLOCK_ERROR) |
|
+ /* TODO: propagate the blocking direction from the NSPR layer */ |
|
+ return CURLE_AGAIN; |
|
+ else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) |
|
curlerr = CURLE_PEER_FAILED_VERIFICATION; |
|
else if(conn->data->set.ssl.certverifyresult!=0) |
|
curlerr = CURLE_SSL_CACERT; |
|
@@ -1517,32 +1520,68 @@ error: |
|
return nss_fail_connect(connssl, data, curlerr); |
|
} |
|
|
|
-CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
+static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, |
|
+ bool *done) |
|
{ |
|
struct ssl_connect_data *connssl = &conn->ssl[sockindex]; |
|
struct SessionHandle *data = conn->data; |
|
+ const bool blocking = (done == NULL); |
|
CURLcode rv; |
|
|
|
- rv = nss_setup_connect(conn, sockindex); |
|
- if(rv) |
|
- return rv; |
|
+ if(connssl->connecting_state == ssl_connect_1) { |
|
+ rv = nss_setup_connect(conn, sockindex); |
|
+ if(rv) |
|
+ /* we do not expect CURLE_AGAIN from nss_setup_connect() */ |
|
+ return rv; |
|
+ |
|
+ if(!blocking) { |
|
+ /* in non-blocking mode, set NSS non-blocking mode before handshake */ |
|
+ rv = nss_set_nonblock(connssl, data); |
|
+ if(rv) |
|
+ return rv; |
|
+ } |
|
+ |
|
+ connssl->connecting_state = ssl_connect_2; |
|
+ } |
|
|
|
rv = nss_do_connect(conn, sockindex); |
|
switch(rv) { |
|
case CURLE_OK: |
|
break; |
|
+ case CURLE_AGAIN: |
|
+ if(!blocking) |
|
+ /* CURLE_AGAIN in non-blocking mode is not an error */ |
|
+ return CURLE_OK; |
|
+ /* fall through */ |
|
default: |
|
return rv; |
|
} |
|
|
|
- /* switch the SSL socket into non-blocking mode */ |
|
- rv = nss_set_nonblock(connssl, data); |
|
- if(rv) |
|
- return rv; |
|
+ if(blocking) { |
|
+ /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */ |
|
+ rv = nss_set_nonblock(connssl, data); |
|
+ if(rv) |
|
+ return rv; |
|
+ } |
|
+ else |
|
+ /* signal completed SSL handshake */ |
|
+ *done = TRUE; |
|
|
|
+ connssl->connecting_state = ssl_connect_done; |
|
return CURLE_OK; |
|
} |
|
|
|
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) |
|
+{ |
|
+ return nss_connect_common(conn, sockindex, /* blocking */ NULL); |
|
+} |
|
+ |
|
+CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, |
|
+ int sockindex, bool *done) |
|
+{ |
|
+ return nss_connect_common(conn, sockindex, done); |
|
+} |
|
+ |
|
static ssize_t nss_send(struct connectdata *conn, /* connection data */ |
|
int sockindex, /* socketindex */ |
|
const void *mem, /* send this data */ |
|
diff --git a/lib/nssg.h b/lib/nssg.h |
|
index a881a9a..6d9aea6 100644 |
|
--- a/lib/nssg.h |
|
+++ b/lib/nssg.h |
|
@@ -64,6 +64,7 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */ |
|
#define curlssl_init Curl_nss_init |
|
#define curlssl_cleanup Curl_nss_cleanup |
|
#define curlssl_connect Curl_nss_connect |
|
+#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking |
|
|
|
/* NSS has its own session ID cache */ |
|
#define curlssl_session_free(x) Curl_nop_stmt |
|
diff --git a/lib/urldata.h b/lib/urldata.h |
|
index e5d85ff..c91bcff 100644 |
|
--- a/lib/urldata.h |
|
+++ b/lib/urldata.h |
|
@@ -303,6 +303,7 @@ struct ssl_connect_data { |
|
struct SessionHandle *data; |
|
struct curl_llist *obj_list; |
|
PK11GenericObject *obj_clicert; |
|
+ ssl_connect_state connecting_state; |
|
#endif /* USE_NSS */ |
|
#ifdef USE_QSOSSL |
|
SSLHandle *handle; |
|
-- |
|
2.1.0 |
|
|
|
|
|
From 2f1f1b1ca2d9c60c5fca5d73303ae2ec4c3d94b2 Mon Sep 17 00:00:00 2001 |
|
From: Kamil Dudka <kdudka@redhat.com> |
|
Date: Wed, 23 Apr 2014 15:37:26 +0200 |
|
Subject: [PATCH 3/4] nss: propagate blocking direction from NSPR I/O |
|
|
|
... during the non-blocking SSL handshake |
|
|
|
Upstream-commit: 9c941e92c4bd3d2a5dbe243f7517b6a6029afc6e |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/http.c | 2 +- |
|
lib/nss.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
|
2 files changed, 104 insertions(+), 6 deletions(-) |
|
|
|
diff --git a/lib/http.c b/lib/http.c |
|
index d1b0405..c007226 100644 |
|
--- a/lib/http.c |
|
+++ b/lib/http.c |
|
@@ -1351,7 +1351,7 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done) |
|
#endif |
|
|
|
#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ |
|
- defined(USE_DARWINSSL) |
|
+ defined(USE_DARWINSSL) || defined(USE_NSS) |
|
/* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only. |
|
It should be made to query the generic SSL layer instead. */ |
|
static int https_getsock(struct connectdata *conn, |
|
diff --git a/lib/nss.c b/lib/nss.c |
|
index 5be1058..dadeb58 100644 |
|
--- a/lib/nss.c |
|
+++ b/lib/nss.c |
|
@@ -179,6 +179,10 @@ static const cipher_s cipherlist[] = { |
|
static const char* pem_library = "libnsspem.so"; |
|
SECMODModule* mod = NULL; |
|
|
|
+/* NSPR I/O layer we use to detect blocking direction during SSL handshake */ |
|
+static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER; |
|
+static PRIOMethods nspr_io_methods; |
|
+ |
|
static const char* nss_error_to_name(PRErrorCode code) |
|
{ |
|
const char *name = PR_ErrorToName(code); |
|
@@ -861,6 +865,60 @@ isTLSIntoleranceError(PRInt32 err) |
|
} |
|
} |
|
|
|
+/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */ |
|
+static void nss_update_connecting_state(ssl_connect_state state, void *secret) |
|
+{ |
|
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret; |
|
+ if(PR_GetError() != PR_WOULD_BLOCK_ERROR) |
|
+ /* an unrelated error is passing by */ |
|
+ return; |
|
+ |
|
+ switch(connssl->connecting_state) { |
|
+ case ssl_connect_2: |
|
+ case ssl_connect_2_reading: |
|
+ case ssl_connect_2_writing: |
|
+ break; |
|
+ default: |
|
+ /* we are not called from an SSL handshake */ |
|
+ return; |
|
+ } |
|
+ |
|
+ /* update the state accordingly */ |
|
+ connssl->connecting_state = state; |
|
+} |
|
+ |
|
+/* recv() wrapper we use to detect blocking direction during SSL handshake */ |
|
+static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount, |
|
+ PRIntn flags, PRIntervalTime timeout) |
|
+{ |
|
+ const PRRecvFN recv_fn = fd->lower->methods->recv; |
|
+ const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout); |
|
+ if(rv < 0) |
|
+ /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ |
|
+ nss_update_connecting_state(ssl_connect_2_reading, fd->secret); |
|
+ return rv; |
|
+} |
|
+ |
|
+/* send() wrapper we use to detect blocking direction during SSL handshake */ |
|
+static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount, |
|
+ PRIntn flags, PRIntervalTime timeout) |
|
+{ |
|
+ const PRSendFN send_fn = fd->lower->methods->send; |
|
+ const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout); |
|
+ if(rv < 0) |
|
+ /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */ |
|
+ nss_update_connecting_state(ssl_connect_2_writing, fd->secret); |
|
+ return rv; |
|
+} |
|
+ |
|
+/* close() wrapper to avoid assertion failure due to fd->secret != NULL */ |
|
+static PRStatus nspr_io_close(PRFileDesc *fd) |
|
+{ |
|
+ const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close; |
|
+ fd->secret = NULL; |
|
+ return close_fn(fd); |
|
+} |
|
+ |
|
static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) |
|
{ |
|
NSSInitParameters initparams; |
|
@@ -925,6 +983,21 @@ static CURLcode nss_init(struct SessionHandle *data) |
|
} |
|
} |
|
|
|
+ if(nspr_io_identity == PR_INVALID_IO_LAYER) { |
|
+ /* allocate an identity for our own NSPR I/O layer */ |
|
+ nspr_io_identity = PR_GetUniqueIdentity("libcurl"); |
|
+ if(nspr_io_identity == PR_INVALID_IO_LAYER) |
|
+ return CURLE_OUT_OF_MEMORY; |
|
+ |
|
+ /* the default methods just call down to the lower I/O layer */ |
|
+ memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof nspr_io_methods); |
|
+ |
|
+ /* override certain methods in the table by our wrappers */ |
|
+ nspr_io_methods.recv = nspr_io_recv; |
|
+ nspr_io_methods.send = nspr_io_send; |
|
+ nspr_io_methods.close = nspr_io_close; |
|
+ } |
|
+ |
|
rv = nss_init_core(data, cert_dir); |
|
if(rv) |
|
return rv; |
|
@@ -1273,6 +1346,8 @@ static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl, |
|
static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) |
|
{ |
|
PRFileDesc *model = NULL; |
|
+ PRFileDesc *nspr_io = NULL; |
|
+ PRFileDesc *nspr_io_stub = NULL; |
|
PRBool ssl_no_cache; |
|
PRBool ssl_cbc_random_iv; |
|
struct SessionHandle *data = conn->data; |
|
@@ -1433,11 +1508,34 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) |
|
goto error; |
|
} |
|
|
|
- /* Import our model socket onto the existing file descriptor */ |
|
- connssl->handle = PR_ImportTCPSocket(sockfd); |
|
- connssl->handle = SSL_ImportFD(model, connssl->handle); |
|
- if(!connssl->handle) |
|
+ /* wrap OS file descriptor by NSPR's file descriptor abstraction */ |
|
+ nspr_io = PR_ImportTCPSocket(sockfd); |
|
+ if(!nspr_io) |
|
+ goto error; |
|
+ |
|
+ /* create our own NSPR I/O layer */ |
|
+ nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); |
|
+ if(!nspr_io_stub) { |
|
+ PR_Close(nspr_io); |
|
goto error; |
|
+ } |
|
+ |
|
+ /* make the per-connection data accessible from NSPR I/O callbacks */ |
|
+ nspr_io_stub->secret = (void *)connssl; |
|
+ |
|
+ /* push our new layer to the NSPR I/O stack */ |
|
+ if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { |
|
+ PR_Close(nspr_io); |
|
+ PR_Close(nspr_io_stub); |
|
+ goto error; |
|
+ } |
|
+ |
|
+ /* import our model socket onto the current I/O stack */ |
|
+ connssl->handle = SSL_ImportFD(model, nspr_io); |
|
+ if(!connssl->handle) { |
|
+ PR_Close(nspr_io); |
|
+ goto error; |
|
+ } |
|
|
|
PR_Close(model); /* We don't need this any more */ |
|
model = NULL; |
|
@@ -1480,7 +1578,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) |
|
timeout = PR_MillisecondsToInterval((PRUint32) time_left); |
|
if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { |
|
if(PR_GetError() == PR_WOULD_BLOCK_ERROR) |
|
- /* TODO: propagate the blocking direction from the NSPR layer */ |
|
+ /* blocking direction is updated by nss_update_connecting_state() */ |
|
return CURLE_AGAIN; |
|
else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) |
|
curlerr = CURLE_PEER_FAILED_VERIFICATION; |
|
-- |
|
2.1.0 |
|
|
|
|
|
From 813f39b34ecc2634aa8ff332709ddde9235f6891 Mon Sep 17 00:00:00 2001 |
|
From: Kamil Dudka <kdudka@redhat.com> |
|
Date: Mon, 20 Oct 2014 18:18:57 +0200 |
|
Subject: [PATCH 4/4] nss: reset SSL handshake state machine |
|
|
|
... when the handshake succeeds |
|
|
|
This fixes a connection failure when FTPS handle is reused. |
|
|
|
Upstream-commit: 0aecdf682895b42c25b232e91529f48bdf7738b3 |
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com> |
|
--- |
|
lib/nss.c | 17 +++++++++-------- |
|
1 file changed, 9 insertions(+), 8 deletions(-) |
|
|
|
diff --git a/lib/nss.c b/lib/nss.c |
|
index dadeb58..36fa097 100644 |
|
--- a/lib/nss.c |
|
+++ b/lib/nss.c |
|
@@ -1360,9 +1360,6 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) |
|
SSL_LIBRARY_VERSION_TLS_1_0 /* max */ |
|
}; |
|
|
|
- if(connssl->state == ssl_connection_complete) |
|
- return CURLE_OK; |
|
- |
|
connssl->data = data; |
|
|
|
/* list of all NSS objects we need to destroy in Curl_nss_close() */ |
|
@@ -1587,10 +1584,6 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) |
|
goto error; |
|
} |
|
|
|
- connssl->state = ssl_connection_complete; |
|
- conn->recv[sockindex] = nss_recv; |
|
- conn->send[sockindex] = nss_send; |
|
- |
|
display_conn_info(conn, connssl->handle); |
|
|
|
if(data->set.str[STRING_SSL_ISSUERCERT]) { |
|
@@ -1626,6 +1619,9 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, |
|
const bool blocking = (done == NULL); |
|
CURLcode rv; |
|
|
|
+ if(connssl->state == ssl_connection_complete) |
|
+ return CURLE_OK; |
|
+ |
|
if(connssl->connecting_state == ssl_connect_1) { |
|
rv = nss_setup_connect(conn, sockindex); |
|
if(rv) |
|
@@ -1665,7 +1661,12 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, |
|
/* signal completed SSL handshake */ |
|
*done = TRUE; |
|
|
|
- connssl->connecting_state = ssl_connect_done; |
|
+ connssl->state = ssl_connection_complete; |
|
+ conn->recv[sockindex] = nss_recv; |
|
+ conn->send[sockindex] = nss_send; |
|
+ |
|
+ /* ssl_connect_done is never used outside, go back to the initial state */ |
|
+ connssl->connecting_state = ssl_connect_1; |
|
return CURLE_OK; |
|
} |
|
|
|
-- |
|
2.1.0 |
|
|
|
|