Commit 13d865d8 authored by kaie@kuix.de's avatar kaie@kuix.de
Browse files

Bug 401755, Cleanup nsNSSIOLayer.cpp->getErrorMessage r=rrelyea, a=mtschrep

parent 2869efb5
Loading
Loading
Loading
Loading
+309 −226
Original line number Diff line number Diff line
@@ -651,51 +651,13 @@ getErrorMessage(PRInt32 err,
  return NS_OK;
}

static nsresult
getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors, 
                           PRErrorCode errorCodeToReport, 
                           PRErrorCode errTrust, 
                           PRErrorCode errMismatch, 
                           PRErrorCode errExpired,
static void
AppendErrorTextUntrusted(PRErrorCode errTrust,
                         const nsString &host,
                           const nsString &hostWithPort,
                           PRInt32 port,
                         nsIX509Cert* ix509,
                           PRBool externalErrorReporting,
                         nsINSSComponent *component,
                         nsString &returnedMessage)
{
  NS_ENSURE_ARG_POINTER(component);

  const PRUnichar *params[1];
  nsresult rv;

  // For now, hide port when it's 443 and we're reporting the error using
  // external reporting. In the future a better mechanism should be used
  // to make a decision about showing the port number, possibly by requiring
  // the context object to implement a specific interface.
  // The motivation is that Mozilla browser would like to hide the port number
  // in error pages in the common case.
  
  if (externalErrorReporting && port == 443)
    params[0] = host.get();
  else
    params[0] = hostWithPort.get();

  nsString formattedString;
  rv = component->PIPBundleFormatStringFromName("certErrorIntro", 
                                                params, 1, 
                                                formattedString);
  if (NS_SUCCEEDED(rv))
  {
    returnedMessage.Append(formattedString);
    returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
  }

  if (multipleCollectedErrors & nsICertOverrideService::ERROR_UNTRUSTED)
  {
    params[0] = host.get();

  const char *errorID = nsnull;
  nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
  if (cert3) {
@@ -728,7 +690,7 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
  }

  nsString formattedString;
    rv = component->GetPIPNSSBundleString(errorID, 
  nsresult rv = component->GetPIPNSSBundleString(errorID, 
                                                 formattedString);
  if (NS_SUCCEEDED(rv))
  {
@@ -737,46 +699,39 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
  }
}

  if (multipleCollectedErrors & nsICertOverrideService::ERROR_MISMATCH)
// returns TRUE if SAN was used to produce names
// return FALSE if nothing was produced
// names => a single name or a list of names
// multipleNames => whether multiple names were delivered
static PRBool
GetSubjectAltNames(CERTCertificate *nssCert,
                   nsINSSComponent *component,
                   nsString &allNames,
                   PRBool &multipleNames)
{
    PRBool useSAN = PR_TRUE; // subject alt name extension
    PRBool multipleNames = PR_FALSE;
    nsString allNames;

    CERTCertificate *nssCert = NULL;
    CERTCertificateCleaner nssCertCleaner(nssCert);
    nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
    if (cert2)
      nssCert = cert2->GetCert();
    if (!nssCert)
      useSAN = PR_FALSE;
  allNames.Truncate();
  multipleNames = PR_FALSE;

  PRArenaPool *san_arena = nsnull;
  SECItem altNameExtension = {siBuffer, NULL, 0 };
  CERTGeneralName *sanNameList = nsnull;

    if (useSAN) {
  nsresult rv;
  rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
                              &altNameExtension);
  if (rv != SECSuccess)
        useSAN = PR_FALSE;
    }
    return PR_FALSE;

    if (useSAN) {
  san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  if (!san_arena)
        useSAN = PR_FALSE;
    }
    return PR_FALSE;

    if (useSAN) {
  sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
  if (!sanNameList)
        useSAN = PR_FALSE;
    }
    return PR_FALSE;

  SECITEM_FreeItem(&altNameExtension, PR_FALSE);

    if (useSAN) {
  CERTGeneralName *current = sanNameList;
  do {
    nsAutoString name;
@@ -822,19 +777,61 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
    }
    current = CERT_GetNextGeneralName(current);
  } while (current != sanNameList); // double linked
    }
    if (san_arena)

  PORT_FreeArena(san_arena, PR_FALSE);
  return PR_TRUE;
}

static void
AppendErrorTextMismatch(const nsString &host,
                        nsIX509Cert* ix509,
                        nsINSSComponent *component,
                        nsString &returnedMessage)
{
  const PRUnichar *params[1];
  nsresult rv;

  CERTCertificate *nssCert = NULL;
  CERTCertificateCleaner nssCertCleaner(nssCert);

  nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
  if (cert2)
    nssCert = cert2->GetCert();

  if (!nssCert) {
    // We are unable to extract the valid names, say "not valid for name".
    params[0] = host.get();
    nsString formattedString;
    rv = component->PIPBundleFormatStringFromName("certErrorMismatch", 
                                                  params, 1, 
                                                  formattedString);
    if (NS_SUCCEEDED(rv)) {
      returnedMessage.Append(formattedString);
      returnedMessage.Append(NS_LITERAL_STRING("\n"));
    }
    return;
  }

  nsString allNames;
  PRBool multipleNames = PR_FALSE;
  PRBool useSAN = PR_FALSE;

  if (nssCert)
    useSAN = GetSubjectAltNames(nssCert, component, allNames, multipleNames);

  if (!useSAN) {
    char *certName = nsnull;
    // currently CERT_FindNSStringExtension is not being exported by NSS.
    // If it gets exported, enable the following line.
    //   certName = CERT_FindNSStringExtension(nssCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
      if (!certName) {
    // However, it has been discussed to treat the extension as obsolete and ignore it.
    if (!certName)
      certName = CERT_GetCommonName(&nssCert->subject);
      }
    if (certName) {
      allNames.AssignASCII(certName);
      PORT_Free(certName);
    }
  }

  if (multipleNames) {
    nsString message;
@@ -848,6 +845,7 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
    }
  }
  else { // !multipleNames
    const PRUnichar *params[1];
    params[0] = allNames.get();

    nsString formattedString;
@@ -861,45 +859,63 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
  }
}

  if (multipleCollectedErrors & nsICertOverrideService::ERROR_TIME)
