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