Bug 1040446 - mozilla::pkix: add error code for CA cert used as end-entity cert. r=briansmith, a=lmandel
authorDavid Keeler <dkeeler@mozilla.com>
Mon, 11 Aug 2014 12:35:45 -0700
changeset 216752 93cd4a068e9d
parent 216751 1f599d357743
child 216753 a6856f90ce36
push id3900
push userryanvm@gmail.com
push date2014-09-15 22:39 +0000
treeherdermozilla-beta@a6856f90ce36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbriansmith, lmandel
bugs1040446
milestone33.0
Bug 1040446 - mozilla::pkix: add error code for CA cert used as end-entity cert. r=briansmith, a=lmandel
security/manager/ssl/src/nsUsageArrayHelper.cpp
security/pkix/include/pkix/Result.h
security/pkix/include/pkix/pkixnss.h
security/pkix/lib/pkixcheck.cpp
security/pkix/lib/pkixnss.cpp
--- a/security/manager/ssl/src/nsUsageArrayHelper.cpp
+++ b/security/manager/ssl/src/nsUsageArrayHelper.cpp
@@ -1,24 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsUsageArrayHelper.h"
 
 #include "mozilla/Assertions.h"
 #include "nsCOMPtr.h"
-#include "nsIDateTimeFormat.h"
+#include "nsComponentManagerUtils.h"
 #include "nsDateTimeFormatCID.h"
-#include "nsComponentManagerUtils.h"
+#include "nsIDateTimeFormat.h"
+#include "nsNSSCertificate.h"
 #include "nsReadableUtils.h"
-#include "nsNSSCertificate.h"
 #include "nsServiceManagerUtils.h"
-
 #include "nspr.h"
+#include "pkix/pkixnss.h"
 #include "secerr.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gPIPNSSLog;
 #endif
@@ -144,16 +144,17 @@ nsUsageArrayHelper::check(uint32_t previ
 void
 nsUsageArrayHelper::verifyFailed(uint32_t *_verified, int err)
 {
   switch (err) {
   /* For these cases, verify only failed for the particular usage */
   case SEC_ERROR_INADEQUATE_KEY_USAGE:
   case SEC_ERROR_INADEQUATE_CERT_TYPE:
   case SEC_ERROR_CA_CERT_INVALID:
+  case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY:
     *_verified = nsNSSCertificate::USAGE_NOT_ALLOWED; break;
   /* These are the cases that have individual error messages */
   case SEC_ERROR_REVOKED_CERTIFICATE:
     *_verified = nsNSSCertificate::CERT_REVOKED; break;
   case SEC_ERROR_EXPIRED_CERTIFICATE:
     *_verified = nsNSSCertificate::CERT_EXPIRED; break;
   case SEC_ERROR_UNTRUSTED_CERT:
     *_verified = nsNSSCertificate::CERT_NOT_TRUSTED; break;
--- a/security/pkix/include/pkix/Result.h
+++ b/security/pkix/include/pkix/Result.h
@@ -70,16 +70,17 @@ MOZILLA_PKIX_ENUM_CLASS Result
   ERROR_OCSP_UNKNOWN_RESPONSE_STATUS = 32,
   ERROR_OCSP_UNKNOWN_CERT = 33,
   ERROR_OCSP_FUTURE_RESPONSE = 34,
 
   ERROR_UNKNOWN_ERROR = 35,
 
   ERROR_INVALID_KEY = 36,
   ERROR_UNSUPPORTED_KEYALG = 37,
+  ERROR_CA_CERT_USED_AS_END_ENTITY = 39,
 
   // Keep this in sync with MAP_LIST in pkixnss.cpp
 
   FATAL_ERROR_INVALID_ARGS = FATAL_ERROR_FLAG | 1,
   FATAL_ERROR_INVALID_STATE = FATAL_ERROR_FLAG | 2,
   FATAL_ERROR_LIBRARY_FAILURE = FATAL_ERROR_FLAG | 3,
   FATAL_ERROR_NO_MEMORY = FATAL_ERROR_FLAG | 4,
 
--- a/security/pkix/include/pkix/pkixnss.h
+++ b/security/pkix/include/pkix/pkixnss.h
@@ -66,16 +66,17 @@ const char* MapResultToName(Result resul
 // involves negating the value of the error and then synthesizing an error
 // in the NS_ERROR_MODULE_SECURITY module. Hence, PSM errors will start at
 // a negative value that both doesn't overlap with the current value
 // ranges for NSS errors and that will fit in 16 bits when negated.
 static const PRErrorCode ERROR_BASE = -0x4000;
 static const PRErrorCode ERROR_LIMIT = ERROR_BASE + 1000;
 
 enum ErrorCode {
-  MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0
+  MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0,
+  MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY = ERROR_BASE + 1
 };
 
 void RegisterErrorTable();
 
 } } // namespace mozilla::pkix
 
 #endif // mozilla_pkix__pkixnss_h
--- a/security/pkix/lib/pkixcheck.cpp
+++ b/security/pkix/lib/pkixcheck.cpp
@@ -361,27 +361,20 @@ CheckBasicConstraints(EndEntityOrCA endE
       isCA = true;
     }
   }
 
   if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
     // CA certificates are not trusted as EE certs.
 
     if (isCA) {
-      // TODO(bug 1040446): We use Result::ERROR_CA_CERT_INVALID here so we can
-      // distinguish this error from other errors, given that NSS does not have
-      // a "CA cert used as end-entity" error code since it doesn't have such a
-      // prohibition. We should add such an error code and stop abusing
-      // Result::ERROR_CA_CERT_INVALID this way.
-      //
-      // Note, in particular, that this check prevents a delegated OCSP
-      // response signing certificate with the CA bit from successfully
-      // validating when we check it from pkixocsp.cpp, which is a good thing.
-      //
-      return Result::ERROR_CA_CERT_INVALID;
+      // Note that this check prevents a delegated OCSP response signing
+      // certificate with the CA bit from successfully validating when we check
+      // it from pkixocsp.cpp, which is a good thing.
+      return Result::ERROR_CA_CERT_USED_AS_END_ENTITY;
     }
 
     return Success;
   }
 
   PORT_Assert(endEntityOrCA == EndEntityOrCA::MustBeCA);
 
   // End-entity certificates are not allowed to act as CA certs.
