nss: implement non-blocking SSL handshake

This commit is contained in:
Kamil Dudka 2014-04-17 13:27:39 +02:00
parent a43bba3a34
commit 8868a226cd
4 changed files with 51 additions and 9 deletions

View File

@ -16,6 +16,7 @@ This release includes the following changes:
o sasl: Added DIGEST-MD5 qop-option validation in native challange handling o sasl: Added DIGEST-MD5 qop-option validation in native challange handling
o imap: Expanded mailbox SEARCH support to use URL query strings [7] o imap: Expanded mailbox SEARCH support to use URL query strings [7]
o imap: Extended FETCH support to include PARTIAL URL specifier [7] o imap: Extended FETCH support to include PARTIAL URL specifier [7]
o nss: implement non-blocking SSL handshake
o o
This release includes the following bugfixes: This release includes the following bugfixes:

View File

@ -318,6 +318,7 @@ struct ssl_connect_data {
struct SessionHandle *data; struct SessionHandle *data;
struct curl_llist *obj_list; struct curl_llist *obj_list;
PK11GenericObject *obj_clicert; PK11GenericObject *obj_clicert;
ssl_connect_state connecting_state;
#endif /* USE_NSS */ #endif /* USE_NSS */
#ifdef USE_QSOSSL #ifdef USE_QSOSSL
SSLHandle *handle; SSLHandle *handle;

View File

@ -1611,7 +1611,10 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
/* Force the handshake now */ /* Force the handshake now */
timeout = PR_MillisecondsToInterval((PRUint32) time_left); timeout = PR_MillisecondsToInterval((PRUint32) time_left);
if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) { 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; curlerr = CURLE_PEER_FAILED_VERIFICATION;
else if(conn->data->set.ssl.certverifyresult!=0) else if(conn->data->set.ssl.certverifyresult!=0)
curlerr = CURLE_SSL_CACERT; curlerr = CURLE_SSL_CACERT;
@ -1649,32 +1652,68 @@ error:
return nss_fail_connect(connssl, data, curlerr); 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 ssl_connect_data *connssl = &conn->ssl[sockindex];
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
const bool blocking = (done == NULL);
CURLcode rv; CURLcode rv;
if(connssl->connecting_state == ssl_connect_1) {
rv = nss_setup_connect(conn, sockindex); rv = nss_setup_connect(conn, sockindex);
if(rv) if(rv)
/* we do not expect CURLE_AGAIN from nss_setup_connect() */
return rv; 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); rv = nss_do_connect(conn, sockindex);
switch(rv) { switch(rv) {
case CURLE_OK: case CURLE_OK:
break; break;
case CURLE_AGAIN:
if(!blocking)
/* CURLE_AGAIN in non-blocking mode is not an error */
return CURLE_OK;
/* fall through */
default: default:
return rv; return rv;
} }
/* switch the SSL socket into non-blocking mode */ if(blocking) {
/* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
rv = nss_set_nonblock(connssl, data); rv = nss_set_nonblock(connssl, data);
if(rv) if(rv)
return rv; return rv;
}
else
/* signal completed SSL handshake */
*done = TRUE;
connssl->connecting_state = ssl_connect_done;
return CURLE_OK; 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 */ static ssize_t nss_send(struct connectdata *conn, /* connection data */
int sockindex, /* socketindex */ int sockindex, /* socketindex */
const void *mem, /* send this data */ const void *mem, /* send this data */

View File

@ -68,6 +68,7 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */
#define curlssl_init Curl_nss_init #define curlssl_init Curl_nss_init
#define curlssl_cleanup Curl_nss_cleanup #define curlssl_cleanup Curl_nss_cleanup
#define curlssl_connect Curl_nss_connect #define curlssl_connect Curl_nss_connect
#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking
/* NSS has its own session ID cache */ /* NSS has its own session ID cache */
#define curlssl_session_free(x) Curl_nop_stmt #define curlssl_session_free(x) Curl_nop_stmt