revocation_builder.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "net/test/revocation_builder.h"
  5. #include "base/hash/sha1.h"
  6. #include "base/strings/string_piece.h"
  7. #include "base/strings/string_util.h"
  8. #include "net/cert/asn1_util.h"
  9. #include "net/cert/x509_util.h"
  10. #include "net/der/encode_values.h"
  11. #include "net/der/input.h"
  12. #include "net/test/cert_builder.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. #include "third_party/boringssl/src/include/openssl/bytestring.h"
  15. #include "third_party/boringssl/src/include/openssl/mem.h"
  16. namespace net {
  17. namespace {
  18. std::string Sha1() {
  19. // SEQUENCE { OBJECT_IDENTIFIER { 1.3.14.3.2.26 } }
  20. const uint8_t kSHA1[] = {0x30, 0x07, 0x06, 0x05, 0x2b,
  21. 0x0e, 0x03, 0x02, 0x1a};
  22. return std::string(std::begin(kSHA1), std::end(kSHA1));
  23. }
  24. // Adds bytes (specified as a StringPiece) to the given CBB.
  25. // The argument ordering follows the boringssl CBB_* api style.
  26. bool CBBAddBytes(CBB* cbb, base::StringPiece bytes) {
  27. return CBB_add_bytes(cbb, reinterpret_cast<const uint8_t*>(bytes.data()),
  28. bytes.size());
  29. }
  30. // Adds bytes (from fixed size array) to the given CBB.
  31. // The argument ordering follows the boringssl CBB_* api style.
  32. template <size_t N>
  33. bool CBBAddBytes(CBB* cbb, const uint8_t (&data)[N]) {
  34. return CBB_add_bytes(cbb, data, N);
  35. }
  36. // Adds a GeneralizedTime value to the given CBB.
  37. // The argument ordering follows the boringssl CBB_* api style.
  38. bool CBBAddGeneralizedTime(CBB* cbb, const base::Time& time) {
  39. der::GeneralizedTime generalized_time;
  40. if (!der::EncodeTimeAsGeneralizedTime(time, &generalized_time))
  41. return false;
  42. CBB time_cbb;
  43. uint8_t out[der::kGeneralizedTimeLength];
  44. if (!der::EncodeGeneralizedTime(generalized_time, out) ||
  45. !CBB_add_asn1(cbb, &time_cbb, CBS_ASN1_GENERALIZEDTIME) ||
  46. !CBBAddBytes(&time_cbb, out) || !CBB_flush(cbb))
  47. return false;
  48. return true;
  49. }
  50. // Finalizes the CBB to a std::string.
  51. std::string FinishCBB(CBB* cbb) {
  52. size_t cbb_len;
  53. uint8_t* cbb_bytes;
  54. if (!CBB_finish(cbb, &cbb_bytes, &cbb_len)) {
  55. ADD_FAILURE() << "CBB_finish() failed";
  56. return std::string();
  57. }
  58. bssl::UniquePtr<uint8_t> delete_bytes(cbb_bytes);
  59. return std::string(reinterpret_cast<char*>(cbb_bytes), cbb_len);
  60. }
  61. std::string PKeyToSPK(const EVP_PKEY* pkey) {
  62. bssl::ScopedCBB cbb;
  63. if (!CBB_init(cbb.get(), 64) || !EVP_marshal_public_key(cbb.get(), pkey)) {
  64. ADD_FAILURE();
  65. return std::string();
  66. }
  67. std::string spki = FinishCBB(cbb.get());
  68. base::StringPiece spk;
  69. if (!asn1::ExtractSubjectPublicKeyFromSPKI(spki, &spk)) {
  70. ADD_FAILURE();
  71. return std::string();
  72. }
  73. // ExtractSubjectPublicKeyFromSPKI() includes the unused bit count. For this
  74. // application, the unused bit count must be zero, and is not included in the
  75. // result.
  76. if (!base::StartsWith(spk, "\0")) {
  77. ADD_FAILURE();
  78. return std::string();
  79. }
  80. spk.remove_prefix(1);
  81. return std::string(spk);
  82. }
  83. // Returns a DER-encoded OCSPResponse with the given |response_status|.
  84. // |response_type| and |response| are optional and may be empty.
  85. std::string EncodeOCSPResponse(OCSPResponse::ResponseStatus response_status,
  86. der::Input response_type,
  87. std::string response) {
  88. // RFC 6960 section 4.2.1:
  89. //
  90. // OCSPResponse ::= SEQUENCE {
  91. // responseStatus OCSPResponseStatus,
  92. // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
  93. //
  94. // OCSPResponseStatus ::= ENUMERATED {
  95. // successful (0), -- Response has valid confirmations
  96. // malformedRequest (1), -- Illegal confirmation request
  97. // internalError (2), -- Internal error in issuer
  98. // tryLater (3), -- Try again later
  99. // -- (4) is not used
  100. // sigRequired (5), -- Must sign the request
  101. // unauthorized (6) -- Request unauthorized
  102. // }
  103. //
  104. // The value for responseBytes consists of an OBJECT IDENTIFIER and a
  105. // response syntax identified by that OID encoded as an OCTET STRING.
  106. //
  107. // ResponseBytes ::= SEQUENCE {
  108. // responseType OBJECT IDENTIFIER,
  109. // response OCTET STRING }
  110. bssl::ScopedCBB cbb;
  111. CBB ocsp_response, ocsp_response_status, ocsp_response_bytes,
  112. ocsp_response_bytes_sequence, ocsp_response_type,
  113. ocsp_response_octet_string;
  114. if (!CBB_init(cbb.get(), 64 + response_type.Length() + response.size()) ||
  115. !CBB_add_asn1(cbb.get(), &ocsp_response, CBS_ASN1_SEQUENCE) ||
  116. !CBB_add_asn1(&ocsp_response, &ocsp_response_status,
  117. CBS_ASN1_ENUMERATED) ||
  118. !CBB_add_u8(&ocsp_response_status,
  119. static_cast<uint8_t>(response_status))) {
  120. ADD_FAILURE();
  121. return std::string();
  122. }
  123. if (response_type.Length()) {
  124. if (!CBB_add_asn1(&ocsp_response, &ocsp_response_bytes,
  125. CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
  126. !CBB_add_asn1(&ocsp_response_bytes, &ocsp_response_bytes_sequence,
  127. CBS_ASN1_SEQUENCE) ||
  128. !CBB_add_asn1(&ocsp_response_bytes_sequence, &ocsp_response_type,
  129. CBS_ASN1_OBJECT) ||
  130. !CBBAddBytes(&ocsp_response_type, response_type.AsStringPiece()) ||
  131. !CBB_add_asn1(&ocsp_response_bytes_sequence,
  132. &ocsp_response_octet_string, CBS_ASN1_OCTETSTRING) ||
  133. !CBBAddBytes(&ocsp_response_octet_string, response)) {
  134. ADD_FAILURE();
  135. return std::string();
  136. }
  137. }
  138. return FinishCBB(cbb.get());
  139. }
  140. // Adds a DER-encoded OCSP SingleResponse to |responses_cbb|.
  141. // |issuer_name_hash| and |issuer_key_hash| should be binary SHA1 hashes.
  142. bool AddOCSPSingleResponse(CBB* responses_cbb,
  143. const OCSPBuilderSingleResponse& response,
  144. const std::string& issuer_name_hash,
  145. const std::string& issuer_key_hash) {
  146. // RFC 6960 section 4.2.1:
  147. //
  148. // SingleResponse ::= SEQUENCE {
  149. // certID CertID,
  150. // certStatus CertStatus,
  151. // thisUpdate GeneralizedTime,
  152. // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
  153. // singleExtensions [1] EXPLICIT Extensions OPTIONAL }
  154. //
  155. // CertStatus ::= CHOICE {
  156. // good [0] IMPLICIT NULL,
  157. // revoked [1] IMPLICIT RevokedInfo,
  158. // unknown [2] IMPLICIT UnknownInfo }
  159. //
  160. // RevokedInfo ::= SEQUENCE {
  161. // revocationTime GeneralizedTime,
  162. // revocationReason [0] EXPLICIT CRLReason OPTIONAL }
  163. //
  164. // UnknownInfo ::= NULL
  165. //
  166. // RFC 6960 section 4.1.1:
  167. // CertID ::= SEQUENCE {
  168. // hashAlgorithm AlgorithmIdentifier,
  169. // issuerNameHash OCTET STRING, -- Hash of issuer's DN
  170. // issuerKeyHash OCTET STRING, -- Hash of issuer's public key
  171. // serialNumber CertificateSerialNumber }
  172. //
  173. // The contents of CertID include the following fields:
  174. //
  175. // o hashAlgorithm is the hash algorithm used to generate the
  176. // issuerNameHash and issuerKeyHash values.
  177. //
  178. // o issuerNameHash is the hash of the issuer's distinguished name
  179. // (DN). The hash shall be calculated over the DER encoding of the
  180. // issuer's name field in the certificate being checked.
  181. //
  182. // o issuerKeyHash is the hash of the issuer's public key. The hash
  183. // shall be calculated over the value (excluding tag and length) of
  184. // the subject public key field in the issuer's certificate.
  185. //
  186. // o serialNumber is the serial number of the certificate for which
  187. // status is being requested.
  188. CBB single_response, issuer_name_hash_cbb, issuer_key_hash_cbb, cert_id;
  189. if (!CBB_add_asn1(responses_cbb, &single_response, CBS_ASN1_SEQUENCE) ||
  190. !CBB_add_asn1(&single_response, &cert_id, CBS_ASN1_SEQUENCE) ||
  191. !CBBAddBytes(&cert_id, Sha1()) ||
  192. !CBB_add_asn1(&cert_id, &issuer_name_hash_cbb, CBS_ASN1_OCTETSTRING) ||
  193. !CBBAddBytes(&issuer_name_hash_cbb, issuer_name_hash) ||
  194. !CBB_add_asn1(&cert_id, &issuer_key_hash_cbb, CBS_ASN1_OCTETSTRING) ||
  195. !CBBAddBytes(&issuer_key_hash_cbb, issuer_key_hash) ||
  196. !CBB_add_asn1_uint64(&cert_id, response.serial)) {
  197. ADD_FAILURE();
  198. return false;
  199. }
  200. unsigned int cert_status_tag_number;
  201. switch (response.cert_status) {
  202. case OCSPRevocationStatus::GOOD:
  203. cert_status_tag_number = CBS_ASN1_CONTEXT_SPECIFIC | 0;
  204. break;
  205. case OCSPRevocationStatus::REVOKED:
  206. cert_status_tag_number =
  207. CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1;
  208. break;
  209. case OCSPRevocationStatus::UNKNOWN:
  210. cert_status_tag_number = CBS_ASN1_CONTEXT_SPECIFIC | 2;
  211. break;
  212. }
  213. CBB cert_status_cbb;
  214. if (!CBB_add_asn1(&single_response, &cert_status_cbb,
  215. cert_status_tag_number)) {
  216. ADD_FAILURE();
  217. return false;
  218. }
  219. if (response.cert_status == OCSPRevocationStatus::REVOKED &&
  220. !CBBAddGeneralizedTime(&cert_status_cbb, response.revocation_time)) {
  221. ADD_FAILURE();
  222. return false;
  223. }
  224. CBB next_update_cbb;
  225. if (!CBBAddGeneralizedTime(&single_response, response.this_update) ||
  226. !CBB_add_asn1(&single_response, &next_update_cbb,
  227. CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
  228. !CBBAddGeneralizedTime(&next_update_cbb, response.next_update)) {
  229. ADD_FAILURE();
  230. return false;
  231. }
  232. return CBB_flush(responses_cbb);
  233. }
  234. } // namespace
  235. std::string BuildOCSPResponseError(
  236. OCSPResponse::ResponseStatus response_status) {
  237. DCHECK_NE(response_status, OCSPResponse::ResponseStatus::SUCCESSFUL);
  238. return EncodeOCSPResponse(response_status, der::Input(), std::string());
  239. }
  240. std::string BuildOCSPResponse(
  241. const std::string& responder_subject,
  242. EVP_PKEY* responder_key,
  243. base::Time produced_at,
  244. const std::vector<OCSPBuilderSingleResponse>& responses) {
  245. std::string responder_name_hash = base::SHA1HashString(responder_subject);
  246. std::string responder_key_hash =
  247. base::SHA1HashString(PKeyToSPK(responder_key));
  248. // RFC 6960 section 4.2.1:
  249. //
  250. // ResponseData ::= SEQUENCE {
  251. // version [0] EXPLICIT Version DEFAULT v1,
  252. // responderID ResponderID,
  253. // producedAt GeneralizedTime,
  254. // responses SEQUENCE OF SingleResponse,
  255. // responseExtensions [1] EXPLICIT Extensions OPTIONAL }
  256. //
  257. // ResponderID ::= CHOICE {
  258. // byName [1] Name,
  259. // byKey [2] KeyHash }
  260. //
  261. // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
  262. // (excluding the tag and length fields)
  263. bssl::ScopedCBB tbs_cbb;
  264. CBB response_data, responder_id, responder_id_by_key, responses_cbb;
  265. if (!CBB_init(tbs_cbb.get(), 64) ||
  266. !CBB_add_asn1(tbs_cbb.get(), &response_data, CBS_ASN1_SEQUENCE) ||
  267. // Version is the default v1, so it is not encoded.
  268. !CBB_add_asn1(&response_data, &responder_id,
  269. CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 2) ||
  270. !CBB_add_asn1(&responder_id, &responder_id_by_key,
  271. CBS_ASN1_OCTETSTRING) ||
  272. !CBBAddBytes(&responder_id_by_key, responder_key_hash) ||
  273. !CBBAddGeneralizedTime(&response_data, produced_at) ||
  274. !CBB_add_asn1(&response_data, &responses_cbb, CBS_ASN1_SEQUENCE)) {
  275. ADD_FAILURE();
  276. return std::string();
  277. }
  278. for (const auto& response : responses) {
  279. if (!AddOCSPSingleResponse(&responses_cbb, response, responder_name_hash,
  280. responder_key_hash)) {
  281. return std::string();
  282. }
  283. }
  284. // responseExtensions not currently supported.
  285. return BuildOCSPResponseWithResponseData(responder_key,
  286. FinishCBB(tbs_cbb.get()));
  287. }
  288. std::string BuildOCSPResponseWithResponseData(
  289. EVP_PKEY* responder_key,
  290. const std::string& tbs_response_data,
  291. absl::optional<SignatureAlgorithm> signature_algorithm) {
  292. // For a basic OCSP responder, responseType will be id-pkix-ocsp-basic.
  293. //
  294. // id-pkix-ocsp OBJECT IDENTIFIER ::= { id-ad-ocsp }
  295. // id-pkix-ocsp-basic OBJECT IDENTIFIER ::= { id-pkix-ocsp 1 }
  296. //
  297. // The value for response SHALL be the DER encoding of
  298. // BasicOCSPResponse.
  299. //
  300. // BasicOCSPResponse ::= SEQUENCE {
  301. // tbsResponseData ResponseData,
  302. // signatureAlgorithm AlgorithmIdentifier,
  303. // signature BIT STRING,
  304. // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
  305. //
  306. // The value for signature SHALL be computed on the hash of the DER
  307. // encoding of ResponseData. The responder MAY include certificates in
  308. // the certs field of BasicOCSPResponse that help the OCSP client verify
  309. // the responder's signature. If no certificates are included, then
  310. // certs SHOULD be absent.
  311. //
  312. bssl::ScopedCBB basic_ocsp_response_cbb;
  313. CBB basic_ocsp_response, signature;
  314. if (!responder_key) {
  315. ADD_FAILURE();
  316. return std::string();
  317. }
  318. if (!signature_algorithm)
  319. signature_algorithm =
  320. CertBuilder::DefaultSignatureAlgorithmForKey(responder_key);
  321. if (!signature_algorithm) {
  322. ADD_FAILURE();
  323. return std::string();
  324. }
  325. std::string signature_algorithm_tlv =
  326. CertBuilder::SignatureAlgorithmToDer(*signature_algorithm);
  327. if (signature_algorithm_tlv.empty() ||
  328. !CBB_init(basic_ocsp_response_cbb.get(), 64 + tbs_response_data.size()) ||
  329. !CBB_add_asn1(basic_ocsp_response_cbb.get(), &basic_ocsp_response,
  330. CBS_ASN1_SEQUENCE) ||
  331. !CBBAddBytes(&basic_ocsp_response, tbs_response_data) ||
  332. !CBBAddBytes(&basic_ocsp_response, signature_algorithm_tlv) ||
  333. !CBB_add_asn1(&basic_ocsp_response, &signature, CBS_ASN1_BITSTRING) ||
  334. !CBB_add_u8(&signature, 0 /* no unused bits */) ||
  335. !CertBuilder::SignData(*signature_algorithm, tbs_response_data,
  336. responder_key, &signature)) {
  337. ADD_FAILURE();
  338. return std::string();
  339. }
  340. // certs field not currently supported.
  341. return EncodeOCSPResponse(OCSPResponse::ResponseStatus::SUCCESSFUL,
  342. der::Input(kBasicOCSPResponseOid),
  343. FinishCBB(basic_ocsp_response_cbb.get()));
  344. }
  345. std::string BuildCrl(const std::string& crl_issuer_subject,
  346. EVP_PKEY* crl_issuer_key,
  347. const std::vector<uint64_t>& revoked_serials,
  348. absl::optional<SignatureAlgorithm> signature_algorithm) {
  349. if (!crl_issuer_key) {
  350. ADD_FAILURE();
  351. return std::string();
  352. }
  353. if (!signature_algorithm)
  354. signature_algorithm =
  355. CertBuilder::DefaultSignatureAlgorithmForKey(crl_issuer_key);
  356. if (!signature_algorithm) {
  357. ADD_FAILURE();
  358. return std::string();
  359. }
  360. std::string signature_algorithm_tlv =
  361. CertBuilder::SignatureAlgorithmToDer(*signature_algorithm);
  362. if (signature_algorithm_tlv.empty()) {
  363. ADD_FAILURE();
  364. return std::string();
  365. }
  366. // TBSCertList ::= SEQUENCE {
  367. // version Version OPTIONAL,
  368. // -- if present, MUST be v2
  369. // signature AlgorithmIdentifier,
  370. // issuer Name,
  371. // thisUpdate Time,
  372. // nextUpdate Time OPTIONAL,
  373. // revokedCertificates SEQUENCE OF SEQUENCE {
  374. // userCertificate CertificateSerialNumber,
  375. // revocationDate Time,
  376. // crlEntryExtensions Extensions OPTIONAL
  377. // -- if present, version MUST be v2
  378. // } OPTIONAL,
  379. // crlExtensions [0] EXPLICIT Extensions OPTIONAL
  380. // -- if present, version MUST be v2
  381. // }
  382. bssl::ScopedCBB tbs_cbb;
  383. CBB tbs_cert_list, revoked_serials_cbb;
  384. if (!CBB_init(tbs_cbb.get(), 10) ||
  385. !CBB_add_asn1(tbs_cbb.get(), &tbs_cert_list, CBS_ASN1_SEQUENCE) ||
  386. !CBB_add_asn1_uint64(&tbs_cert_list, 1 /* V2 */) ||
  387. !CBBAddBytes(&tbs_cert_list, signature_algorithm_tlv) ||
  388. !CBBAddBytes(&tbs_cert_list, crl_issuer_subject) ||
  389. !x509_util::CBBAddTime(&tbs_cert_list,
  390. base::Time::Now() - base::Days(1)) ||
  391. !x509_util::CBBAddTime(&tbs_cert_list,
  392. base::Time::Now() + base::Days(6))) {
  393. ADD_FAILURE();
  394. return std::string();
  395. }
  396. if (!revoked_serials.empty()) {
  397. if (!CBB_add_asn1(&tbs_cert_list, &revoked_serials_cbb,
  398. CBS_ASN1_SEQUENCE)) {
  399. ADD_FAILURE();
  400. return std::string();
  401. }
  402. for (const int64_t revoked_serial : revoked_serials) {
  403. CBB revoked_serial_cbb;
  404. if (!CBB_add_asn1(&revoked_serials_cbb, &revoked_serial_cbb,
  405. CBS_ASN1_SEQUENCE) ||
  406. !CBB_add_asn1_uint64(&revoked_serial_cbb, revoked_serial) ||
  407. !x509_util::CBBAddTime(&revoked_serial_cbb,
  408. base::Time::Now() - base::Days(1)) ||
  409. !CBB_flush(&revoked_serials_cbb)) {
  410. ADD_FAILURE();
  411. return std::string();
  412. }
  413. }
  414. }
  415. std::string tbs_tlv = FinishCBB(tbs_cbb.get());
  416. // CertificateList ::= SEQUENCE {
  417. // tbsCertList TBSCertList,
  418. // signatureAlgorithm AlgorithmIdentifier,
  419. // signatureValue BIT STRING }
  420. bssl::ScopedCBB crl_cbb;
  421. CBB cert_list, signature;
  422. if (!CBB_init(crl_cbb.get(), 10) ||
  423. !CBB_add_asn1(crl_cbb.get(), &cert_list, CBS_ASN1_SEQUENCE) ||
  424. !CBBAddBytes(&cert_list, tbs_tlv) ||
  425. !CBBAddBytes(&cert_list, signature_algorithm_tlv) ||
  426. !CBB_add_asn1(&cert_list, &signature, CBS_ASN1_BITSTRING) ||
  427. !CBB_add_u8(&signature, 0 /* no unused bits */) ||
  428. !CertBuilder::SignData(*signature_algorithm, tbs_tlv, crl_issuer_key,
  429. &signature)) {
  430. ADD_FAILURE();
  431. return std::string();
  432. }
  433. return FinishCBB(crl_cbb.get());
  434. }
  435. } // namespace net