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

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

mercurial