security/manager/ssl/src/nsUsageArrayHelper.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/manager/ssl/src/nsUsageArrayHelper.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,233 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include "nsUsageArrayHelper.h"
     1.9 +
    1.10 +#include "mozilla/Assertions.h"
    1.11 +#include "nsCOMPtr.h"
    1.12 +#include "nsIDateTimeFormat.h"
    1.13 +#include "nsDateTimeFormatCID.h"
    1.14 +#include "nsComponentManagerUtils.h"
    1.15 +#include "nsReadableUtils.h"
    1.16 +#include "nsNSSCertificate.h"
    1.17 +#include "nsServiceManagerUtils.h"
    1.18 +
    1.19 +#include "nspr.h"
    1.20 +#include "secerr.h"
    1.21 +
    1.22 +using namespace mozilla;
    1.23 +using namespace mozilla::psm;
    1.24 +
    1.25 +#ifdef PR_LOGGING
    1.26 +extern PRLogModuleInfo* gPIPNSSLog;
    1.27 +#endif
    1.28 +
    1.29 +static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); // XXX? needed?::
    1.30 +
    1.31 +nsUsageArrayHelper::nsUsageArrayHelper(CERTCertificate *aCert)
    1.32 +:mCert(aCert)
    1.33 +{
    1.34 +  nsNSSShutDownPreventionLock locker;
    1.35 +  defaultcertdb = CERT_GetDefaultCertDB();
    1.36 +  nssComponent = do_GetService(kNSSComponentCID, &m_rv);
    1.37 +}
    1.38 +
    1.39 +namespace {
    1.40 +
    1.41 +// Some validation errors are non-fatal in that, we should keep checking the
    1.42 +// cert for other usages after receiving them; i.e. they are errors that NSS
    1.43 +// returns when a certificate isn't valid for a particular usage, but which
    1.44 +// don't indicate that the certificate is invalid for ANY usage. Others errors
    1.45 +// (e.g. revocation) are fatal, and we should immediately stop validation of
    1.46 +// the cert when we encounter them.
    1.47 +bool
    1.48 +isFatalError(uint32_t checkResult)
    1.49 +{
    1.50 +  return checkResult != nsIX509Cert::VERIFIED_OK &&
    1.51 +         checkResult != nsIX509Cert::USAGE_NOT_ALLOWED &&
    1.52 +         checkResult != nsIX509Cert::ISSUER_NOT_TRUSTED &&
    1.53 +         checkResult != nsIX509Cert::ISSUER_UNKNOWN;
    1.54 +}
    1.55 +
    1.56 +} // unnamed namespace
    1.57 +
    1.58 +// Validates the certificate for the given usage. If the certificate is valid
    1.59 +// for the given usage, aCounter is incremented, a string description of the
    1.60 +// usage is appended to outUsages, and nsNSSCertificate::VERIFIED_OK is
    1.61 +// returned. Otherwise, if validation failed, one of the other "Constants for
    1.62 +// certificate verification results" in nsIX509Cert is returned.
    1.63 +uint32_t
    1.64 +nsUsageArrayHelper::check(uint32_t previousCheckResult,
    1.65 +                          const char *suffix,
    1.66 +                          CertVerifier * certVerifier,
    1.67 +                          SECCertificateUsage aCertUsage,
    1.68 +                          PRTime time,
    1.69 +                          CertVerifier::Flags flags,
    1.70 +                          uint32_t &aCounter,
    1.71 +                          char16_t **outUsages)
    1.72 +{
    1.73 +  if (!aCertUsage) {
    1.74 +    MOZ_CRASH("caller should have supplied non-zero aCertUsage");
    1.75 +  }
    1.76 +
    1.77 +  if (isFatalError(previousCheckResult)) {
    1.78 +      return previousCheckResult;
    1.79 +  }
    1.80 +
    1.81 +  nsAutoCString typestr;
    1.82 +  switch (aCertUsage) {
    1.83 +  case certificateUsageSSLClient:
    1.84 +    typestr = "VerifySSLClient";
    1.85 +    break;
    1.86 +  case certificateUsageSSLServer:
    1.87 +    typestr = "VerifySSLServer";
    1.88 +    break;
    1.89 +  case certificateUsageEmailSigner:
    1.90 +    typestr = "VerifyEmailSigner";
    1.91 +    break;
    1.92 +  case certificateUsageEmailRecipient:
    1.93 +    typestr = "VerifyEmailRecip";
    1.94 +    break;
    1.95 +  case certificateUsageObjectSigner:
    1.96 +    typestr = "VerifyObjSign";
    1.97 +    break;
    1.98 +  case certificateUsageSSLCA:
    1.99 +    typestr = "VerifySSLCA";
   1.100 +    break;
   1.101 +  case certificateUsageVerifyCA:
   1.102 +    typestr = "VerifyCAVerifier";
   1.103 +    break;
   1.104 +  case certificateUsageStatusResponder:
   1.105 +    typestr = "VerifyStatusResponder";
   1.106 +    break;
   1.107 +  default:
   1.108 +    MOZ_CRASH("unknown cert usage passed to check()");
   1.109 +  }
   1.110 +
   1.111 +  SECStatus rv = certVerifier->VerifyCert(mCert, aCertUsage, time,
   1.112 +                                          nullptr /*XXX:wincx*/,
   1.113 +                                          nullptr /*hostname*/, flags);
   1.114 +
   1.115 +  if (rv == SECSuccess) {
   1.116 +    typestr.Append(suffix);
   1.117 +    nsAutoString verifyDesc;
   1.118 +    m_rv = nssComponent->GetPIPNSSBundleString(typestr.get(), verifyDesc);
   1.119 +    if (NS_SUCCEEDED(m_rv)) {
   1.120 +      outUsages[aCounter++] = ToNewUnicode(verifyDesc);
   1.121 +    }
   1.122 +    return nsIX509Cert::VERIFIED_OK;
   1.123 +  }
   1.124 +
   1.125 +  PRErrorCode error = PR_GetError();
   1.126 +
   1.127 +  uint32_t result = nsIX509Cert::NOT_VERIFIED_UNKNOWN;
   1.128 +  verifyFailed(&result, error);
   1.129 +
   1.130 +  // USAGE_NOT_ALLOWED is the weakest non-fatal error; let all other errors
   1.131 +  // override it.
   1.132 +  if (result == nsIX509Cert::USAGE_NOT_ALLOWED &&
   1.133 +      previousCheckResult != nsIX509Cert::VERIFIED_OK) {
   1.134 +      result = previousCheckResult;
   1.135 +  }
   1.136 +
   1.137 +  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
   1.138 +          ("error validating certificate for usage %s: %s (%d) -> %ud \n",
   1.139 +          typestr.get(), PR_ErrorToName(error), (int) error, (int) result));
   1.140 +
   1.141 +  return result;
   1.142 +}
   1.143 +
   1.144 +
   1.145 +// Maps the error code to one of the Constants for certificate verification
   1.146 +// results" in nsIX509Cert.
   1.147 +void
   1.148 +nsUsageArrayHelper::verifyFailed(uint32_t *_verified, int err)
   1.149 +{
   1.150 +  switch (err) {
   1.151 +  /* For these cases, verify only failed for the particular usage */
   1.152 +  case SEC_ERROR_INADEQUATE_KEY_USAGE:
   1.153 +  case SEC_ERROR_INADEQUATE_CERT_TYPE:
   1.154 +  case SEC_ERROR_CA_CERT_INVALID:
   1.155 +    *_verified = nsNSSCertificate::USAGE_NOT_ALLOWED; break;
   1.156 +  /* These are the cases that have individual error messages */
   1.157 +  case SEC_ERROR_REVOKED_CERTIFICATE:
   1.158 +    *_verified = nsNSSCertificate::CERT_REVOKED; break;
   1.159 +  case SEC_ERROR_EXPIRED_CERTIFICATE:
   1.160 +    *_verified = nsNSSCertificate::CERT_EXPIRED; break;
   1.161 +  case SEC_ERROR_UNTRUSTED_CERT:
   1.162 +    *_verified = nsNSSCertificate::CERT_NOT_TRUSTED; break;
   1.163 +  case SEC_ERROR_UNTRUSTED_ISSUER:
   1.164 +    *_verified = nsNSSCertificate::ISSUER_NOT_TRUSTED; break;
   1.165 +  case SEC_ERROR_UNKNOWN_ISSUER:
   1.166 +    *_verified = nsNSSCertificate::ISSUER_UNKNOWN; break;
   1.167 +  case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
   1.168 +    // XXX are there other error for this?
   1.169 +    *_verified = nsNSSCertificate::INVALID_CA; break;
   1.170 +  case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED:
   1.171 +    *_verified = nsNSSCertificate::SIGNATURE_ALGORITHM_DISABLED; break;
   1.172 +  default:
   1.173 +    *_verified = nsNSSCertificate::NOT_VERIFIED_UNKNOWN; break;
   1.174 +  }
   1.175 +}
   1.176 +
   1.177 +nsresult
   1.178 +nsUsageArrayHelper::GetUsagesArray(const char *suffix,
   1.179 +                      bool localOnly,
   1.180 +                      uint32_t outArraySize,
   1.181 +                      uint32_t *_verified,
   1.182 +                      uint32_t *_count,
   1.183 +                      char16_t **outUsages)
   1.184 +{
   1.185 +  nsNSSShutDownPreventionLock locker;
   1.186 +  if (NS_FAILED(m_rv))
   1.187 +    return m_rv;
   1.188 +
   1.189 +  NS_ENSURE_TRUE(nssComponent, NS_ERROR_NOT_AVAILABLE);
   1.190 +
   1.191 +  if (outArraySize < max_returned_out_array_size)
   1.192 +    return NS_ERROR_FAILURE;
   1.193 +
   1.194 +  RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier());
   1.195 +  NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED);
   1.196 +
   1.197 +  uint32_t &count = *_count;
   1.198 +  count = 0;
   1.199 +
   1.200 +  PRTime now = PR_Now();
   1.201 +  CertVerifier::Flags flags = localOnly ? CertVerifier::FLAG_LOCAL_ONLY : 0;
   1.202 +
   1.203 +  // The following list of checks must be < max_returned_out_array_size
   1.204 +
   1.205 +  uint32_t result;
   1.206 +  result = check(nsIX509Cert::VERIFIED_OK, suffix, certVerifier,
   1.207 +                 certificateUsageSSLClient, now, flags, count, outUsages);
   1.208 +  result = check(result, suffix, certVerifier,
   1.209 +                 certificateUsageSSLServer, now, flags, count, outUsages);
   1.210 +  result = check(result, suffix, certVerifier,
   1.211 +                 certificateUsageEmailSigner, now, flags, count, outUsages);
   1.212 +  result = check(result, suffix, certVerifier,
   1.213 +                 certificateUsageEmailRecipient, now, flags, count, outUsages);
   1.214 +  result = check(result, suffix, certVerifier,
   1.215 +                 certificateUsageObjectSigner, now, flags, count, outUsages);
   1.216 +  result = check(result, suffix, certVerifier,
   1.217 +                 certificateUsageSSLCA, now, flags, count, outUsages);
   1.218 +  result = check(result, suffix, certVerifier,
   1.219 +                 certificateUsageStatusResponder, now, flags, count, outUsages);
   1.220 +
   1.221 +  if (isFatalError(result) || count == 0) {
   1.222 +    MOZ_ASSERT(result != nsIX509Cert::VERIFIED_OK);
   1.223 +
   1.224 +    // Clear the output usage strings in the case where we encountered a fatal
   1.225 +    // error after we already successfully validated the cert for some usages.
   1.226 +    for (uint32_t i = 0; i < count; ++i) {
   1.227 +      delete outUsages[i];
   1.228 +      outUsages[i] = nullptr;
   1.229 +    }
   1.230 +    count = 0;
   1.231 +    *_verified = result;
   1.232 +  } else {
   1.233 +    *_verified = nsNSSCertificate::VERIFIED_OK;
   1.234 +  }
   1.235 +  return NS_OK;
   1.236 +}

mercurial