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