527 lines
17 KiB
Diff
527 lines
17 KiB
Diff
|
From 79dd8298f45b9f5dd97c06c397d40e45f905d5d3 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/3] nss: split Curl_nss_connect() into 4 functions
|
||
|
|
||
|
[upstream commit a43bba3a34ed8912c4ca10f213590d1998ba0d29]
|
||
|
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/vtls/nss.c | 134 +++++++++++++++++++++++++++++++++++++++-----------------
|
||
|
1 files changed, 94 insertions(+), 40 deletions(-)
|
||
|
|
||
|
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
|
||
|
index 80e26e2..4f4e6c8 100644
|
||
|
--- a/lib/vtls/nss.c
|
||
|
+++ b/lib/vtls/nss.c
|
||
|
@@ -1296,9 +1296,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;
|
||
|
@@ -1306,9 +1359,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 */
|
||
|
@@ -1534,16 +1584,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;
|
||
|
@@ -1552,12 +1618,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;
|
||
|
@@ -1585,40 +1645,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 */
|
||
|
--
|
||
|
1.7.1
|
||
|
|
||
|
|
||
|
From f6c04350401c111f92f1428f80a28b66f6609cac 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/3] nss: implement non-blocking SSL handshake
|
||
|
|
||
|
[upstream commit 8868a226cdad66a9a07d6e3f168884817592a1df]
|
||
|
|
||
|
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
|
||
|
---
|
||
|
lib/urldata.h | 1 +
|
||
|
lib/vtls/nss.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++--------
|
||
|
lib/vtls/nssg.h | 1 +
|
||
|
3 files changed, 50 insertions(+), 9 deletions(-)
|
||
|
|
||
|
diff --git a/lib/urldata.h b/lib/urldata.h
|
||
|
index 25f9676..d3bb350 100644
|
||
|
--- a/lib/urldata.h
|
||
|
+++ b/lib/urldata.h
|
||
|
@@ -318,6 +318,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;
|
||
|
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
|
||
|
index 4f4e6c8..e076e54 100644
|
||
|
--- a/lib/vtls/nss.c
|
||
|
+++ b/lib/vtls/nss.c
|
||
|
@@ -1611,7 +1611,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;
|
||
|
@@ -1649,32 +1652,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/vtls/nssg.h b/lib/vtls/nssg.h
|
||
|
index 38181a9..21e96ce 100644
|
||
|
--- a/lib/vtls/nssg.h
|
||
|
+++ b/lib/vtls/nssg.h
|
||
|
@@ -68,6 +68,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
|
||
|
--
|
||
|
1.7.1
|
||
|
|
||
|
|
||
|
From 9fb78efb737ea8c2a9f7c27ea501b1fcf6a90599 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/3] 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/vtls/nss.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
|
||
|
2 files changed, 104 insertions(+), 6 deletions(-)
|
||
|
|
||
|
diff --git a/lib/http.c b/lib/http.c
|
||
|
index 4a29058..3f8a4c0 100644
|
||
|
--- a/lib/http.c
|
||
|
+++ b/lib/http.c
|
||
|
@@ -1361,7 +1361,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_POLARSSL)
|
||
|
+ defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS)
|
||
|
/* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only.
|
||
|
It should be made to query the generic SSL layer instead. */
|
||
|
static int https_getsock(struct connectdata *conn,
|
||
|
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
|
||
|
index e076e54..3447f97 100644
|
||
|
--- a/lib/vtls/nss.c
|
||
|
+++ b/lib/vtls/nss.c
|
||
|
@@ -180,6 +180,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);
|
||
|
@@ -940,6 +944,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;
|
||
|
@@ -1004,6 +1062,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;
|
||
|
@@ -1353,6 +1426,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;
|
||
|
@@ -1525,11 +1600,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;
|
||
|
@@ -1612,7 +1710,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;
|
||
|
--
|
||
|
1.7.1
|
||
|
|