Commit a43bba3a authored by Kamil Dudka's avatar Kamil Dudka
Browse files

nss: split Curl_nss_connect() into 4 functions

parent c1d61587
Loading
Loading
Loading
Loading
+94 −40
Original line number Diff line number Diff line
@@ -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;
@@ -1586,41 +1646,35 @@ 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;
  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;
  /* switch the SSL socket into non-blocking mode */
  rv = nss_set_nonblock(connssl, data);
  if(rv)
    return rv;

  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;
}

  return curlerr;
}

static ssize_t nss_send(struct connectdata *conn,  /* connection data */
                        int sockindex,             /* socketindex */
                        const void *mem,           /* send this data */