Bug 968560 - Return distinct error codes for certificates that are not valid yet, in mozilla::pkix. r=keeler
authorCykesiopka <cykesiopka.bmo@gmail.com>
Fri, 06 Feb 2015 11:18:20 -0800
changeset 245426 ed767baad4bc983a485cebbca9e65defe0b717dc
parent 245425 e7468e7abe805091b4eca74287ee3bb0e39ca6e5
child 245427 0c23f8c034d11587b1d733372af547205f4cefc5
push id7677
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 18:11:24 +0000
treeherdermozilla-aurora@f531d838c055 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskeeler
bugs968560
milestone38.0a1
Bug 968560 - Return distinct error codes for certificates that are not valid yet, in mozilla::pkix. r=keeler
security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
security/manager/ssl/src/NSSErrorsService.cpp
security/manager/ssl/src/SSLServerCertVerification.cpp
security/pkix/include/pkix/Result.h
security/pkix/include/pkix/pkixnss.h
security/pkix/lib/pkixbuild.cpp
security/pkix/lib/pkixcheck.cpp
security/pkix/lib/pkixnss.cpp
security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp
--- a/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
+++ b/security/manager/locales/en-US/chrome/pipnss/nsserrors.properties
@@ -310,8 +310,10 @@ SEC_ERROR_EXPIRED_PASSWORD=The password 
 SEC_ERROR_LOCKED_PASSWORD=The password is locked.
 SEC_ERROR_UNKNOWN_PKCS11_ERROR=Unknown PKCS #11 error.
 SEC_ERROR_BAD_CRL_DP_URL=Invalid or unsupported URL in CRL distribution point name.
 SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED=The certificate was signed using a signature algorithm that is disabled because it is not secure.
 MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE=The server uses key pinning (HPKP) but no trusted certificate chain could be constructed that matches the pinset. Key pinning violations cannot be overridden.
 MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY=The server uses a certificate with a basic constraints extension identifying it as a certificate authority. For a properly-issued certificate, this should not be the case.
 MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE=The server presented a certificate with a key size that is too small to establish a secure connection.
 MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA=An X.509 version 1 certificate that is not a trust anchor was used to issue the server's certificate. X.509 version 1 certificates are deprecated and should not be used to sign other certificates.
+MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE=The server presented a certificate that is not yet valid.
+MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE=A certificate that is not yet valid was used to issue the server's certificate.
--- a/security/manager/ssl/src/NSSErrorsService.cpp
+++ b/security/manager/ssl/src/NSSErrorsService.cpp
@@ -139,16 +139,18 @@ NSSErrorsService::GetErrorClass(nsresult
     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
     case SEC_ERROR_UNTRUSTED_CERT:
     case SSL_ERROR_BAD_CERT_DOMAIN:
     case SEC_ERROR_EXPIRED_CERTIFICATE:
     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
       *aErrorClass = ERROR_CLASS_BAD_CERT;
       break;
     // Non-overridable errors.
     default:
       *aErrorClass = ERROR_CLASS_SSL_PROTOCOL;
       break;
   }
   return NS_OK;
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -305,16 +305,19 @@ MapCertErrorToProbeValue(PRErrorCode err
     case SEC_ERROR_UNTRUSTED_CERT:                     return  6;
     case SEC_ERROR_INADEQUATE_KEY_USAGE:               return  7;
     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:  return  8;
     case SSL_ERROR_BAD_CERT_DOMAIN:                    return  9;
     case SEC_ERROR_EXPIRED_CERTIFICATE:                return 10;
     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: return 11;
     case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA: return 12;
     case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE: return 13;
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE: return 14;
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
+      return 15;
   }
   NS_WARNING("Unknown certificate error code. Does MapCertErrorToProbeValue "
              "handle everything in DetermineCertOverrideErrors?");
   return 0;
 }
 
 SECStatus
 DetermineCertOverrideErrors(CERTCertificate* cert, const char* hostName,
@@ -336,35 +339,41 @@ DetermineCertOverrideErrors(CERTCertific
   // called if CertVerifier::VerifyCert succeeded.
   switch (defaultErrorCodeToReport) {
     case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
     case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
     case SEC_ERROR_UNKNOWN_ISSUER:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE:
     case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA:
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE:
     {
       collectedErrors = nsICertOverrideService::ERROR_UNTRUSTED;
       errorCodeTrust = defaultErrorCodeToReport;
 
       SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, now, false);
       if (validity == secCertTimeUndetermined) {
         PR_SetError(defaultErrorCodeToReport, 0);
         return SECFailure;
       }
-      if (validity != secCertTimeValid) {
+      if (validity == secCertTimeExpired) {
         collectedErrors |= nsICertOverrideService::ERROR_TIME;
         errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
+      } else if (validity == secCertTimeNotValidYet) {
+        collectedErrors |= nsICertOverrideService::ERROR_TIME;
+        errorCodeExpired =
+          mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE;
       }
       break;
     }
 
     case SEC_ERROR_EXPIRED_CERTIFICATE:
+    case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE:
       collectedErrors = nsICertOverrideService::ERROR_TIME;
-      errorCodeExpired = SEC_ERROR_EXPIRED_CERTIFICATE;
+      errorCodeExpired = defaultErrorCodeToReport;
       break;
 
     case SSL_ERROR_BAD_CERT_DOMAIN:
       collectedErrors = nsICertOverrideService::ERROR_MISMATCH;
       errorCodeMismatch = SSL_ERROR_BAD_CERT_DOMAIN;
       break;
 
     case 0:
--- a/security/pkix/include/pkix/Result.h
+++ b/security/pkix/include/pkix/Result.h
@@ -168,16 +168,20 @@ static const unsigned int FATAL_ERROR_FL
     MOZILLA_PKIX_MAP(ERROR_V1_CERT_USED_AS_CA, 41, \
                      MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA) \
     MOZILLA_PKIX_MAP(ERROR_BAD_CERT_DOMAIN, 42, \
                      SSL_ERROR_BAD_CERT_DOMAIN) \
     MOZILLA_PKIX_MAP(ERROR_NO_RFC822NAME_MATCH, 43, \
                      MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH) \
     MOZILLA_PKIX_MAP(ERROR_UNSUPPORTED_ELLIPTIC_CURVE, 44, \
                      SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE) \
+    MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_CERTIFICATE, 45, \
+                     MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE) \
+    MOZILLA_PKIX_MAP(ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE, 46, \
+                     MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE) \
     MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_ARGS, FATAL_ERROR_FLAG | 1, \
                      SEC_ERROR_INVALID_ARGS) \
     MOZILLA_PKIX_MAP(FATAL_ERROR_INVALID_STATE, FATAL_ERROR_FLAG | 2, \
                      PR_INVALID_STATE_ERROR) \
     MOZILLA_PKIX_MAP(FATAL_ERROR_LIBRARY_FAILURE, FATAL_ERROR_FLAG | 3, \
                      SEC_ERROR_LIBRARY_FAILURE) \
     MOZILLA_PKIX_MAP(FATAL_ERROR_NO_MEMORY, FATAL_ERROR_FLAG | 4, \
                      SEC_ERROR_NO_MEMORY) \
--- a/security/pkix/include/pkix/pkixnss.h
+++ b/security/pkix/include/pkix/pkixnss.h
@@ -72,16 +72,18 @@ static const PRErrorCode ERROR_LIMIT = E
 
 enum ErrorCode
 {
   MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0,
   MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = ERROR_BASE + 1,
   MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE = ERROR_BASE + 2,
   MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA = ERROR_BASE + 3,
   MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH = ERROR_BASE + 4,
+  MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE = ERROR_BASE + 5,
+  MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE = ERROR_BASE + 6,
 };
 
 void RegisterErrorTable();
 
 inline SECItem UnsafeMapInputToSECItem(Input input)
 {
   SECItem result = {
     siBuffer,
--- a/security/pkix/lib/pkixbuild.cpp
+++ b/security/pkix/lib/pkixbuild.cpp
@@ -90,16 +90,18 @@ private:
 
 Result
 PathBuildingStep::RecordResult(Result newResult, /*out*/ bool& keepGoing)
 {
   if (newResult == Result::ERROR_UNTRUSTED_CERT) {
     newResult = Result::ERROR_UNTRUSTED_ISSUER;
   } else if (newResult == Result::ERROR_EXPIRED_CERTIFICATE) {
     newResult = Result::ERROR_EXPIRED_ISSUER_CERTIFICATE;
+  } else if (newResult == Result::ERROR_NOT_YET_VALID_CERTIFICATE) {
+    newResult = Result::ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE;
   }
 
   if (resultWasSet) {
     if (result == Success) {
       return NotReached("RecordResult called after finding a chain",
                         Result::FATAL_ERROR_INVALID_STATE);
     }
     // If every potential issuer has the same problem (e.g. expired) and/or if
--- a/security/pkix/lib/pkixcheck.cpp
+++ b/security/pkix/lib/pkixcheck.cpp
@@ -33,17 +33,17 @@ Result
 CheckValidity(Input encodedValidity, Time time)
 {
   Reader validity(encodedValidity);
   Time notBefore(Time::uninitialized);
   if (der::TimeChoice(validity, notBefore) != Success) {
     return Result::ERROR_EXPIRED_CERTIFICATE;
   }
   if (time < notBefore) {
-    return Result::ERROR_EXPIRED_CERTIFICATE;
+    return Result::ERROR_NOT_YET_VALID_CERTIFICATE;
   }
 
   Time notAfter(Time::uninitialized);
   if (der::TimeChoice(validity, notAfter) != Success) {
     return Result::ERROR_EXPIRED_CERTIFICATE;
   }
   if (time > notAfter) {
     return Result::ERROR_EXPIRED_CERTIFICATE;
--- a/security/pkix/lib/pkixnss.cpp
+++ b/security/pkix/lib/pkixnss.cpp
@@ -268,16 +268,21 @@ RegisterErrorTable()
       "The server presented a certificate with a key size that is too small "
       "to establish a secure connection." },
     { "MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA",
       "An X.509 version 1 certificate that is not a trust anchor was used to "
       "issue the server's certificate. X.509 version 1 certificates are "
       "deprecated and should not be used to sign other certificates." },
     { "MOZILLA_PKIX_ERROR_NO_RFC822NAME_MATCH",
       "The certificate is not valid for the given email address." },
+    { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE",
+      "The server presented a certificate that is not yet valid." },
+    { "MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE",
+      "A certificate that is not yet valid was used to issue the server's "
+      "certificate." },
   };
   // Note that these error strings are not localizable.
   // When these strings change, update the localization information too.
 
   static const PRErrorTable ErrorTable = {
     ErrorTableText,
     "pkixerrors",
     ERROR_BASE,
--- a/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp
+++ b/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp
@@ -85,17 +85,18 @@ TEST_F(pkixcheck_CheckValidity, NotBefor
 
 TEST_F(pkixcheck_CheckValidity, NotAfterEmptyNull)
 {
   static const uint8_t DER[] = {
     NEWER_UTCTIME,
     0x17/*UTCTime*/, 0x00/*length*/,
   };
   static const Input validity(DER);
-  ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
+  ASSERT_EQ(Result::ERROR_NOT_YET_VALID_CERTIFICATE,
+            CheckValidity(validity, NOW));
 }
 
 static const uint8_t OLDER_UTCTIME_NEWER_UTCTIME_DATA[] = {
   OLDER_UTCTIME,
   NEWER_UTCTIME,
 };
 static const Input
 OLDER_UTCTIME_NEWER_UTCTIME(OLDER_UTCTIME_NEWER_UTCTIME_DATA);
@@ -132,27 +133,28 @@ TEST_F(pkixcheck_CheckValidity, Valid_UT
     NEWER_GENERALIZEDTIME,
   };
   static const Input validity(DER);
   ASSERT_EQ(Success, CheckValidity(validity, NOW));
 }
 
 TEST_F(pkixcheck_CheckValidity, InvalidBeforeNotBefore)
 {
-  ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE,
+  ASSERT_EQ(Result::ERROR_NOT_YET_VALID_CERTIFICATE,
             CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME, PAST_TIME));
 }
 
 TEST_F(pkixcheck_CheckValidity, InvalidAfterNotAfter)
 {
   ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE,
             CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME, FUTURE_TIME));
 }
 
 TEST_F(pkixcheck_CheckValidity, InvalidNotAfterBeforeNotBefore)
 {
   static const uint8_t DER[] = {
     NEWER_UTCTIME,
     OLDER_UTCTIME,
   };
   static const Input validity(DER);
-  ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
+  ASSERT_EQ(Result::ERROR_NOT_YET_VALID_CERTIFICATE,
+            CheckValidity(validity, NOW));
 }