Commit 72f4b534 authored by Kamil Dudka's avatar Kamil Dudka
Browse files

nss: use human-readable error messages provided by NSS

parent a03100c3
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ Curl and libcurl 7.26.1

This release includes the following changes:

 o nss: use human-readable error messages provided by NSS
 o 

This release includes the following bugfixes:
+57 −71
Original line number Diff line number Diff line
@@ -186,6 +186,11 @@ static const char* nss_error_to_name(PRErrorCode code)
  return "unknown error";
}

static void nss_print_error_message(struct SessionHandle *data, PRUint32 err)
{
  failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
}

static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
                             char *cipher_list)
{
@@ -612,61 +617,6 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
  return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
}

static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
  SECStatus result = SECFailure;
  struct connectdata *conn = (struct connectdata *)arg;
  PRErrorCode err = PR_GetError();
  CERTCertificate *cert = NULL;
  char *subject, *subject_cn, *issuer;

  conn->data->set.ssl.certverifyresult=err;
  cert = SSL_PeerCertificate(sock);
  subject = CERT_NameToAscii(&cert->subject);
  subject_cn = CERT_GetCommonName(&cert->subject);
  issuer = CERT_NameToAscii(&cert->issuer);
  CERT_DestroyCertificate(cert);

  switch(err) {
  case SEC_ERROR_CA_CERT_INVALID:
    infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
    break;
  case SEC_ERROR_UNTRUSTED_ISSUER:
    infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
          issuer);
    break;
  case SSL_ERROR_BAD_CERT_DOMAIN:
    if(conn->data->set.ssl.verifyhost) {
      failf(conn->data, "SSL: certificate subject name '%s' does not match "
            "target host name '%s'", subject_cn, conn->host.dispname);
    }
    else {
      result = SECSuccess;
      infof(conn->data, "warning: SSL: certificate subject name '%s' does not "
            "match target host name '%s'\n", subject_cn, conn->host.dispname);
    }
    break;
  case SEC_ERROR_EXPIRED_CERTIFICATE:
    infof(conn->data, "Remote Certificate has expired.\n");
    break;
  case SEC_ERROR_UNKNOWN_ISSUER:
    infof(conn->data, "Peer's certificate issuer is not recognized: '%s'\n",
          issuer);
    break;
  default:
    infof(conn->data, "Bad certificate received. Subject = '%s', "
          "Issuer = '%s'\n", subject, issuer);
    break;
  }
  if(result == SECSuccess)
    infof(conn->data, "SSL certificate verify ok.\n");
  PR_Free(subject);
  PR_Free(subject_cn);
  PR_Free(issuer);

  return result;
}

/**
 * Inform the application that the handshake is complete.
 */
@@ -728,6 +678,31 @@ static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
  return;
}

static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
{
  struct connectdata *conn = (struct connectdata *)arg;
  struct SessionHandle *data = conn->data;
  PRErrorCode err = PR_GetError();
  CERTCertificate *cert;

  /* remember the cert verification result */
  data->set.ssl.certverifyresult = err;

  if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost)
    /* we are asked not to verify the host name */
    return SECSuccess;

  /* print only info about the cert, the error is printed off the callback */
  cert = SSL_PeerCertificate(sock);
  if(cert) {
    infof(data, "Server certificate:\n");
    display_cert_info(data, cert);
    CERT_DestroyCertificate(cert);
  }

  return SECFailure;
}

/**
 *
 * Check that the Peer certificate's issuer certificate matches the one found
@@ -1108,20 +1083,17 @@ int Curl_nss_close_all(struct SessionHandle *data)
  return 0;
}

/* handle client certificate related errors if any; return false otherwise */
static bool handle_cc_error(PRInt32 err, struct SessionHandle *data)
/* return true if the given error code is related to a client certificate */
static bool is_cc_error(PRInt32 err)
{
  switch(err) {
  case SSL_ERROR_BAD_CERT_ALERT:
    failf(data, "SSL error: SSL_ERROR_BAD_CERT_ALERT");
    return true;

  case SSL_ERROR_REVOKED_CERT_ALERT:
    failf(data, "SSL error: SSL_ERROR_REVOKED_CERT_ALERT");
    return true;

  case SSL_ERROR_EXPIRED_CERT_ALERT:
    failf(data, "SSL error: SSL_ERROR_EXPIRED_CERT_ALERT");
    return true;

  default:
@@ -1460,11 +1432,15 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
  data->state.ssl_connect_retry = FALSE;

  err = PR_GetError();
  if(handle_cc_error(err, data))
  if(is_cc_error(err))
    curlerr = CURLE_SSL_CERTPROBLEM;
  else

  /* 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);

  if(model)
    PR_Close(model);

@@ -1496,12 +1472,17 @@ static ssize_t nss_send(struct connectdata *conn, /* connection data */
    PRInt32 err = PR_GetError();
    if(err == PR_WOULD_BLOCK_ERROR)
      *curlcode = CURLE_AGAIN;
    else if(handle_cc_error(err, conn->data))
      *curlcode = CURLE_SSL_CERTPROBLEM;
    else {
      /* print the error number and error string */
      const char *err_name = nss_error_to_name(err);
      failf(conn->data, "SSL write: error %d (%s)", err, err_name);
      *curlcode = CURLE_SEND_ERROR;
      infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);

      /* print a human-readable message describing the error if available */
      nss_print_error_message(conn->data, err);

      *curlcode = (is_cc_error(err))
        ? CURLE_SSL_CERTPROBLEM
        : CURLE_SEND_ERROR;
    }
    return -1;
  }
@@ -1523,12 +1504,17 @@ static ssize_t nss_recv(struct connectdata * conn, /* connection data */

    if(err == PR_WOULD_BLOCK_ERROR)
      *curlcode = CURLE_AGAIN;
    else if(handle_cc_error(err, conn->data))
      *curlcode = CURLE_SSL_CERTPROBLEM;
    else {
      /* print the error number and error string */
      const char *err_name = nss_error_to_name(err);
      failf(conn->data, "SSL read: errno %d (%s)", err, err_name);
      *curlcode = CURLE_RECV_ERROR;
      infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);

      /* print a human-readable message describing the error if available */
      nss_print_error_message(conn->data, err);

      *curlcode = (is_cc_error(err))
        ? CURLE_SSL_CERTPROBLEM
        : CURLE_RECV_ERROR;
    }
    return -1;
  }