1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/pkix/lib/pkixcheck.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,693 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ 1.6 +/* Copyright 2013 Mozilla Foundation 1.7 + * 1.8 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.9 + * you may not use this file except in compliance with the License. 1.10 + * You may obtain a copy of the License at 1.11 + * 1.12 + * http://www.apache.org/licenses/LICENSE-2.0 1.13 + * 1.14 + * Unless required by applicable law or agreed to in writing, software 1.15 + * distributed under the License is distributed on an "AS IS" BASIS, 1.16 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.17 + * See the License for the specific language governing permissions and 1.18 + * limitations under the License. 1.19 + */ 1.20 + 1.21 +#include <limits> 1.22 + 1.23 +#include "pkix/pkix.h" 1.24 +#include "pkixcheck.h" 1.25 +#include "pkixder.h" 1.26 +#include "pkixutil.h" 1.27 +#include "secder.h" 1.28 + 1.29 +namespace mozilla { namespace pkix { 1.30 + 1.31 +Result 1.32 +CheckTimes(const CERTCertificate* cert, PRTime time) 1.33 +{ 1.34 + PR_ASSERT(cert); 1.35 + 1.36 + SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, time, false); 1.37 + if (validity != secCertTimeValid) { 1.38 + return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE); 1.39 + } 1.40 + 1.41 + return Success; 1.42 +} 1.43 + 1.44 +// 4.2.1.3. Key Usage (id-ce-keyUsage) 1.45 + 1.46 +// As explained in the comment in CheckKeyUsage, bit 0 is the most significant 1.47 +// bit and bit 7 is the least significant bit. 1.48 +inline uint8_t KeyUsageToBitMask(KeyUsage keyUsage) 1.49 +{ 1.50 + PR_ASSERT(keyUsage != KeyUsage::noParticularKeyUsageRequired); 1.51 + return 0x80u >> static_cast<uint8_t>(keyUsage); 1.52 +} 1.53 + 1.54 +Result 1.55 +CheckKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedKeyUsage, 1.56 + KeyUsage requiredKeyUsageIfPresent) 1.57 +{ 1.58 + if (!encodedKeyUsage) { 1.59 + // TODO(bug 970196): Reject certificates that are being used to verify 1.60 + // certificate signatures unless the certificate is a trust anchor, to 1.61 + // reduce the chances of an end-entity certificate being abused as a CA 1.62 + // certificate. 1.63 + // if (endEntityOrCA == EndEntityOrCA::MustBeCA && !isTrustAnchor) { 1.64 + // return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.65 + // } 1.66 + // 1.67 + // TODO: Users may configure arbitrary certificates as trust anchors, not 1.68 + // just roots. We should only allow a certificate without a key usage to be 1.69 + // used as a CA when it is self-issued and self-signed. 1.70 + return Success; 1.71 + } 1.72 + 1.73 + der::Input input; 1.74 + if (input.Init(encodedKeyUsage->data, encodedKeyUsage->len) != der::Success) { 1.75 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.76 + } 1.77 + der::Input value; 1.78 + if (der::ExpectTagAndGetValue(input, der::BIT_STRING, value) != der::Success) { 1.79 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.80 + } 1.81 + 1.82 + uint8_t numberOfPaddingBits; 1.83 + if (value.Read(numberOfPaddingBits) != der::Success) { 1.84 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.85 + } 1.86 + if (numberOfPaddingBits > 7) { 1.87 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.88 + } 1.89 + 1.90 + uint8_t bits; 1.91 + if (value.Read(bits) != der::Success) { 1.92 + // Reject empty bit masks. 1.93 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.94 + } 1.95 + 1.96 + // The most significant bit is numbered 0 (digitalSignature) and the least 1.97 + // significant bit is numbered 7 (encipherOnly), and the padding is in the 1.98 + // least significant bits of the last byte. The numbering of bits in a byte 1.99 + // is backwards from how we usually interpret them. 1.100 + // 1.101 + // For example, let's say bits is encoded in one byte with of value 0xB0 and 1.102 + // numberOfPaddingBits == 4. Then, bits is 10110000 in binary: 1.103 + // 1.104 + // bit 0 bit 3 1.105 + // | | 1.106 + // v v 1.107 + // 10110000 1.108 + // ^^^^ 1.109 + // | 1.110 + // 4 padding bits 1.111 + // 1.112 + // Since bits is the last byte, we have to consider the padding by ensuring 1.113 + // that the least significant 4 bits are all zero, since DER rules require 1.114 + // all padding bits to be zero. Then we have to look at the bit N bits to the 1.115 + // right of the most significant bit, where N is a value from the KeyUsage 1.116 + // enumeration. 1.117 + // 1.118 + // Let's say we're interested in the keyCertSign (5) bit. We'd need to look 1.119 + // at bit 5, which is zero, so keyCertSign is not asserted. (Since we check 1.120 + // that the padding is all zeros, it is OK to read from the padding bits.) 1.121 + // 1.122 + // Let's say we're interested in the digitalSignature (0) bit. We'd need to 1.123 + // look at the bit 0 (the most significant bit), which is set, so that means 1.124 + // digitalSignature is asserted. Similarly, keyEncipherment (2) and 1.125 + // dataEncipherment (3) are asserted. 1.126 + // 1.127 + // Note that since the KeyUsage enumeration is limited to values 0-7, we 1.128 + // only ever need to examine the first byte test for 1.129 + // requiredKeyUsageIfPresent. 1.130 + 1.131 + if (requiredKeyUsageIfPresent != KeyUsage::noParticularKeyUsageRequired) { 1.132 + // Check that the required key usage bit is set. 1.133 + if ((bits & KeyUsageToBitMask(requiredKeyUsageIfPresent)) == 0) { 1.134 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.135 + } 1.136 + } 1.137 + 1.138 + if (endEntityOrCA != EndEntityOrCA::MustBeCA) { 1.139 + // RFC 5280 says "The keyCertSign bit is asserted when the subject public 1.140 + // key is used for verifying signatures on public key certificates. If the 1.141 + // keyCertSign bit is asserted, then the cA bit in the basic constraints 1.142 + // extension (Section 4.2.1.9) MUST also be asserted." 1.143 + if ((bits & KeyUsageToBitMask(KeyUsage::keyCertSign)) != 0) { 1.144 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.145 + } 1.146 + } 1.147 + 1.148 + // The padding applies to the last byte, so skip to the last byte. 1.149 + while (!value.AtEnd()) { 1.150 + if (value.Read(bits) != der::Success) { 1.151 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.152 + } 1.153 + } 1.154 + 1.155 + // All of the padding bits must be zero, according to DER rules. 1.156 + uint8_t paddingMask = static_cast<uint8_t>((1 << numberOfPaddingBits) - 1); 1.157 + if ((bits & paddingMask) != 0) { 1.158 + return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE); 1.159 + } 1.160 + 1.161 + return Success; 1.162 +} 1.163 + 1.164 +// RFC5820 4.2.1.4. Certificate Policies 1.165 +// 1.166 +// "The user-initial-policy-set contains the special value any-policy if the 1.167 +// user is not concerned about certificate policy." 1.168 +Result 1.169 +CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA, 1.170 + bool isTrustAnchor, SECOidTag requiredPolicy) 1.171 +{ 1.172 + if (requiredPolicy == SEC_OID_X509_ANY_POLICY) { 1.173 + return Success; 1.174 + } 1.175 + 1.176 + // It is likely some callers will pass SEC_OID_UNKNOWN when they don't care, 1.177 + // instead of passing SEC_OID_X509_ANY_POLICY. Help them out by failing hard. 1.178 + if (requiredPolicy == SEC_OID_UNKNOWN) { 1.179 + PR_SetError(SEC_ERROR_INVALID_ARGS, 0); 1.180 + return FatalError; 1.181 + } 1.182 + 1.183 + // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when 1.184 + // inhibitAnyPolicy extension is present and we need to evaluate certificate 1.185 + // policies. 1.186 + if (cert.encodedInhibitAnyPolicy) { 1.187 + PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); 1.188 + return RecoverableError; 1.189 + } 1.190 + 1.191 + // The root CA certificate may omit the policies that it has been 1.192 + // trusted for, so we cannot require the policies to be present in those 1.193 + // certificates. Instead, the determination of which roots are trusted for 1.194 + // which policies is made by the TrustDomain's GetCertTrust method. 1.195 + if (isTrustAnchor && endEntityOrCA == MustBeCA) { 1.196 + return Success; 1.197 + } 1.198 + 1.199 + if (!cert.encodedCertificatePolicies) { 1.200 + PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); 1.201 + return RecoverableError; 1.202 + } 1.203 + 1.204 + ScopedPtr<CERTCertificatePolicies, CERT_DestroyCertificatePoliciesExtension> 1.205 + policies(CERT_DecodeCertificatePoliciesExtension( 1.206 + cert.encodedCertificatePolicies)); 1.207 + if (!policies) { 1.208 + return MapSECStatus(SECFailure); 1.209 + } 1.210 + 1.211 + for (const CERTPolicyInfo* const* policyInfos = policies->policyInfos; 1.212 + *policyInfos; ++policyInfos) { 1.213 + if ((*policyInfos)->oid == requiredPolicy) { 1.214 + return Success; 1.215 + } 1.216 + // Intermediate certs are allowed to have the anyPolicy OID 1.217 + if (endEntityOrCA == MustBeCA && 1.218 + (*policyInfos)->oid == SEC_OID_X509_ANY_POLICY) { 1.219 + return Success; 1.220 + } 1.221 + } 1.222 + 1.223 + PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0); 1.224 + return RecoverableError; 1.225 +} 1.226 + 1.227 +// BasicConstraints ::= SEQUENCE { 1.228 +// cA BOOLEAN DEFAULT FALSE, 1.229 +// pathLenConstraint INTEGER (0..MAX) OPTIONAL } 1.230 +der::Result 1.231 +DecodeBasicConstraints(const SECItem* encodedBasicConstraints, 1.232 + CERTBasicConstraints& basicConstraints) 1.233 +{ 1.234 + PR_ASSERT(encodedBasicConstraints); 1.235 + if (!encodedBasicConstraints) { 1.236 + return der::Fail(SEC_ERROR_INVALID_ARGS); 1.237 + } 1.238 + 1.239 + basicConstraints.isCA = false; 1.240 + basicConstraints.pathLenConstraint = 0; 1.241 + 1.242 + der::Input input; 1.243 + if (input.Init(encodedBasicConstraints->data, encodedBasicConstraints->len) 1.244 + != der::Success) { 1.245 + return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); 1.246 + } 1.247 + 1.248 + if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) { 1.249 + return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); 1.250 + } 1.251 + 1.252 + bool isCA = false; 1.253 + // TODO(bug 989518): cA is by default false. According to DER, default 1.254 + // values must not be explicitly encoded in a SEQUENCE. So, if this 1.255 + // value is present and false, it is an encoding error. However, Go Daddy 1.256 + // has issued many certificates with this improper encoding, so we can't 1.257 + // enforce this yet (hence passing true for allowInvalidExplicitEncoding 1.258 + // to der::OptionalBoolean). 1.259 + if (der::OptionalBoolean(input, true, isCA) != der::Success) { 1.260 + return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); 1.261 + } 1.262 + basicConstraints.isCA = isCA; 1.263 + 1.264 + if (input.Peek(der::INTEGER)) { 1.265 + SECItem pathLenConstraintEncoded; 1.266 + if (der::Integer(input, pathLenConstraintEncoded) != der::Success) { 1.267 + return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); 1.268 + } 1.269 + long pathLenConstraint = DER_GetInteger(&pathLenConstraintEncoded); 1.270 + if (pathLenConstraint >= std::numeric_limits<int>::max() || 1.271 + pathLenConstraint < 0) { 1.272 + return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); 1.273 + } 1.274 + basicConstraints.pathLenConstraint = static_cast<int>(pathLenConstraint); 1.275 + // TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT 1.276 + // be included (as per RFC 5280 section 4.2.1.9), but for compatibility 1.277 + // reasons, we don't check this for now. 1.278 + } else if (basicConstraints.isCA) { 1.279 + // If this is a CA but the path length is omitted, it is unlimited. 1.280 + basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; 1.281 + } 1.282 + 1.283 + if (der::End(input) != der::Success) { 1.284 + return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID); 1.285 + } 1.286 + return der::Success; 1.287 +} 1.288 + 1.289 +// RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints) 1.290 +Result 1.291 +CheckBasicConstraints(const BackCert& cert, 1.292 + EndEntityOrCA endEntityOrCA, 1.293 + bool isTrustAnchor, 1.294 + unsigned int subCACount) 1.295 +{ 1.296 + CERTBasicConstraints basicConstraints; 1.297 + if (cert.encodedBasicConstraints) { 1.298 + if (DecodeBasicConstraints(cert.encodedBasicConstraints, 1.299 + basicConstraints) != der::Success) { 1.300 + return RecoverableError; 1.301 + } 1.302 + } else { 1.303 + // Synthesize a non-CA basic constraints by default 1.304 + basicConstraints.isCA = false; 1.305 + basicConstraints.pathLenConstraint = 0; 1.306 + 1.307 + // "If the basic constraints extension is not present in a version 3 1.308 + // certificate, or the extension is present but the cA boolean is not 1.309 + // asserted, then the certified public key MUST NOT be used to verify 1.310 + // certificate signatures." 1.311 + // 1.312 + // For compatibility, we must accept v1 trust anchors without basic 1.313 + // constraints as CAs. 1.314 + // 1.315 + // TODO: add check for self-signedness? 1.316 + if (endEntityOrCA == MustBeCA && isTrustAnchor) { 1.317 + const CERTCertificate* nssCert = cert.GetNSSCert(); 1.318 + // We only allow trust anchor CA certs to omit the 1.319 + // basicConstraints extension if they are v1. v1 is encoded 1.320 + // implicitly. 1.321 + if (!nssCert->version.data && !nssCert->version.len) { 1.322 + basicConstraints.isCA = true; 1.323 + basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; 1.324 + } 1.325 + } 1.326 + } 1.327 + 1.328 + if (endEntityOrCA == MustBeEndEntity) { 1.329 + // CA certificates are not trusted as EE certs. 1.330 + 1.331 + if (basicConstraints.isCA) { 1.332 + // XXX: We use SEC_ERROR_CA_CERT_INVALID here so we can distinguish 1.333 + // this error from other errors, given that NSS does not have a "CA cert 1.334 + // used as end-entity" error code since it doesn't have such a 1.335 + // prohibition. We should add such an error code and stop abusing 1.336 + // SEC_ERROR_CA_CERT_INVALID this way. 1.337 + // 1.338 + // Note, in particular, that this check prevents a delegated OCSP 1.339 + // response signing certificate with the CA bit from successfully 1.340 + // validating when we check it from pkixocsp.cpp, which is a good thing. 1.341 + // 1.342 + return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID); 1.343 + } 1.344 + 1.345 + return Success; 1.346 + } 1.347 + 1.348 + PORT_Assert(endEntityOrCA == MustBeCA); 1.349 + 1.350 + // End-entity certificates are not allowed to act as CA certs. 1.351 + if (!basicConstraints.isCA) { 1.352 + return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID); 1.353 + } 1.354 + 1.355 + if (basicConstraints.pathLenConstraint >= 0) { 1.356 + if (subCACount > 1.357 + static_cast<unsigned int>(basicConstraints.pathLenConstraint)) { 1.358 + return Fail(RecoverableError, SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID); 1.359 + } 1.360 + } 1.361 + 1.362 + return Success; 1.363 +} 1.364 + 1.365 +Result 1.366 +BackCert::GetConstrainedNames(/*out*/ const CERTGeneralName** result) 1.367 +{ 1.368 + if (!constrainedNames) { 1.369 + if (!GetArena()) { 1.370 + return FatalError; 1.371 + } 1.372 + 1.373 + constrainedNames = 1.374 + CERT_GetConstrainedCertificateNames(nssCert, arena.get(), 1.375 + cnOptions == IncludeCN); 1.376 + if (!constrainedNames) { 1.377 + return MapSECStatus(SECFailure); 1.378 + } 1.379 + } 1.380 + 1.381 + *result = constrainedNames; 1.382 + return Success; 1.383 +} 1.384 + 1.385 +// 4.2.1.10. Name Constraints 1.386 +Result 1.387 +CheckNameConstraints(BackCert& cert) 1.388 +{ 1.389 + static const char constraintFranceGov[] = 1.390 + "\x30\x5D" /* sequence len 93*/ 1.391 + "\xA0\x5B" /* element len 91 */ 1.392 + "\x30\x05" /* sequence len 5 */ 1.393 + "\x82\x03" /* entry len 3 */ 1.394 + ".fr" 1.395 + "\x30\x05\x82\x03" /* sequence len 5, entry len 3 */ 1.396 + ".gp" 1.397 + "\x30\x05\x82\x03" 1.398 + ".gf" 1.399 + "\x30\x05\x82\x03" 1.400 + ".mq" 1.401 + "\x30\x05\x82\x03" 1.402 + ".re" 1.403 + "\x30\x05\x82\x03" 1.404 + ".yt" 1.405 + "\x30\x05\x82\x03" 1.406 + ".pm" 1.407 + "\x30\x05\x82\x03" 1.408 + ".bl" 1.409 + "\x30\x05\x82\x03" 1.410 + ".mf" 1.411 + "\x30\x05\x82\x03" 1.412 + ".wf" 1.413 + "\x30\x05\x82\x03" 1.414 + ".pf" 1.415 + "\x30\x05\x82\x03" 1.416 + ".nc" 1.417 + "\x30\x05\x82\x03" 1.418 + ".tf"; 1.419 + 1.420 + /* The stringified value for the subject is: 1.421 + E=igca@sgdn.pm.gouv.fr,CN=IGC/A,OU=DCSSI,O=PM/SGDN,L=Paris,ST=France,C=FR 1.422 + */ 1.423 + static const char rawANSSISubject[] = 1.424 + "\x30\x81\x85\x31\x0B\x30\x09\x06\x03\x55\x04" 1.425 + "\x06\x13\x02\x46\x52\x31\x0F\x30\x0D\x06\x03" 1.426 + "\x55\x04\x08\x13\x06\x46\x72\x61\x6E\x63\x65" 1.427 + "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05" 1.428 + "\x50\x61\x72\x69\x73\x31\x10\x30\x0E\x06\x03" 1.429 + "\x55\x04\x0A\x13\x07\x50\x4D\x2F\x53\x47\x44" 1.430 + "\x4E\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13" 1.431 + "\x05\x44\x43\x53\x53\x49\x31\x0E\x30\x0C\x06" 1.432 + "\x03\x55\x04\x03\x13\x05\x49\x47\x43\x2F\x41" 1.433 + "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7" 1.434 + "\x0D\x01\x09\x01\x16\x14\x69\x67\x63\x61\x40" 1.435 + "\x73\x67\x64\x6E\x2E\x70\x6D\x2E\x67\x6F\x75" 1.436 + "\x76\x2E\x66\x72"; 1.437 + 1.438 + const SECItem ANSSI_SUBJECT = { 1.439 + siBuffer, 1.440 + reinterpret_cast<uint8_t *>(const_cast<char *>(rawANSSISubject)), 1.441 + sizeof(rawANSSISubject) - 1 1.442 + }; 1.443 + 1.444 + const SECItem PERMIT_FRANCE_GOV_NC = { 1.445 + siBuffer, 1.446 + reinterpret_cast<uint8_t *>(const_cast<char *>(constraintFranceGov)), 1.447 + sizeof(constraintFranceGov) - 1 1.448 + }; 1.449 + 1.450 + const SECItem* nameConstraintsToUse = cert.encodedNameConstraints; 1.451 + 1.452 + if (!nameConstraintsToUse) { 1.453 + if (SECITEM_ItemsAreEqual(&cert.GetNSSCert()->derSubject, &ANSSI_SUBJECT)) { 1.454 + nameConstraintsToUse = &PERMIT_FRANCE_GOV_NC; 1.455 + } else { 1.456 + return Success; 1.457 + } 1.458 + } 1.459 + 1.460 + PLArenaPool* arena = cert.GetArena(); 1.461 + if (!arena) { 1.462 + return FatalError; 1.463 + } 1.464 + 1.465 + // Owned by arena 1.466 + const CERTNameConstraints* constraints = 1.467 + CERT_DecodeNameConstraintsExtension(arena, nameConstraintsToUse); 1.468 + if (!constraints) { 1.469 + return MapSECStatus(SECFailure); 1.470 + } 1.471 + 1.472 + for (BackCert* prev = cert.childCert; prev; prev = prev->childCert) { 1.473 + const CERTGeneralName* names = nullptr; 1.474 + Result rv = prev->GetConstrainedNames(&names); 1.475 + if (rv != Success) { 1.476 + return rv; 1.477 + } 1.478 + PORT_Assert(names); 1.479 + CERTGeneralName* currentName = const_cast<CERTGeneralName*>(names); 1.480 + do { 1.481 + if (CERT_CheckNameSpace(arena, constraints, currentName) != SECSuccess) { 1.482 + // XXX: It seems like CERT_CheckNameSpace doesn't always call 1.483 + // PR_SetError when it fails. We set the error code here, though this 1.484 + // may be papering over some fatal errors. NSS's 1.485 + // cert_VerifyCertChainOld does something similar. 1.486 + PR_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, 0); 1.487 + return RecoverableError; 1.488 + } 1.489 + currentName = CERT_GetNextGeneralName(currentName); 1.490 + } while (currentName != names); 1.491 + } 1.492 + 1.493 + return Success; 1.494 +} 1.495 + 1.496 +// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) 1.497 +// 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage) 1.498 +Result 1.499 +CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs, 1.500 + SECOidTag requiredEKU) 1.501 +{ 1.502 + // TODO: Either do not allow anyExtendedKeyUsage to be passed as requiredEKU, 1.503 + // or require that callers pass anyExtendedKeyUsage instead of 1.504 + // SEC_OID_UNKNWON and disallow SEC_OID_UNKNWON. 1.505 + 1.506 + // XXX: We're using SEC_ERROR_INADEQUATE_CERT_TYPE here so that callers can 1.507 + // distinguish EKU mismatch from KU mismatch from basic constraints mismatch. 1.508 + // We should probably add a new error code that is more clear for this type 1.509 + // of problem. 1.510 + 1.511 + bool foundOCSPSigning = false; 1.512 + 1.513 + if (encodedEKUs) { 1.514 + ScopedPtr<CERTOidSequence, CERT_DestroyOidSequence> 1.515 + seq(CERT_DecodeOidSequence(encodedEKUs)); 1.516 + if (!seq) { 1.517 + PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); 1.518 + return RecoverableError; 1.519 + } 1.520 + 1.521 + bool found = false; 1.522 + 1.523 + // XXX: We allow duplicate entries. 1.524 + for (const SECItem* const* oids = seq->oids; oids && *oids; ++oids) { 1.525 + SECOidTag oidTag = SECOID_FindOIDTag(*oids); 1.526 + if (requiredEKU != SEC_OID_UNKNOWN && oidTag == requiredEKU) { 1.527 + found = true; 1.528 + } else { 1.529 + // Treat CA certs with step-up OID as also having SSL server type. 1.530 + // COMODO has issued certificates that require this behavior 1.531 + // that don't expire until June 2020! 1.532 + // TODO 982932: Limit this expection to old certificates 1.533 + if (endEntityOrCA == MustBeCA && 1.534 + requiredEKU == SEC_OID_EXT_KEY_USAGE_SERVER_AUTH && 1.535 + oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) { 1.536 + found = true; 1.537 + } 1.538 + } 1.539 + if (oidTag == SEC_OID_OCSP_RESPONDER) { 1.540 + foundOCSPSigning = true; 1.541 + } 1.542 + } 1.543 + 1.544 + // If the EKU extension was included, then the required EKU must be in the 1.545 + // list. 1.546 + if (!found) { 1.547 + PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); 1.548 + return RecoverableError; 1.549 + } 1.550 + } 1.551 + 1.552 + // pkixocsp.cpp depends on the following additional checks. 1.553 + 1.554 + if (endEntityOrCA == MustBeEndEntity) { 1.555 + // When validating anything other than an delegated OCSP signing cert, 1.556 + // reject any cert that also claims to be an OCSP responder, because such 1.557 + // a cert does not make sense. For example, if an SSL certificate were to 1.558 + // assert id-kp-OCSPSigning then it could sign OCSP responses for itself, 1.559 + // if not for this check. 1.560 + // That said, we accept CA certificates with id-kp-OCSPSigning because 1.561 + // some CAs in Mozilla's CA program have issued such intermediate 1.562 + // certificates, and because some CAs have reported some Microsoft server 1.563 + // software wrongly requires CA certificates to have id-kp-OCSPSigning. 1.564 + // Allowing this exception does not cause any security issues because we 1.565 + // require delegated OCSP response signing certificates to be end-entity 1.566 + // certificates. 1.567 + if (foundOCSPSigning && requiredEKU != SEC_OID_OCSP_RESPONDER) { 1.568 + PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); 1.569 + return RecoverableError; 1.570 + } 1.571 + // http://tools.ietf.org/html/rfc6960#section-4.2.2.2: 1.572 + // "OCSP signing delegation SHALL be designated by the inclusion of 1.573 + // id-kp-OCSPSigning in an extended key usage certificate extension 1.574 + // included in the OCSP response signer's certificate." 1.575 + // 1.576 + // id-kp-OCSPSigning is the only EKU that isn't implicitly assumed when the 1.577 + // EKU extension is missing from an end-entity certificate. However, any CA 1.578 + // certificate can issue a delegated OCSP response signing certificate, so 1.579 + // we can't require the EKU be explicitly included for CA certificates. 1.580 + if (!foundOCSPSigning && requiredEKU == SEC_OID_OCSP_RESPONDER) { 1.581 + PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0); 1.582 + return RecoverableError; 1.583 + } 1.584 + } 1.585 + 1.586 + return Success; 1.587 +} 1.588 + 1.589 +Result 1.590 +CheckIssuerIndependentProperties(TrustDomain& trustDomain, 1.591 + BackCert& cert, 1.592 + PRTime time, 1.593 + EndEntityOrCA endEntityOrCA, 1.594 + KeyUsage requiredKeyUsageIfPresent, 1.595 + SECOidTag requiredEKUIfPresent, 1.596 + SECOidTag requiredPolicy, 1.597 + unsigned int subCACount, 1.598 + /*optional out*/ TrustDomain::TrustLevel* trustLevelOut) 1.599 +{ 1.600 + Result rv; 1.601 + 1.602 + TrustDomain::TrustLevel trustLevel; 1.603 + rv = MapSECStatus(trustDomain.GetCertTrust(endEntityOrCA, 1.604 + requiredPolicy, 1.605 + cert.GetNSSCert(), 1.606 + &trustLevel)); 1.607 + if (rv != Success) { 1.608 + return rv; 1.609 + } 1.610 + if (trustLevel == TrustDomain::ActivelyDistrusted) { 1.611 + PORT_SetError(SEC_ERROR_UNTRUSTED_CERT); 1.612 + return RecoverableError; 1.613 + } 1.614 + if (trustLevel != TrustDomain::TrustAnchor && 1.615 + trustLevel != TrustDomain::InheritsTrust) { 1.616 + // The TrustDomain returned a trust level that we weren't expecting. 1.617 + PORT_SetError(PR_INVALID_STATE_ERROR); 1.618 + return FatalError; 1.619 + } 1.620 + if (trustLevelOut) { 1.621 + *trustLevelOut = trustLevel; 1.622 + } 1.623 + 1.624 + bool isTrustAnchor = endEntityOrCA == MustBeCA && 1.625 + trustLevel == TrustDomain::TrustAnchor; 1.626 + 1.627 + PLArenaPool* arena = cert.GetArena(); 1.628 + if (!arena) { 1.629 + return FatalError; 1.630 + } 1.631 + 1.632 + // 4.2.1.1. Authority Key Identifier is ignored (see bug 965136). 1.633 + 1.634 + // 4.2.1.2. Subject Key Identifier is ignored (see bug 965136). 1.635 + 1.636 + // 4.2.1.3. Key Usage 1.637 + rv = CheckKeyUsage(endEntityOrCA, cert.encodedKeyUsage, 1.638 + requiredKeyUsageIfPresent); 1.639 + if (rv != Success) { 1.640 + return rv; 1.641 + } 1.642 + 1.643 + // 4.2.1.4. Certificate Policies 1.644 + rv = CheckCertificatePolicies(cert, endEntityOrCA, isTrustAnchor, 1.645 + requiredPolicy); 1.646 + if (rv != Success) { 1.647 + return rv; 1.648 + } 1.649 + 1.650 + // 4.2.1.5. Policy Mappings are not supported; see the documentation about 1.651 + // policy enforcement in pkix.h. 1.652 + 1.653 + // 4.2.1.6. Subject Alternative Name dealt with during name constraint 1.654 + // checking and during name verification (CERT_VerifyCertName). 1.655 + 1.656 + // 4.2.1.7. Issuer Alternative Name is not something that needs checking. 1.657 + 1.658 + // 4.2.1.8. Subject Directory Attributes is not something that needs 1.659 + // checking. 1.660 + 1.661 + // 4.2.1.9. Basic Constraints. 1.662 + rv = CheckBasicConstraints(cert, endEntityOrCA, isTrustAnchor, subCACount); 1.663 + if (rv != Success) { 1.664 + return rv; 1.665 + } 1.666 + 1.667 + // 4.2.1.10. Name Constraints is dealt with in during path building. 1.668 + 1.669 + // 4.2.1.11. Policy Constraints are implicitly supported; see the 1.670 + // documentation about policy enforcement in pkix.h. 1.671 + 1.672 + // 4.2.1.12. Extended Key Usage 1.673 + rv = CheckExtendedKeyUsage(endEntityOrCA, cert.encodedExtendedKeyUsage, 1.674 + requiredEKUIfPresent); 1.675 + if (rv != Success) { 1.676 + return rv; 1.677 + } 1.678 + 1.679 + // 4.2.1.13. CRL Distribution Points is not supported, though the 1.680 + // TrustDomain's CheckRevocation method may parse it and process it 1.681 + // on its own. 1.682 + 1.683 + // 4.2.1.14. Inhibit anyPolicy is implicitly supported; see the documentation 1.684 + // about policy enforcement in pkix.h. 1.685 + 1.686 + // IMPORTANT: This check must come after the other checks in order for error 1.687 + // ranking to work correctly. 1.688 + rv = CheckTimes(cert.GetNSSCert(), time); 1.689 + if (rv != Success) { 1.690 + return rv; 1.691 + } 1.692 + 1.693 + return Success; 1.694 +} 1.695 + 1.696 +} } // namespace mozilla::pkix