pkixcert.cpp 11 KB

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