static void
GetDateBoundary(nsIX509Cert* ix509,
                nsString &formattedDate,
                PRBool trueExpired_falseNotYetValid)
{
    PRTime now = PR_Now();
  trueExpired_falseNotYetValid = PR_TRUE;
  formattedDate.Truncate();

  PRTime notAfter, notBefore, timeToUse;
  nsCOMPtr<nsIX509CertValidity> validity;
    const char *key;
  nsresult rv;

  rv = ix509->GetValidity(getter_AddRefs(validity));
  if (NS_FAILED(rv))
      return rv;
    return;

  rv = validity->GetNotAfter(&notAfter);
  if (NS_FAILED(rv))
      return rv;
    return;

  rv = validity->GetNotBefore(&notBefore);
  if (NS_FAILED(rv))
      return rv;
    return;

    if (LL_CMP(now, >, notAfter)) {
      key       = "certErrorExpired"; 
  if (LL_CMP(PR_Now(), >, notAfter)) {
    timeToUse = notAfter;
  } else {
      key       = "certErrorNotYetValid";
    timeToUse = notBefore;
    trueExpired_falseNotYetValid = PR_FALSE;
  }

    nsAutoString formattedDate;
  nsIDateTimeFormat* aDateTimeFormat;
  rv = CallCreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &aDateTimeFormat);
  if (NS_FAILED(rv))
      return rv;
    return;

  aDateTimeFormat->FormatPRTime(nsnull, kDateFormatShort, 
                                kTimeFormatNoSeconds, timeToUse, 
                                formattedDate);
  NS_IF_RELEASE(aDateTimeFormat);
    params[0] = formattedDate.get(); 
}

static void
AppendErrorTextTime(nsIX509Cert* ix509,
                    nsINSSComponent *component,
                    nsString &returnedMessage)
{
  nsAutoString formattedDate;
  PRBool trueExpired_falseNotYetValid;
  GetDateBoundary(ix509, formattedDate, trueExpired_falseNotYetValid);

  const PRUnichar *params[1];
  params[0] = formattedDate.get(); // might be empty, if helper function had a problem 

  const char *key = trueExpired_falseNotYetValid ? 
                    "certErrorExpired" : "certErrorNotYetValid";
  nsresult rv;
  nsString formattedString;
  rv = component->PIPBundleFormatStringFromName(key, params, 
                                                1, formattedString);
@@ -910,6 +926,11 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
  }
}

static void
AppendErrorTextCode(PRErrorCode errorCodeToReport,
                    nsINSSComponent *component,
                    nsString &returnedMessage)
{
  const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
  if (codeName)
  {
@@ -917,9 +938,11 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
    ToLowerCase(error_id);
    NS_ConvertASCIItoUTF16 idU(error_id);

    const PRUnichar *params[1];
    params[0] = idU.get();

    nsString formattedString;
    nsresult rv;
    rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix", 
                                                  params, 1, 
                                                  formattedString);
@@ -934,6 +957,66 @@ getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors,
      returnedMessage.Append(NS_LITERAL_STRING(")"));
    }
  }
}

static nsresult
getInvalidCertErrorMessage(PRUint32 multipleCollectedErrors, 
                           PRErrorCode errorCodeToReport, 
                           PRErrorCode errTrust, 
                           PRErrorCode errMismatch, 
                           PRErrorCode errExpired,
                           const nsString &host,
                           const nsString &hostWithPort,
                           PRInt32 port,
                           nsIX509Cert* ix509,
                           PRBool externalErrorReporting,
                           nsINSSComponent *component,
                           nsString &returnedMessage)
{
  NS_ENSURE_ARG_POINTER(component);

  const PRUnichar *params[1];
  nsresult rv;

  // For now, hide port when it's 443 and we're reporting the error using
  // external reporting. In the future a better mechanism should be used
  // to make a decision about showing the port number, possibly by requiring
  // the context object to implement a specific interface.
  // The motivation is that Mozilla browser would like to hide the port number
  // in error pages in the common case.
  
  if (externalErrorReporting && port == 443)
    params[0] = host.get();
  else
    params[0] = hostWithPort.get();

  nsString formattedString;
  rv = component->PIPBundleFormatStringFromName("certErrorIntro", 
                                                params, 1, 
                                                formattedString);
  if (NS_SUCCEEDED(rv))
  {
    returnedMessage.Append(formattedString);
    returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
  }

  if (multipleCollectedErrors & nsICertOverrideService::ERROR_UNTRUSTED)
  {
    AppendErrorTextUntrusted(errTrust, host, ix509, 
                             component, returnedMessage);
  }

  if (multipleCollectedErrors & nsICertOverrideService::ERROR_MISMATCH)
  {
    AppendErrorTextMismatch(host, ix509, component, returnedMessage);
  }

  if (multipleCollectedErrors & nsICertOverrideService::ERROR_TIME)
  {
    AppendErrorTextTime(ix509, component, returnedMessage);
  }

  AppendErrorTextCode(errorCodeToReport, component, returnedMessage);

  return NS_OK;
}