security/manager/ssl/src/nsUsageArrayHelper.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "nsUsageArrayHelper.h"
     7 #include "mozilla/Assertions.h"
     8 #include "nsCOMPtr.h"
     9 #include "nsIDateTimeFormat.h"
    10 #include "nsDateTimeFormatCID.h"
    11 #include "nsComponentManagerUtils.h"
    12 #include "nsReadableUtils.h"
    13 #include "nsNSSCertificate.h"
    14 #include "nsServiceManagerUtils.h"
    16 #include "nspr.h"
    17 #include "secerr.h"
    19 using namespace mozilla;
    20 using namespace mozilla::psm;
    22 #ifdef PR_LOGGING
    23 extern PRLogModuleInfo* gPIPNSSLog;
    24 #endif
    26 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); // XXX? needed?::
    28 nsUsageArrayHelper::nsUsageArrayHelper(CERTCertificate *aCert)
    29 :mCert(aCert)
    30 {
    31   nsNSSShutDownPreventionLock locker;
    32   defaultcertdb = CERT_GetDefaultCertDB();
    33   nssComponent = do_GetService(kNSSComponentCID, &m_rv);
    34 }
    36 namespace {
    38 // Some validation errors are non-fatal in that, we should keep checking the
    39 // cert for other usages after receiving them; i.e. they are errors that NSS
    40 // returns when a certificate isn't valid for a particular usage, but which
    41 // don't indicate that the certificate is invalid for ANY usage. Others errors
    42 // (e.g. revocation) are fatal, and we should immediately stop validation of
    43 // the cert when we encounter them.
    44 bool
    45 isFatalError(uint32_t checkResult)
    46 {
    47   return checkResult != nsIX509Cert::VERIFIED_OK &&
    48          checkResult != nsIX509Cert::USAGE_NOT_ALLOWED &&
    49          checkResult != nsIX509Cert::ISSUER_NOT_TRUSTED &&
    50          checkResult != nsIX509Cert::ISSUER_UNKNOWN;
    51 }
    53 } // unnamed namespace
    55 // Validates the certificate for the given usage. If the certificate is valid
    56 // for the given usage, aCounter is incremented, a string description of the
    57 // usage is appended to outUsages, and nsNSSCertificate::VERIFIED_OK is
    58 // returned. Otherwise, if validation failed, one of the other "Constants for
    59 // certificate verification results" in nsIX509Cert is returned.
    60 uint32_t
    61 nsUsageArrayHelper::check(uint32_t previousCheckResult,
    62                           const char *suffix,
    63                           CertVerifier * certVerifier,
    64                           SECCertificateUsage aCertUsage,
    65                           PRTime time,
    66                           CertVerifier::Flags flags,
    67                           uint32_t &aCounter,
    68                           char16_t **outUsages)
    69 {
    70   if (!aCertUsage) {
    71     MOZ_CRASH("caller should have supplied non-zero aCertUsage");
    72   }
    74   if (isFatalError(previousCheckResult)) {
    75       return previousCheckResult;
    76   }
    78   nsAutoCString typestr;
    79   switch (aCertUsage) {
    80   case certificateUsageSSLClient:
    81     typestr = "VerifySSLClient";
    82     break;
    83   case certificateUsageSSLServer:
    84     typestr = "VerifySSLServer";
    85     break;
    86   case certificateUsageEmailSigner:
    87     typestr = "VerifyEmailSigner";
    88     break;
    89   case certificateUsageEmailRecipient:
    90     typestr = "VerifyEmailRecip";
    91     break;
    92   case certificateUsageObjectSigner:
    93     typestr = "VerifyObjSign";
    94     break;
    95   case certificateUsageSSLCA:
    96     typestr = "VerifySSLCA";
    97     break;
    98   case certificateUsageVerifyCA:
    99     typestr = "VerifyCAVerifier";
   100     break;
   101   case certificateUsageStatusResponder:
   102     typestr = "VerifyStatusResponder";
   103     break;
   104   default:
   105     MOZ_CRASH("unknown cert usage passed to check()");
   106   }
   108   SECStatus rv = certVerifier->VerifyCert(mCert, aCertUsage, time,
   109                                           nullptr /*XXX:wincx*/,
   110                                           nullptr /*hostname*/, flags);
   112   if (rv == SECSuccess) {
   113     typestr.Append(suffix);
   114     nsAutoString verifyDesc;
   115     m_rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
   116     if (NS_SUCCEEDED(m_rv)) {
   117       outUsages[aCounter++] = ToNewUnicode(verifyDesc);
   118     }
   119     return nsIX509Cert::VERIFIED_OK;
   120   }
   122   PRErrorCode error = PR_GetError();
   124   uint32_t result = nsIX509Cert::NOT_VERIFIED_UNKNOWN;
   125   verifyFailed(&result, error);
   127   // USAGE_NOT_ALLOWED is the weakest non-fatal error; let all other errors
   128   // override it.
   129   if (result == nsIX509Cert::USAGE_NOT_ALLOWED &&
   130       previousCheckResult != nsIX509Cert::VERIFIED_OK) {
   131       result = previousCheckResult;
   132   }
   134   PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   135           ("error validating certificate for usage %s: %s (%d) -> %ud \n",
   136           typestr.get(), PR_ErrorToName(error), (int) error, (int) result));
   138   return result;
   139 }
   142 // Maps the error code to one of the Constants for certificate verification
   143 // results" in nsIX509Cert.
   144 void
   145 nsUsageArrayHelper::verifyFailed(uint32_t *_verified, int err)
   146 {
   147   switch (err) {
   148   /* For these cases, verify only failed for the particular usage */
   149   case SEC_ERROR_INADEQUATE_KEY_USAGE:
   150   case SEC_ERROR_INADEQUATE_CERT_TYPE:
   151   case SEC_ERROR_CA_CERT_INVALID:
   152     *_verified = nsNSSCertificate::USAGE_NOT_ALLOWED; break;
   153   /* These are the cases that have individual error messages */
   154   case SEC_ERROR_REVOKED_CERTIFICATE:
   155     *_verified = nsNSSCertificate::CERT_REVOKED; break;
   156   case SEC_ERROR_EXPIRED_CERTIFICATE:
   157     *_verified = nsNSSCertificate::CERT_EXPIRED; break;
   158   case SEC_ERROR_UNTRUSTED_CERT:
   159     *_verified = nsNSSCertificate::CERT_NOT_TRUSTED; break;
   160   case SEC_ERROR_UNTRUSTED_ISSUER:
   161     *_verified = nsNSSCertificate::ISSUER_NOT_TRUSTED; break;
   162   case SEC_ERROR_UNKNOWN_ISSUER:
   163     *_verified = nsNSSCertificate::ISSUER_UNKNOWN; break;
   164   case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
   165     // XXX are there other error for this?
   166     *_verified = nsNSSCertificate::INVALID_CA; break;
   167   case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   168     *_verified = nsNSSCertificate::SIGNATURE_ALGORITHM_DISABLED; break;
   169   default:
   170     *_verified = nsNSSCertificate::NOT_VERIFIED_UNKNOWN; break;
   171   }
   172 }
   174 nsresult
   175 nsUsageArrayHelper::GetUsagesArray(const char *suffix,
   176                       bool localOnly,
   177                       uint32_t outArraySize,
   178                       uint32_t *_verified,
   179                       uint32_t *_count,
   180                       char16_t **outUsages)
   181 {
   182   nsNSSShutDownPreventionLock locker;
   183   if (NS_FAILED(m_rv))
   184     return m_rv;
   186   NS_ENSURE_TRUE(nssComponent, NS_ERROR_NOT_AVAILABLE);
   188   if (outArraySize < max_returned_out_array_size)
   189     return NS_ERROR_FAILURE;
   191   RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
   192   NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
   194   uint32_t &count = *_count;
   195   count = 0;
   197   PRTime now = PR_Now();
   198   CertVerifier::Flags flags = localOnly ? CertVerifier::FLAG_LOCAL_ONLY : 0;
   200   // The following list of checks must be < max_returned_out_array_size
   202   uint32_t result;
   203   result = check(nsIX509Cert::VERIFIED_OK, suffix, certVerifier,
   204                  certificateUsageSSLClient, now, flags, count, outUsages);
   205   result = check(result, suffix, certVerifier,
   206                  certificateUsageSSLServer, now, flags, count, outUsages);
   207   result = check(result, suffix, certVerifier,
   208                  certificateUsageEmailSigner, now, flags, count, outUsages);
   209   result = check(result, suffix, certVerifier,
   210                  certificateUsageEmailRecipient, now, flags, count, outUsages);
   211   result = check(result, suffix, certVerifier,
   212                  certificateUsageObjectSigner, now, flags, count, outUsages);
   213   result = check(result, suffix, certVerifier,
   214                  certificateUsageSSLCA, now, flags, count, outUsages);
   215   result = check(result, suffix, certVerifier,
   216                  certificateUsageStatusResponder, now, flags, count, outUsages);
   218   if (isFatalError(result) || count == 0) {
   219     MOZ_ASSERT(result != nsIX509Cert::VERIFIED_OK);
   221     // Clear the output usage strings in the case where we encountered a fatal
   222     // error after we already successfully validated the cert for some usages.
   223     for (uint32_t i = 0; i < count; ++i) {
   224       delete outUsages[i];
   225       outUsages[i] = nullptr;
   226     }
   227     count = 0;
   228     *_verified = result;
   229   } else {
   230     *_verified = nsNSSCertificate::VERIFIED_OK;
   231   }
   232   return NS_OK;
   233 }

mercurial