--- a/security/pkix/lib/pkixnss.cpp
+++ b/security/pkix/lib/pkixnss.cpp
@@ -225,16 +225,17 @@ DigestBuf(const SECItem& item, /*out*/ u
     MAP(Result::ERROR_OCSP_SERVER_ERROR, SEC_ERROR_OCSP_SERVER_ERROR) \
     MAP(Result::ERROR_OCSP_TRY_SERVER_LATER, SEC_ERROR_OCSP_TRY_SERVER_LATER) \
     MAP(Result::ERROR_OCSP_UNAUTHORIZED_REQUEST, SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST) \
     MAP(Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS) \
     MAP(Result::ERROR_OCSP_UNKNOWN_CERT, SEC_ERROR_OCSP_UNKNOWN_CERT) \
     MAP(Result::ERROR_OCSP_FUTURE_RESPONSE, SEC_ERROR_OCSP_FUTURE_RESPONSE) \
     MAP(Result::ERROR_INVALID_KEY, SEC_ERROR_INVALID_KEY) \
     MAP(Result::ERROR_UNSUPPORTED_KEYALG, SEC_ERROR_UNSUPPORTED_KEYALG) \
+    MAP(Result::ERROR_CA_CERT_USED_AS_END_ENTITY, MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY) \
     MAP(Result::FATAL_ERROR_INVALID_ARGS, SEC_ERROR_INVALID_ARGS) \
     MAP(Result::FATAL_ERROR_INVALID_STATE, PR_INVALID_STATE_ERROR) \
     MAP(Result::FATAL_ERROR_LIBRARY_FAILURE, SEC_ERROR_LIBRARY_FAILURE) \
     MAP(Result::FATAL_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY) \
     /* nothing here */
 
 Result
 MapPRErrorCodeToResult(PRErrorCode error)
@@ -291,17 +292,21 @@ MapResultToName(Result result)
 
 void
 RegisterErrorTable()
 {
   static const struct PRErrorMessage ErrorTableText[] = {
     { "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." }
+      "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." }
   };
 
   static const struct PRErrorTable ErrorTable = {
     ErrorTableText,
     "pkixerrors",
     ERROR_BASE,
     PR_ARRAY_SIZE(ErrorTableText)
   };