security/pkix/lib/pkixcheck.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
michael@0 3 /* Copyright 2013 Mozilla Foundation
michael@0 4 *
michael@0 5 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 6 * you may not use this file except in compliance with the License.
michael@0 7 * You may obtain a copy of the License at
michael@0 8 *
michael@0 9 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 10 *
michael@0 11 * Unless required by applicable law or agreed to in writing, software
michael@0 12 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 14 * See the License for the specific language governing permissions and
michael@0 15 * limitations under the License.
michael@0 16 */
michael@0 17
michael@0 18 #include <limits>
michael@0 19
michael@0 20 #include "pkix/pkix.h"
michael@0 21 #include "pkixcheck.h"
michael@0 22 #include "pkixder.h"
michael@0 23 #include "pkixutil.h"
michael@0 24 #include "secder.h"
michael@0 25
michael@0 26 namespace mozilla { namespace pkix {
michael@0 27
michael@0 28 Result
michael@0 29 CheckTimes(const CERTCertificate* cert, PRTime time)
michael@0 30 {
michael@0 31 PR_ASSERT(cert);
michael@0 32
michael@0 33 SECCertTimeValidity validity = CERT_CheckCertValidTimes(cert, time, false);
michael@0 34 if (validity != secCertTimeValid) {
michael@0 35 return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
michael@0 36 }
michael@0 37
michael@0 38 return Success;
michael@0 39 }
michael@0 40
michael@0 41 // 4.2.1.3. Key Usage (id-ce-keyUsage)
michael@0 42
michael@0 43 // As explained in the comment in CheckKeyUsage, bit 0 is the most significant
michael@0 44 // bit and bit 7 is the least significant bit.
michael@0 45 inline uint8_t KeyUsageToBitMask(KeyUsage keyUsage)
michael@0 46 {
michael@0 47 PR_ASSERT(keyUsage != KeyUsage::noParticularKeyUsageRequired);
michael@0 48 return 0x80u >> static_cast<uint8_t>(keyUsage);
michael@0 49 }
michael@0 50
michael@0 51 Result
michael@0 52 CheckKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedKeyUsage,
michael@0 53 KeyUsage requiredKeyUsageIfPresent)
michael@0 54 {
michael@0 55 if (!encodedKeyUsage) {
michael@0 56 // TODO(bug 970196): Reject certificates that are being used to verify
michael@0 57 // certificate signatures unless the certificate is a trust anchor, to
michael@0 58 // reduce the chances of an end-entity certificate being abused as a CA
michael@0 59 // certificate.
michael@0 60 // if (endEntityOrCA == EndEntityOrCA::MustBeCA && !isTrustAnchor) {
michael@0 61 // return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 62 // }
michael@0 63 //
michael@0 64 // TODO: Users may configure arbitrary certificates as trust anchors, not
michael@0 65 // just roots. We should only allow a certificate without a key usage to be
michael@0 66 // used as a CA when it is self-issued and self-signed.
michael@0 67 return Success;
michael@0 68 }
michael@0 69
michael@0 70 der::Input input;
michael@0 71 if (input.Init(encodedKeyUsage->data, encodedKeyUsage->len) != der::Success) {
michael@0 72 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 73 }
michael@0 74 der::Input value;
michael@0 75 if (der::ExpectTagAndGetValue(input, der::BIT_STRING, value) != der::Success) {
michael@0 76 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 77 }
michael@0 78
michael@0 79 uint8_t numberOfPaddingBits;
michael@0 80 if (value.Read(numberOfPaddingBits) != der::Success) {
michael@0 81 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 82 }
michael@0 83 if (numberOfPaddingBits > 7) {
michael@0 84 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 85 }
michael@0 86
michael@0 87 uint8_t bits;
michael@0 88 if (value.Read(bits) != der::Success) {
michael@0 89 // Reject empty bit masks.
michael@0 90 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 91 }
michael@0 92
michael@0 93 // The most significant bit is numbered 0 (digitalSignature) and the least
michael@0 94 // significant bit is numbered 7 (encipherOnly), and the padding is in the
michael@0 95 // least significant bits of the last byte. The numbering of bits in a byte
michael@0 96 // is backwards from how we usually interpret them.
michael@0 97 //
michael@0 98 // For example, let's say bits is encoded in one byte with of value 0xB0 and
michael@0 99 // numberOfPaddingBits == 4. Then, bits is 10110000 in binary:
michael@0 100 //
michael@0 101 // bit 0 bit 3
michael@0 102 // | |
michael@0 103 // v v
michael@0 104 // 10110000
michael@0 105 // ^^^^
michael@0 106 // |
michael@0 107 // 4 padding bits
michael@0 108 //
michael@0 109 // Since bits is the last byte, we have to consider the padding by ensuring
michael@0 110 // that the least significant 4 bits are all zero, since DER rules require
michael@0 111 // all padding bits to be zero. Then we have to look at the bit N bits to the
michael@0 112 // right of the most significant bit, where N is a value from the KeyUsage
michael@0 113 // enumeration.
michael@0 114 //
michael@0 115 // Let's say we're interested in the keyCertSign (5) bit. We'd need to look
michael@0 116 // at bit 5, which is zero, so keyCertSign is not asserted. (Since we check
michael@0 117 // that the padding is all zeros, it is OK to read from the padding bits.)
michael@0 118 //
michael@0 119 // Let's say we're interested in the digitalSignature (0) bit. We'd need to
michael@0 120 // look at the bit 0 (the most significant bit), which is set, so that means
michael@0 121 // digitalSignature is asserted. Similarly, keyEncipherment (2) and
michael@0 122 // dataEncipherment (3) are asserted.
michael@0 123 //
michael@0 124 // Note that since the KeyUsage enumeration is limited to values 0-7, we
michael@0 125 // only ever need to examine the first byte test for
michael@0 126 // requiredKeyUsageIfPresent.
michael@0 127
michael@0 128 if (requiredKeyUsageIfPresent != KeyUsage::noParticularKeyUsageRequired) {
michael@0 129 // Check that the required key usage bit is set.
michael@0 130 if ((bits & KeyUsageToBitMask(requiredKeyUsageIfPresent)) == 0) {
michael@0 131 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 132 }
michael@0 133 }
michael@0 134
michael@0 135 if (endEntityOrCA != EndEntityOrCA::MustBeCA) {
michael@0 136 // RFC 5280 says "The keyCertSign bit is asserted when the subject public
michael@0 137 // key is used for verifying signatures on public key certificates. If the
michael@0 138 // keyCertSign bit is asserted, then the cA bit in the basic constraints
michael@0 139 // extension (Section 4.2.1.9) MUST also be asserted."
michael@0 140 if ((bits & KeyUsageToBitMask(KeyUsage::keyCertSign)) != 0) {
michael@0 141 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 142 }
michael@0 143 }
michael@0 144
michael@0 145 // The padding applies to the last byte, so skip to the last byte.
michael@0 146 while (!value.AtEnd()) {
michael@0 147 if (value.Read(bits) != der::Success) {
michael@0 148 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 149 }
michael@0 150 }
michael@0 151
michael@0 152 // All of the padding bits must be zero, according to DER rules.
michael@0 153 uint8_t paddingMask = static_cast<uint8_t>((1 << numberOfPaddingBits) - 1);
michael@0 154 if ((bits & paddingMask) != 0) {
michael@0 155 return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
michael@0 156 }
michael@0 157
michael@0 158 return Success;
michael@0 159 }
michael@0 160
michael@0 161 // RFC5820 4.2.1.4. Certificate Policies
michael@0 162 //
michael@0 163 // "The user-initial-policy-set contains the special value any-policy if the
michael@0 164 // user is not concerned about certificate policy."
michael@0 165 Result
michael@0 166 CheckCertificatePolicies(BackCert& cert, EndEntityOrCA endEntityOrCA,
michael@0 167 bool isTrustAnchor, SECOidTag requiredPolicy)
michael@0 168 {
michael@0 169 if (requiredPolicy == SEC_OID_X509_ANY_POLICY) {
michael@0 170 return Success;
michael@0 171 }
michael@0 172
michael@0 173 // It is likely some callers will pass SEC_OID_UNKNOWN when they don't care,
michael@0 174 // instead of passing SEC_OID_X509_ANY_POLICY. Help them out by failing hard.
michael@0 175 if (requiredPolicy == SEC_OID_UNKNOWN) {
michael@0 176 PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
michael@0 177 return FatalError;
michael@0 178 }
michael@0 179
michael@0 180 // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when
michael@0 181 // inhibitAnyPolicy extension is present and we need to evaluate certificate
michael@0 182 // policies.
michael@0 183 if (cert.encodedInhibitAnyPolicy) {
michael@0 184 PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
michael@0 185 return RecoverableError;
michael@0 186 }
michael@0 187
michael@0 188 // The root CA certificate may omit the policies that it has been
michael@0 189 // trusted for, so we cannot require the policies to be present in those
michael@0 190 // certificates. Instead, the determination of which roots are trusted for
michael@0 191 // which policies is made by the TrustDomain's GetCertTrust method.
michael@0 192 if (isTrustAnchor && endEntityOrCA == MustBeCA) {
michael@0 193 return Success;
michael@0 194 }
michael@0 195
michael@0 196 if (!cert.encodedCertificatePolicies) {
michael@0 197 PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
michael@0 198 return RecoverableError;
michael@0 199 }
michael@0 200
michael@0 201 ScopedPtr<CERTCertificatePolicies, CERT_DestroyCertificatePoliciesExtension>
michael@0 202 policies(CERT_DecodeCertificatePoliciesExtension(
michael@0 203 cert.encodedCertificatePolicies));
michael@0 204 if (!policies) {
michael@0 205 return MapSECStatus(SECFailure);
michael@0 206 }
michael@0 207
michael@0 208 for (const CERTPolicyInfo* const* policyInfos = policies->policyInfos;
michael@0 209 *policyInfos; ++policyInfos) {
michael@0 210 if ((*policyInfos)->oid == requiredPolicy) {
michael@0 211 return Success;
michael@0 212 }
michael@0 213 // Intermediate certs are allowed to have the anyPolicy OID
michael@0 214 if (endEntityOrCA == MustBeCA &&
michael@0 215 (*policyInfos)->oid == SEC_OID_X509_ANY_POLICY) {
michael@0 216 return Success;
michael@0 217 }
michael@0 218 }
michael@0 219
michael@0 220 PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
michael@0 221 return RecoverableError;
michael@0 222 }
michael@0 223
michael@0 224 // BasicConstraints ::= SEQUENCE {
michael@0 225 // cA BOOLEAN DEFAULT FALSE,
michael@0 226 // pathLenConstraint INTEGER (0..MAX) OPTIONAL }
michael@0 227 der::Result
michael@0 228 DecodeBasicConstraints(const SECItem* encodedBasicConstraints,
michael@0 229 CERTBasicConstraints& basicConstraints)
michael@0 230 {
michael@0 231 PR_ASSERT(encodedBasicConstraints);
michael@0 232 if (!encodedBasicConstraints) {
michael@0 233 return der::Fail(SEC_ERROR_INVALID_ARGS);
michael@0 234 }
michael@0 235
michael@0 236 basicConstraints.isCA = false;
michael@0 237 basicConstraints.pathLenConstraint = 0;
michael@0 238
michael@0 239 der::Input input;
michael@0 240 if (input.Init(encodedBasicConstraints->data, encodedBasicConstraints->len)
michael@0 241 != der::Success) {
michael@0 242 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
michael@0 243 }
michael@0 244
michael@0 245 if (der::ExpectTagAndIgnoreLength(input, der::SEQUENCE) != der::Success) {
michael@0 246 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
michael@0 247 }
michael@0 248
michael@0 249 bool isCA = false;
michael@0 250 // TODO(bug 989518): cA is by default false. According to DER, default
michael@0 251 // values must not be explicitly encoded in a SEQUENCE. So, if this
michael@0 252 // value is present and false, it is an encoding error. However, Go Daddy
michael@0 253 // has issued many certificates with this improper encoding, so we can't
michael@0 254 // enforce this yet (hence passing true for allowInvalidExplicitEncoding
michael@0 255 // to der::OptionalBoolean).
michael@0 256 if (der::OptionalBoolean(input, true, isCA) != der::Success) {
michael@0 257 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
michael@0 258 }
michael@0 259 basicConstraints.isCA = isCA;
michael@0 260
michael@0 261 if (input.Peek(der::INTEGER)) {
michael@0 262 SECItem pathLenConstraintEncoded;
michael@0 263 if (der::Integer(input, pathLenConstraintEncoded) != der::Success) {
michael@0 264 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
michael@0 265 }
michael@0 266 long pathLenConstraint = DER_GetInteger(&pathLenConstraintEncoded);
michael@0 267 if (pathLenConstraint >= std::numeric_limits<int>::max() ||
michael@0 268 pathLenConstraint < 0) {
michael@0 269 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
michael@0 270 }
michael@0 271 basicConstraints.pathLenConstraint = static_cast<int>(pathLenConstraint);
michael@0 272 // TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT
michael@0 273 // be included (as per RFC 5280 section 4.2.1.9), but for compatibility
michael@0 274 // reasons, we don't check this for now.
michael@0 275 } else if (basicConstraints.isCA) {
michael@0 276 // If this is a CA but the path length is omitted, it is unlimited.
michael@0 277 basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
michael@0 278 }
michael@0 279
michael@0 280 if (der::End(input) != der::Success) {
michael@0 281 return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
michael@0 282 }
michael@0 283 return der::Success;
michael@0 284 }
michael@0 285
michael@0 286 // RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints)
michael@0 287 Result
michael@0 288 CheckBasicConstraints(const BackCert& cert,
michael@0 289 EndEntityOrCA endEntityOrCA,
michael@0 290 bool isTrustAnchor,
michael@0 291 unsigned int subCACount)
michael@0 292 {
michael@0 293 CERTBasicConstraints basicConstraints;
michael@0 294 if (cert.encodedBasicConstraints) {
michael@0 295 if (DecodeBasicConstraints(cert.encodedBasicConstraints,
michael@0 296 basicConstraints) != der::Success) {
michael@0 297 return RecoverableError;
michael@0 298 }
michael@0 299 } else {
michael@0 300 // Synthesize a non-CA basic constraints by default
michael@0 301 basicConstraints.isCA = false;
michael@0 302 basicConstraints.pathLenConstraint = 0;
michael@0 303
michael@0 304 // "If the basic constraints extension is not present in a version 3
michael@0 305 // certificate, or the extension is present but the cA boolean is not
michael@0 306 // asserted, then the certified public key MUST NOT be used to verify
michael@0 307 // certificate signatures."
michael@0 308 //
michael@0 309 // For compatibility, we must accept v1 trust anchors without basic
michael@0 310 // constraints as CAs.
michael@0 311 //
michael@0 312 // TODO: add check for self-signedness?
michael@0 313 if (endEntityOrCA == MustBeCA && isTrustAnchor) {
michael@0 314 const CERTCertificate* nssCert = cert.GetNSSCert();
michael@0 315 // We only allow trust anchor CA certs to omit the
michael@0 316 // basicConstraints extension if they are v1. v1 is encoded
michael@0 317 // implicitly.
michael@0 318 if (!nssCert->version.data && !nssCert->version.len) {
michael@0 319 basicConstraints.isCA = true;
michael@0 320 basicConstraints.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
michael@0 321 }
michael@0 322 }
michael@0 323 }
michael@0 324
michael@0 325 if (endEntityOrCA == MustBeEndEntity) {
michael@0 326 // CA certificates are not trusted as EE certs.
michael@0 327
michael@0 328 if (basicConstraints.isCA) {
michael@0 329 // XXX: We use SEC_ERROR_CA_CERT_INVALID here so we can distinguish
michael@0 330 // this error from other errors, given that NSS does not have a "CA cert
michael@0 331 // used as end-entity" error code since it doesn't have such a
michael@0 332 // prohibition. We should add such an error code and stop abusing
michael@0 333 // SEC_ERROR_CA_CERT_INVALID this way.
michael@0 334 //
michael@0 335 // Note, in particular, that this check prevents a delegated OCSP
michael@0 336 // response signing certificate with the CA bit from successfully
michael@0 337 // validating when we check it from pkixocsp.cpp, which is a good thing.
michael@0 338 //
michael@0 339 return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID);
michael@0 340 }
michael@0 341
michael@0 342 return Success;
michael@0 343 }
michael@0 344
michael@0 345 PORT_Assert(endEntityOrCA == MustBeCA);
michael@0 346
michael@0 347 // End-entity certificates are not allowed to act as CA certs.
michael@0 348 if (!basicConstraints.isCA) {
michael@0 349 return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID);
michael@0 350 }
michael@0 351
michael@0 352 if (basicConstraints.pathLenConstraint >= 0) {
michael@0 353 if (subCACount >
michael@0 354 static_cast<unsigned int>(basicConstraints.pathLenConstraint)) {
michael@0 355 return Fail(RecoverableError, SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
michael@0 356 }
michael@0 357 }
michael@0 358
michael@0 359 return Success;
michael@0 360 }
michael@0 361
michael@0 362 Result
michael@0 363 BackCert::GetConstrainedNames(/*out*/ const CERTGeneralName** result)
michael@0 364 {
michael@0 365 if (!constrainedNames) {
michael@0 366 if (!GetArena()) {
michael@0 367 return FatalError;
michael@0 368 }
michael@0 369
michael@0 370 constrainedNames =
michael@0 371 CERT_GetConstrainedCertificateNames(nssCert, arena.get(),
michael@0 372 cnOptions == IncludeCN);
michael@0 373 if (!constrainedNames) {
michael@0 374 return MapSECStatus(SECFailure);
michael@0 375 }
michael@0 376 }
michael@0 377
michael@0 378 *result = constrainedNames;
michael@0 379 return Success;
michael@0 380 }
michael@0 381
michael@0 382 // 4.2.1.10. Name Constraints
michael@0 383 Result
michael@0 384 CheckNameConstraints(BackCert& cert)
michael@0 385 {
michael@0 386 static const char constraintFranceGov[] =
michael@0 387 "\x30\x5D" /* sequence len 93*/
michael@0 388 "\xA0\x5B" /* element len 91 */
michael@0 389 "\x30\x05" /* sequence len 5 */
michael@0 390 "\x82\x03" /* entry len 3 */
michael@0 391 ".fr"
michael@0 392 "\x30\x05\x82\x03" /* sequence len 5, entry len 3 */
michael@0 393 ".gp"
michael@0 394 "\x30\x05\x82\x03"
michael@0 395 ".gf"
michael@0 396 "\x30\x05\x82\x03"
michael@0 397 ".mq"
michael@0 398 "\x30\x05\x82\x03"
michael@0 399 ".re"
michael@0 400 "\x30\x05\x82\x03"
michael@0 401 ".yt"
michael@0 402 "\x30\x05\x82\x03"
michael@0 403 ".pm"
michael@0 404 "\x30\x05\x82\x03"
michael@0 405 ".bl"
michael@0 406 "\x30\x05\x82\x03"
michael@0 407 ".mf"
michael@0 408 "\x30\x05\x82\x03"
michael@0 409 ".wf"
michael@0 410 "\x30\x05\x82\x03"
michael@0 411 ".pf"
michael@0 412 "\x30\x05\x82\x03"
michael@0 413 ".nc"
michael@0 414 "\x30\x05\x82\x03"
michael@0 415 ".tf";
michael@0 416
michael@0 417 /* The stringified value for the subject is:
michael@0 418 E=igca@sgdn.pm.gouv.fr,CN=IGC/A,OU=DCSSI,O=PM/SGDN,L=Paris,ST=France,C=FR
michael@0 419 */
michael@0 420 static const char rawANSSISubject[] =
michael@0 421 "\x30\x81\x85\x31\x0B\x30\x09\x06\x03\x55\x04"
michael@0 422 "\x06\x13\x02\x46\x52\x31\x0F\x30\x0D\x06\x03"
michael@0 423 "\x55\x04\x08\x13\x06\x46\x72\x61\x6E\x63\x65"
michael@0 424 "\x31\x0E\x30\x0C\x06\x03\x55\x04\x07\x13\x05"
michael@0 425 "\x50\x61\x72\x69\x73\x31\x10\x30\x0E\x06\x03"
michael@0 426 "\x55\x04\x0A\x13\x07\x50\x4D\x2F\x53\x47\x44"
michael@0 427 "\x4E\x31\x0E\x30\x0C\x06\x03\x55\x04\x0B\x13"
michael@0 428 "\x05\x44\x43\x53\x53\x49\x31\x0E\x30\x0C\x06"
michael@0 429 "\x03\x55\x04\x03\x13\x05\x49\x47\x43\x2F\x41"
michael@0 430 "\x31\x23\x30\x21\x06\x09\x2A\x86\x48\x86\xF7"
michael@0 431 "\x0D\x01\x09\x01\x16\x14\x69\x67\x63\x61\x40"
michael@0 432 "\x73\x67\x64\x6E\x2E\x70\x6D\x2E\x67\x6F\x75"
michael@0 433 "\x76\x2E\x66\x72";
michael@0 434
michael@0 435 const SECItem ANSSI_SUBJECT = {
michael@0 436 siBuffer,
michael@0 437 reinterpret_cast<uint8_t *>(const_cast<char *>(rawANSSISubject)),
michael@0 438 sizeof(rawANSSISubject) - 1
michael@0 439 };
michael@0 440
michael@0 441 const SECItem PERMIT_FRANCE_GOV_NC = {
michael@0 442 siBuffer,
michael@0 443 reinterpret_cast<uint8_t *>(const_cast<char *>(constraintFranceGov)),
michael@0 444 sizeof(constraintFranceGov) - 1
michael@0 445 };
michael@0 446
michael@0 447 const SECItem* nameConstraintsToUse = cert.encodedNameConstraints;
michael@0 448
michael@0 449 if (!nameConstraintsToUse) {
michael@0 450 if (SECITEM_ItemsAreEqual(&cert.GetNSSCert()->derSubject, &ANSSI_SUBJECT)) {
michael@0 451 nameConstraintsToUse = &PERMIT_FRANCE_GOV_NC;
michael@0 452 } else {
michael@0 453 return Success;
michael@0 454 }
michael@0 455 }
michael@0 456
michael@0 457 PLArenaPool* arena = cert.GetArena();
michael@0 458 if (!arena) {
michael@0 459 return FatalError;
michael@0 460 }
michael@0 461
michael@0 462 // Owned by arena
michael@0 463 const CERTNameConstraints* constraints =
michael@0 464 CERT_DecodeNameConstraintsExtension(arena, nameConstraintsToUse);
michael@0 465 if (!constraints) {
michael@0 466 return MapSECStatus(SECFailure);
michael@0 467 }
michael@0 468
michael@0 469 for (BackCert* prev = cert.childCert; prev; prev = prev->childCert) {
michael@0 470 const CERTGeneralName* names = nullptr;
michael@0 471 Result rv = prev->GetConstrainedNames(&names);
michael@0 472 if (rv != Success) {
michael@0 473 return rv;
michael@0 474 }
michael@0 475 PORT_Assert(names);
michael@0 476 CERTGeneralName* currentName = const_cast<CERTGeneralName*>(names);
michael@0 477 do {
michael@0 478 if (CERT_CheckNameSpace(arena, constraints, currentName) != SECSuccess) {
michael@0 479 // XXX: It seems like CERT_CheckNameSpace doesn't always call
michael@0 480 // PR_SetError when it fails. We set the error code here, though this
michael@0 481 // may be papering over some fatal errors. NSS's
michael@0 482 // cert_VerifyCertChainOld does something similar.
michael@0 483 PR_SetError(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, 0);
michael@0 484 return RecoverableError;
michael@0 485 }
michael@0 486 currentName = CERT_GetNextGeneralName(currentName);
michael@0 487 } while (currentName != names);
michael@0 488 }
michael@0 489
michael@0 490 return Success;
michael@0 491 }
michael@0 492
michael@0 493 // 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage)
michael@0 494 // 4.2.1.12. Extended Key Usage (id-ce-extKeyUsage)
michael@0 495 Result
michael@0 496 CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedEKUs,
michael@0 497 SECOidTag requiredEKU)
michael@0 498 {
michael@0 499 // TODO: Either do not allow anyExtendedKeyUsage to be passed as requiredEKU,
michael@0 500 // or require that callers pass anyExtendedKeyUsage instead of
michael@0 501 // SEC_OID_UNKNWON and disallow SEC_OID_UNKNWON.
michael@0 502
michael@0 503 // XXX: We're using SEC_ERROR_INADEQUATE_CERT_TYPE here so that callers can
michael@0 504 // distinguish EKU mismatch from KU mismatch from basic constraints mismatch.
michael@0 505 // We should probably add a new error code that is more clear for this type
michael@0 506 // of problem.
michael@0 507
michael@0 508 bool foundOCSPSigning = false;
michael@0 509
michael@0 510 if (encodedEKUs) {
michael@0 511 ScopedPtr<CERTOidSequence, CERT_DestroyOidSequence>
michael@0 512 seq(CERT_DecodeOidSequence(encodedEKUs));
michael@0 513 if (!seq) {
michael@0 514 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0);
michael@0 515 return RecoverableError;
michael@0 516 }
michael@0 517
michael@0 518 bool found = false;
michael@0 519
michael@0 520 // XXX: We allow duplicate entries.
michael@0 521 for (const SECItem* const* oids = seq->oids; oids && *oids; ++oids) {
michael@0 522 SECOidTag oidTag = SECOID_FindOIDTag(*oids);
michael@0 523 if (requiredEKU != SEC_OID_UNKNOWN && oidTag == requiredEKU) {
michael@0 524 found = true;
michael@0 525 } else {
michael@0 526 // Treat CA certs with step-up OID as also having SSL server type.
michael@0 527 // COMODO has issued certificates that require this behavior
michael@0 528 // that don't expire until June 2020!
michael@0 529 // TODO 982932: Limit this expection to old certificates
michael@0 530 if (endEntityOrCA == MustBeCA &&
michael@0 531 requiredEKU == SEC_OID_EXT_KEY_USAGE_SERVER_AUTH &&
michael@0 532 oidTag == SEC_OID_NS_KEY_USAGE_GOVT_APPROVED) {
michael@0 533 found = true;
michael@0 534 }
michael@0 535 }
michael@0 536 if (oidTag == SEC_OID_OCSP_RESPONDER) {
michael@0 537 foundOCSPSigning = true;
michael@0 538 }
michael@0 539 }
michael@0 540
michael@0 541 // If the EKU extension was included, then the required EKU must be in the
michael@0 542 // list.
michael@0 543 if (!found) {
michael@0 544 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0);
michael@0 545 return RecoverableError;
michael@0 546 }
michael@0 547 }
michael@0 548
michael@0 549 // pkixocsp.cpp depends on the following additional checks.
michael@0 550
michael@0 551 if (endEntityOrCA == MustBeEndEntity) {
michael@0 552 // When validating anything other than an delegated OCSP signing cert,
michael@0 553 // reject any cert that also claims to be an OCSP responder, because such
michael@0 554 // a cert does not make sense. For example, if an SSL certificate were to
michael@0 555 // assert id-kp-OCSPSigning then it could sign OCSP responses for itself,
michael@0 556 // if not for this check.
michael@0 557 // That said, we accept CA certificates with id-kp-OCSPSigning because
michael@0 558 // some CAs in Mozilla's CA program have issued such intermediate
michael@0 559 // certificates, and because some CAs have reported some Microsoft server
michael@0 560 // software wrongly requires CA certificates to have id-kp-OCSPSigning.
michael@0 561 // Allowing this exception does not cause any security issues because we
michael@0 562 // require delegated OCSP response signing certificates to be end-entity
michael@0 563 // certificates.
michael@0 564 if (foundOCSPSigning && requiredEKU != SEC_OID_OCSP_RESPONDER) {
michael@0 565 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0);
michael@0 566 return RecoverableError;
michael@0 567 }
michael@0 568 // http://tools.ietf.org/html/rfc6960#section-4.2.2.2:
michael@0 569 // "OCSP signing delegation SHALL be designated by the inclusion of
michael@0 570 // id-kp-OCSPSigning in an extended key usage certificate extension
michael@0 571 // included in the OCSP response signer's certificate."
michael@0 572 //
michael@0 573 // id-kp-OCSPSigning is the only EKU that isn't implicitly assumed when the
michael@0 574 // EKU extension is missing from an end-entity certificate. However, any CA
michael@0 575 // certificate can issue a delegated OCSP response signing certificate, so
michael@0 576 // we can't require the EKU be explicitly included for CA certificates.
michael@0 577 if (!foundOCSPSigning && requiredEKU == SEC_OID_OCSP_RESPONDER) {
michael@0 578 PR_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE, 0);
michael@0 579 return RecoverableError;
michael@0 580 }
michael@0 581 }
michael@0 582
michael@0 583 return Success;
michael@0 584 }
michael@0 585
michael@0 586 Result
michael@0 587 CheckIssuerIndependentProperties(TrustDomain& trustDomain,
michael@0 588 BackCert& cert,
michael@0 589 PRTime time,
michael@0 590 EndEntityOrCA endEntityOrCA,
michael@0 591 KeyUsage requiredKeyUsageIfPresent,
michael@0 592 SECOidTag requiredEKUIfPresent,
michael@0 593 SECOidTag requiredPolicy,
michael@0 594 unsigned int subCACount,
michael@0 595 /*optional out*/ TrustDomain::TrustLevel* trustLevelOut)
michael@0 596 {
michael@0 597 Result rv;
michael@0 598
michael@0 599 TrustDomain::TrustLevel trustLevel;
michael@0 600 rv = MapSECStatus(trustDomain.GetCertTrust(endEntityOrCA,
michael@0 601 requiredPolicy,
michael@0 602 cert.GetNSSCert(),
michael@0 603 &trustLevel));
michael@0 604 if (rv != Success) {
michael@0 605 return rv;
michael@0 606 }
michael@0 607 if (trustLevel == TrustDomain::ActivelyDistrusted) {
michael@0 608 PORT_SetError(SEC_ERROR_UNTRUSTED_CERT);
michael@0 609 return RecoverableError;
michael@0 610 }
michael@0 611 if (trustLevel != TrustDomain::TrustAnchor &&
michael@0 612 trustLevel != TrustDomain::InheritsTrust) {
michael@0 613 // The TrustDomain returned a trust level that we weren't expecting.
michael@0 614 PORT_SetError(PR_INVALID_STATE_ERROR);
michael@0 615 return FatalError;
michael@0 616 }
michael@0 617 if (trustLevelOut) {
michael@0 618 *trustLevelOut = trustLevel;
michael@0 619 }
michael@0 620
michael@0 621 bool isTrustAnchor = endEntityOrCA == MustBeCA &&
michael@0 622 trustLevel == TrustDomain::TrustAnchor;
michael@0 623
michael@0 624 PLArenaPool* arena = cert.GetArena();
michael@0 625 if (!arena) {
michael@0 626 return FatalError;
michael@0 627 }
michael@0 628
michael@0 629 // 4.2.1.1. Authority Key Identifier is ignored (see bug 965136).
michael@0 630
michael@0 631 // 4.2.1.2. Subject Key Identifier is ignored (see bug 965136).
michael@0 632
michael@0 633 // 4.2.1.3. Key Usage
michael@0 634 rv = CheckKeyUsage(endEntityOrCA, cert.encodedKeyUsage,
michael@0 635 requiredKeyUsageIfPresent);
michael@0 636 if (rv != Success) {
michael@0 637 return rv;
michael@0 638 }
michael@0 639
michael@0 640 // 4.2.1.4. Certificate Policies
michael@0 641 rv = CheckCertificatePolicies(cert, endEntityOrCA, isTrustAnchor,
michael@0 642 requiredPolicy);
michael@0 643 if (rv != Success) {
michael@0 644 return rv;
michael@0 645 }
michael@0 646
michael@0 647 // 4.2.1.5. Policy Mappings are not supported; see the documentation about
michael@0 648 // policy enforcement in pkix.h.
michael@0 649
michael@0 650 // 4.2.1.6. Subject Alternative Name dealt with during name constraint
michael@0 651 // checking and during name verification (CERT_VerifyCertName).
michael@0 652
michael@0 653 // 4.2.1.7. Issuer Alternative Name is not something that needs checking.
michael@0 654
michael@0 655 // 4.2.1.8. Subject Directory Attributes is not something that needs
michael@0 656 // checking.
michael@0 657
michael@0 658 // 4.2.1.9. Basic Constraints.
michael@0 659 rv = CheckBasicConstraints(cert, endEntityOrCA, isTrustAnchor, subCACount);
michael@0 660 if (rv != Success) {
michael@0 661 return rv;
michael@0 662 }
michael@0 663
michael@0 664 // 4.2.1.10. Name Constraints is dealt with in during path building.
michael@0 665
michael@0 666 // 4.2.1.11. Policy Constraints are implicitly supported; see the
michael@0 667 // documentation about policy enforcement in pkix.h.
michael@0 668
michael@0 669 // 4.2.1.12. Extended Key Usage
michael@0 670 rv = CheckExtendedKeyUsage(endEntityOrCA, cert.encodedExtendedKeyUsage,
michael@0 671 requiredEKUIfPresent);
michael@0 672 if (rv != Success) {
michael@0 673 return rv;
michael@0 674 }
michael@0 675
michael@0 676 // 4.2.1.13. CRL Distribution Points is not supported, though the
michael@0 677 // TrustDomain's CheckRevocation method may parse it and process it
michael@0 678 // on its own.
michael@0 679
michael@0 680 // 4.2.1.14. Inhibit anyPolicy is implicitly supported; see the documentation
michael@0 681 // about policy enforcement in pkix.h.
michael@0 682
michael@0 683 // IMPORTANT: This check must come after the other checks in order for error
michael@0 684 // ranking to work correctly.
michael@0 685 rv = CheckTimes(cert.GetNSSCert(), time);
michael@0 686 if (rv != Success) {
michael@0 687 return rv;
michael@0 688 }
michael@0 689
michael@0 690 return Success;
michael@0 691 }
michael@0 692
michael@0 693 } } // namespace mozilla::pkix

mercurial