security/pkix/lib/pkixcheck.cpp

changeset 0
6474c204b198
     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

mercurial