LCOV - code coverage report
Current view: top level - security/pkix/lib - pkixcert.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 98 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This code is made available to you under your choice of the following sets
       4             :  * of licensing terms:
       5             :  */
       6             : /* This Source Code Form is subject to the terms of the Mozilla Public
       7             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       8             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       9             :  */
      10             : /* Copyright 2014 Mozilla Contributors
      11             :  *
      12             :  * Licensed under the Apache License, Version 2.0 (the "License");
      13             :  * you may not use this file except in compliance with the License.
      14             :  * You may obtain a copy of the License at
      15             :  *
      16             :  *     http://www.apache.org/licenses/LICENSE-2.0
      17             :  *
      18             :  * Unless required by applicable law or agreed to in writing, software
      19             :  * distributed under the License is distributed on an "AS IS" BASIS,
      20             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      21             :  * See the License for the specific language governing permissions and
      22             :  * limitations under the License.
      23             :  */
      24             : 
      25             : #include "pkixutil.h"
      26             : 
      27             : namespace mozilla { namespace pkix {
      28             : 
      29             : Result
      30           0 : BackCert::Init()
      31             : {
      32             :   Result rv;
      33             : 
      34             :   // Certificate  ::=  SEQUENCE  {
      35             :   //         tbsCertificate       TBSCertificate,
      36             :   //         signatureAlgorithm   AlgorithmIdentifier,
      37             :   //         signatureValue       BIT STRING  }
      38             : 
      39           0 :   Reader tbsCertificate;
      40             : 
      41             :   // The scope of |input| and |certificate| are limited to this block so we
      42             :   // don't accidentally confuse them for tbsCertificate later.
      43             :   {
      44           0 :     Reader certificate;
      45           0 :     rv = der::ExpectTagAndGetValueAtEnd(der, der::SEQUENCE, certificate);
      46           0 :     if (rv != Success) {
      47           0 :       return rv;
      48             :     }
      49           0 :     rv = der::SignedData(certificate, tbsCertificate, signedData);
      50           0 :     if (rv != Success) {
      51           0 :       return rv;
      52             :     }
      53           0 :     rv = der::End(certificate);
      54           0 :     if (rv != Success) {
      55           0 :       return rv;
      56             :     }
      57             :   }
      58             : 
      59             :   // TBSCertificate  ::=  SEQUENCE  {
      60             :   //      version         [0]  EXPLICIT Version DEFAULT v1,
      61             :   //      serialNumber         CertificateSerialNumber,
      62             :   //      signature            AlgorithmIdentifier,
      63             :   //      issuer               Name,
      64             :   //      validity             Validity,
      65             :   //      subject              Name,
      66             :   //      subjectPublicKeyInfo SubjectPublicKeyInfo,
      67             :   //      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
      68             :   //                           -- If present, version MUST be v2 or v3
      69             :   //      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
      70             :   //                           -- If present, version MUST be v2 or v3
      71             :   //      extensions      [3]  EXPLICIT Extensions OPTIONAL
      72             :   //                           -- If present, version MUST be v3
      73             :   //      }
      74           0 :   rv = der::OptionalVersion(tbsCertificate, version);
      75           0 :   if (rv != Success) {
      76           0 :     return rv;
      77             :   }
      78           0 :   rv = der::CertificateSerialNumber(tbsCertificate, serialNumber);
      79           0 :   if (rv != Success) {
      80           0 :     return rv;
      81             :   }
      82           0 :   rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, signature);
      83           0 :   if (rv != Success) {
      84           0 :     return rv;
      85             :   }
      86           0 :   rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, issuer);
      87           0 :   if (rv != Success) {
      88           0 :     return rv;
      89             :   }
      90           0 :   rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, validity);
      91           0 :   if (rv != Success) {
      92           0 :     return rv;
      93             :   }
      94             :   // TODO(bug XXXXXXX): We rely on the the caller of mozilla::pkix to validate
      95             :   // that the name is syntactically valid, if they care. In Gecko we do this
      96             :   // implicitly by parsing the certificate into a CERTCertificate object.
      97             :   // Instead of relying on the caller to do this, we should do it ourselves.
      98           0 :   rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, subject);
      99           0 :   if (rv != Success) {
     100           0 :     return rv;
     101             :   }
     102           0 :   rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE,
     103           0 :                                subjectPublicKeyInfo);
     104           0 :   if (rv != Success) {
     105           0 :     return rv;
     106             :   }
     107             : 
     108             :   static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED;
     109             : 
     110             :   // According to RFC 5280, all fields below this line are forbidden for
     111             :   // certificate versions less than v3.  However, for compatibility reasons,
     112             :   // we parse v1/v2 certificates in the same way as v3 certificates.  So if
     113             :   // these fields appear in a v1 certificate, they will be used.
     114             : 
     115             :   // Ignore issuerUniqueID if present.
     116           0 :   if (tbsCertificate.Peek(CSC | 1)) {
     117           0 :     rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 1);
     118           0 :     if (rv != Success) {
     119           0 :       return rv;
     120             :     }
     121             :   }
     122             : 
     123             :   // Ignore subjectUniqueID if present.
     124           0 :   if (tbsCertificate.Peek(CSC | 2)) {
     125           0 :     rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 2);
     126           0 :     if (rv != Success) {
     127           0 :       return rv;
     128             :     }
     129             :   }
     130             : 
     131           0 :   rv = der::OptionalExtensions(
     132             :          tbsCertificate, CSC | 3,
     133             :          [this](Reader& extnID, const Input& extnValue, bool critical,
     134           0 :                 /*out*/ bool& understood) {
     135           0 :            return RememberExtension(extnID, extnValue, critical, understood);
     136           0 :          });
     137           0 :   if (rv != Success) {
     138           0 :     return rv;
     139             :   }
     140             : 
     141             :   // The Netscape Certificate Type extension is an obsolete
     142             :   // Netscape-proprietary mechanism that we ignore in favor of the standard
     143             :   // extensions. However, some CAs have issued certificates with the Netscape
     144             :   // Cert Type extension marked critical. Thus, for compatibility reasons, we
     145             :   // "understand" this extension by ignoring it when it is not critical, and
     146             :   // by ensuring that the equivalent standardized extensions are present when
     147             :   // it is marked critical, based on the assumption that the information in
     148             :   // the Netscape Cert Type extension is consistent with the information in
     149             :   // the standard extensions.
     150             :   //
     151             :   // Here is a mapping between the Netscape Cert Type extension and the
     152             :   // standard extensions:
     153             :   //
     154             :   // Netscape Cert Type  |  BasicConstraints.cA  |  Extended Key Usage
     155             :   // --------------------+-----------------------+----------------------
     156             :   // SSL Server          |  false                |  id_kp_serverAuth
     157             :   // SSL Client          |  false                |  id_kp_clientAuth
     158             :   // S/MIME Client       |  false                |  id_kp_emailProtection
     159             :   // Object Signing      |  false                |  id_kp_codeSigning
     160             :   // SSL Server CA       |  true                 |  id_pk_serverAuth
     161             :   // SSL Client CA       |  true                 |  id_kp_clientAuth
     162             :   // S/MIME CA           |  true                 |  id_kp_emailProtection
     163             :   // Object Signing CA   |  true                 |  id_kp_codeSigning
     164           0 :   if (criticalNetscapeCertificateType.GetLength() > 0 &&
     165           0 :       (basicConstraints.GetLength() == 0 || extKeyUsage.GetLength() == 0)) {
     166           0 :     return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
     167             :   }
     168             : 
     169           0 :   return der::End(tbsCertificate);
     170             : }
     171             : 
     172             : Result
     173           0 : BackCert::RememberExtension(Reader& extnID, Input extnValue,
     174             :                             bool critical, /*out*/ bool& understood)
     175             : {
     176           0 :   understood = false;
     177             : 
     178             :   // python DottedOIDToCode.py id-ce-keyUsage 2.5.29.15
     179             :   static const uint8_t id_ce_keyUsage[] = {
     180             :     0x55, 0x1d, 0x0f
     181             :   };
     182             :   // python DottedOIDToCode.py id-ce-subjectAltName 2.5.29.17
     183             :   static const uint8_t id_ce_subjectAltName[] = {
     184             :     0x55, 0x1d, 0x11
     185             :   };
     186             :   // python DottedOIDToCode.py id-ce-basicConstraints 2.5.29.19
     187             :   static const uint8_t id_ce_basicConstraints[] = {
     188             :     0x55, 0x1d, 0x13
     189             :   };
     190             :   // python DottedOIDToCode.py id-ce-nameConstraints 2.5.29.30
     191             :   static const uint8_t id_ce_nameConstraints[] = {
     192             :     0x55, 0x1d, 0x1e
     193             :   };
     194             :   // python DottedOIDToCode.py id-ce-certificatePolicies 2.5.29.32
     195             :   static const uint8_t id_ce_certificatePolicies[] = {
     196             :     0x55, 0x1d, 0x20
     197             :   };
     198             :   // python DottedOIDToCode.py id-ce-policyConstraints 2.5.29.36
     199             :   static const uint8_t id_ce_policyConstraints[] = {
     200             :     0x55, 0x1d, 0x24
     201             :   };
     202             :   // python DottedOIDToCode.py id-ce-extKeyUsage 2.5.29.37
     203             :   static const uint8_t id_ce_extKeyUsage[] = {
     204             :     0x55, 0x1d, 0x25
     205             :   };
     206             :   // python DottedOIDToCode.py id-ce-inhibitAnyPolicy 2.5.29.54
     207             :   static const uint8_t id_ce_inhibitAnyPolicy[] = {
     208             :     0x55, 0x1d, 0x36
     209             :   };
     210             :   // python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1
     211             :   static const uint8_t id_pe_authorityInfoAccess[] = {
     212             :     0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
     213             :   };
     214             :   // python DottedOIDToCode.py id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
     215             :   static const uint8_t id_pkix_ocsp_nocheck[] = {
     216             :     0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05
     217             :   };
     218             :   // python DottedOIDToCode.py Netscape-certificate-type 2.16.840.1.113730.1.1
     219             :   static const uint8_t Netscape_certificate_type[] = {
     220             :     0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x01, 0x01
     221             :   };
     222             :   // python DottedOIDToCode.py id-pe-tlsfeature 1.3.6.1.5.5.7.1.24
     223             :   static const uint8_t id_pe_tlsfeature[] = {
     224             :     0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x18
     225             :   };
     226             :   // python DottedOIDToCode.py id-embeddedSctList 1.3.6.1.4.1.11129.2.4.2
     227             :   // See Section 3.3 of RFC 6962.
     228             :   static const uint8_t id_embeddedSctList[] = {
     229             :     0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x02
     230             :   };
     231             : 
     232           0 :   Input* out = nullptr;
     233             : 
     234             :   // We already enforce the maximum possible constraints for policies so we
     235             :   // can safely ignore even critical policy constraint extensions.
     236             :   //
     237             :   // XXX: Doing it this way won't allow us to detect duplicate
     238             :   // policyConstraints extensions, but that's OK because (and only because) we
     239             :   // ignore the extension.
     240           0 :   Input dummyPolicyConstraints;
     241             : 
     242             :   // We don't need to save the contents of this extension if it is present. We
     243             :   // just need to handle its presence (it is essentially ignored right now).
     244           0 :   Input dummyOCSPNocheck;
     245             : 
     246             :   // For compatibility reasons, for some extensions we have to allow empty
     247             :   // extension values. This would normally interfere with our duplicate
     248             :   // extension checking code. However, as long as the extensions we allow to
     249             :   // have empty values are also the ones we implicitly allow duplicates of,
     250             :   // this will work fine.
     251           0 :   bool emptyValueAllowed = false;
     252             : 
     253             :   // RFC says "Conforming CAs MUST mark this extension as non-critical" for
     254             :   // both authorityKeyIdentifier and subjectKeyIdentifier, and we do not use
     255             :   // them for anything, so we totally ignore them here.
     256             : 
     257           0 :   if (extnID.MatchRest(id_ce_keyUsage)) {
     258           0 :     out = &keyUsage;
     259           0 :   } else if (extnID.MatchRest(id_ce_subjectAltName)) {
     260           0 :     out = &subjectAltName;
     261           0 :   } else if (extnID.MatchRest(id_ce_basicConstraints)) {
     262           0 :     out = &basicConstraints;
     263           0 :   } else if (extnID.MatchRest(id_ce_nameConstraints)) {
     264           0 :     out = &nameConstraints;
     265           0 :   } else if (extnID.MatchRest(id_ce_certificatePolicies)) {
     266           0 :     out = &certificatePolicies;
     267           0 :   } else if (extnID.MatchRest(id_ce_policyConstraints)) {
     268           0 :     out = &dummyPolicyConstraints;
     269           0 :   } else if (extnID.MatchRest(id_ce_extKeyUsage)) {
     270           0 :     out = &extKeyUsage;
     271           0 :   } else if (extnID.MatchRest(id_ce_inhibitAnyPolicy)) {
     272           0 :     out = &inhibitAnyPolicy;
     273           0 :   } else if (extnID.MatchRest(id_pe_authorityInfoAccess)) {
     274           0 :     out = &authorityInfoAccess;
     275           0 :   } else if (extnID.MatchRest(id_pe_tlsfeature)) {
     276           0 :     out = &requiredTLSFeatures;
     277           0 :   } else if (extnID.MatchRest(id_embeddedSctList)) {
     278           0 :     out = &signedCertificateTimestamps;
     279           0 :   } else if (extnID.MatchRest(id_pkix_ocsp_nocheck) && critical) {
     280             :     // We need to make sure we don't reject delegated OCSP response signing
     281             :     // certificates that contain the id-pkix-ocsp-nocheck extension marked as
     282             :     // critical when validating OCSP responses. Without this, an application
     283             :     // that implements soft-fail OCSP might ignore a valid Revoked or Unknown
     284             :     // response, and an application that implements hard-fail OCSP might fail
     285             :     // to connect to a server given a valid Good response.
     286           0 :     out = &dummyOCSPNocheck;
     287             :     // We allow this extension to have an empty value.
     288             :     // See http://comments.gmane.org/gmane.ietf.x509/30947
     289           0 :     emptyValueAllowed = true;
     290           0 :   } else if (extnID.MatchRest(Netscape_certificate_type) && critical) {
     291           0 :     out = &criticalNetscapeCertificateType;
     292             :   }
     293             : 
     294           0 :   if (out) {
     295             :     // Don't allow an empty value for any extension we understand. This way, we
     296             :     // can test out->GetLength() != 0 or out->Init() to check for duplicates.
     297           0 :     if (extnValue.GetLength() == 0 && !emptyValueAllowed) {
     298           0 :       return Result::ERROR_EXTENSION_VALUE_INVALID;
     299             :     }
     300           0 :     if (out->Init(extnValue) != Success) {
     301             :       // Duplicate extension
     302           0 :       return Result::ERROR_EXTENSION_VALUE_INVALID;
     303             :     }
     304           0 :     understood = true;
     305             :   }
     306             : 
     307           0 :   return Success;
     308             : }
     309             : 
     310             : Result
     311           0 : ExtractSignedCertificateTimestampListFromExtension(Input extnValue,
     312             :                                                    Input& sctList)
     313             : {
     314           0 :   Reader decodedValue;
     315             :   Result rv = der::ExpectTagAndGetValueAtEnd(extnValue, der::OCTET_STRING,
     316           0 :                                              decodedValue);
     317           0 :   if (rv != Success) {
     318           0 :     return rv;
     319             :   }
     320           0 :   return decodedValue.SkipToEnd(sctList);
     321             : }
     322             : 
     323             : } } // namespace mozilla::pkix

Generated by: LCOV version 1.13