xref: /aosp_15_r20/external/cronet/net/cert/ct_log_verifier.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2013 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #include "net/cert/ct_log_verifier.h"
6*6777b538SAndroid Build Coastguard Worker 
7*6777b538SAndroid Build Coastguard Worker #include <string.h>
8*6777b538SAndroid Build Coastguard Worker 
9*6777b538SAndroid Build Coastguard Worker #include <bit>
10*6777b538SAndroid Build Coastguard Worker #include <string_view>
11*6777b538SAndroid Build Coastguard Worker #include <vector>
12*6777b538SAndroid Build Coastguard Worker 
13*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
15*6777b538SAndroid Build Coastguard Worker #include "crypto/openssl_util.h"
16*6777b538SAndroid Build Coastguard Worker #include "crypto/sha2.h"
17*6777b538SAndroid Build Coastguard Worker #include "net/cert/ct_log_verifier_util.h"
18*6777b538SAndroid Build Coastguard Worker #include "net/cert/ct_serialization.h"
19*6777b538SAndroid Build Coastguard Worker #include "net/cert/merkle_audit_proof.h"
20*6777b538SAndroid Build Coastguard Worker #include "net/cert/merkle_consistency_proof.h"
21*6777b538SAndroid Build Coastguard Worker #include "net/cert/signed_tree_head.h"
22*6777b538SAndroid Build Coastguard Worker #include "third_party/boringssl/src/include/openssl/bytestring.h"
23*6777b538SAndroid Build Coastguard Worker #include "third_party/boringssl/src/include/openssl/evp.h"
24*6777b538SAndroid Build Coastguard Worker 
25*6777b538SAndroid Build Coastguard Worker namespace net {
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker namespace {
28*6777b538SAndroid Build Coastguard Worker 
29*6777b538SAndroid Build Coastguard Worker // The SHA-256 hash of the empty string.
30*6777b538SAndroid Build Coastguard Worker const unsigned char kSHA256EmptyStringHash[ct::kSthRootHashLength] = {
31*6777b538SAndroid Build Coastguard Worker     0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
32*6777b538SAndroid Build Coastguard Worker     0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
33*6777b538SAndroid Build Coastguard Worker     0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
34*6777b538SAndroid Build Coastguard Worker 
GetEvpAlg(ct::DigitallySigned::HashAlgorithm alg)35*6777b538SAndroid Build Coastguard Worker const EVP_MD* GetEvpAlg(ct::DigitallySigned::HashAlgorithm alg) {
36*6777b538SAndroid Build Coastguard Worker   switch (alg) {
37*6777b538SAndroid Build Coastguard Worker     case ct::DigitallySigned::HASH_ALGO_MD5:
38*6777b538SAndroid Build Coastguard Worker       return EVP_md5();
39*6777b538SAndroid Build Coastguard Worker     case ct::DigitallySigned::HASH_ALGO_SHA1:
40*6777b538SAndroid Build Coastguard Worker       return EVP_sha1();
41*6777b538SAndroid Build Coastguard Worker     case ct::DigitallySigned::HASH_ALGO_SHA224:
42*6777b538SAndroid Build Coastguard Worker       return EVP_sha224();
43*6777b538SAndroid Build Coastguard Worker     case ct::DigitallySigned::HASH_ALGO_SHA256:
44*6777b538SAndroid Build Coastguard Worker       return EVP_sha256();
45*6777b538SAndroid Build Coastguard Worker     case ct::DigitallySigned::HASH_ALGO_SHA384:
46*6777b538SAndroid Build Coastguard Worker       return EVP_sha384();
47*6777b538SAndroid Build Coastguard Worker     case ct::DigitallySigned::HASH_ALGO_SHA512:
48*6777b538SAndroid Build Coastguard Worker       return EVP_sha512();
49*6777b538SAndroid Build Coastguard Worker     case ct::DigitallySigned::HASH_ALGO_NONE:
50*6777b538SAndroid Build Coastguard Worker     default:
51*6777b538SAndroid Build Coastguard Worker       NOTREACHED();
52*6777b538SAndroid Build Coastguard Worker       return nullptr;
53*6777b538SAndroid Build Coastguard Worker   }
54*6777b538SAndroid Build Coastguard Worker }
55*6777b538SAndroid Build Coastguard Worker 
56*6777b538SAndroid Build Coastguard Worker }  // namespace
57*6777b538SAndroid Build Coastguard Worker 
58*6777b538SAndroid Build Coastguard Worker // static
Create(std::string_view public_key,std::string description)59*6777b538SAndroid Build Coastguard Worker scoped_refptr<const CTLogVerifier> CTLogVerifier::Create(
60*6777b538SAndroid Build Coastguard Worker     std::string_view public_key,
61*6777b538SAndroid Build Coastguard Worker     std::string description) {
62*6777b538SAndroid Build Coastguard Worker   auto result = base::WrapRefCounted(new CTLogVerifier(std::move(description)));
63*6777b538SAndroid Build Coastguard Worker   if (!result->Init(public_key))
64*6777b538SAndroid Build Coastguard Worker     return nullptr;
65*6777b538SAndroid Build Coastguard Worker   return result;
66*6777b538SAndroid Build Coastguard Worker }
67*6777b538SAndroid Build Coastguard Worker 
CTLogVerifier(std::string description)68*6777b538SAndroid Build Coastguard Worker CTLogVerifier::CTLogVerifier(std::string description)
69*6777b538SAndroid Build Coastguard Worker     : description_(std::move(description)) {}
70*6777b538SAndroid Build Coastguard Worker 
Verify(const ct::SignedEntryData & entry,const ct::SignedCertificateTimestamp & sct) const71*6777b538SAndroid Build Coastguard Worker bool CTLogVerifier::Verify(const ct::SignedEntryData& entry,
72*6777b538SAndroid Build Coastguard Worker                            const ct::SignedCertificateTimestamp& sct) const {
73*6777b538SAndroid Build Coastguard Worker   std::string serialized_log_entry;
74*6777b538SAndroid Build Coastguard Worker   std::string serialized_data;
75*6777b538SAndroid Build Coastguard Worker 
76*6777b538SAndroid Build Coastguard Worker   return sct.log_id == key_id_ && SignatureParametersMatch(sct.signature) &&
77*6777b538SAndroid Build Coastguard Worker          ct::EncodeSignedEntry(entry, &serialized_log_entry) &&
78*6777b538SAndroid Build Coastguard Worker          ct::EncodeV1SCTSignedData(sct.timestamp, serialized_log_entry,
79*6777b538SAndroid Build Coastguard Worker                                    sct.extensions, &serialized_data) &&
80*6777b538SAndroid Build Coastguard Worker          VerifySignature(serialized_data, sct.signature.signature_data);
81*6777b538SAndroid Build Coastguard Worker }
82*6777b538SAndroid Build Coastguard Worker 
VerifySignedTreeHead(const ct::SignedTreeHead & signed_tree_head) const83*6777b538SAndroid Build Coastguard Worker bool CTLogVerifier::VerifySignedTreeHead(
84*6777b538SAndroid Build Coastguard Worker     const ct::SignedTreeHead& signed_tree_head) const {
85*6777b538SAndroid Build Coastguard Worker   std::string serialized_data;
86*6777b538SAndroid Build Coastguard Worker   if (!SignatureParametersMatch(signed_tree_head.signature) ||
87*6777b538SAndroid Build Coastguard Worker       !ct::EncodeTreeHeadSignature(signed_tree_head, &serialized_data) ||
88*6777b538SAndroid Build Coastguard Worker       !VerifySignature(serialized_data,
89*6777b538SAndroid Build Coastguard Worker                        signed_tree_head.signature.signature_data)) {
90*6777b538SAndroid Build Coastguard Worker     return false;
91*6777b538SAndroid Build Coastguard Worker   }
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker   if (signed_tree_head.tree_size == 0) {
94*6777b538SAndroid Build Coastguard Worker     // Root hash must equate SHA256 hash of the empty string.
95*6777b538SAndroid Build Coastguard Worker     return memcmp(signed_tree_head.sha256_root_hash, kSHA256EmptyStringHash,
96*6777b538SAndroid Build Coastguard Worker                   ct::kSthRootHashLength) == 0;
97*6777b538SAndroid Build Coastguard Worker   }
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker   return true;
100*6777b538SAndroid Build Coastguard Worker }
101*6777b538SAndroid Build Coastguard Worker 
SignatureParametersMatch(const ct::DigitallySigned & signature) const102*6777b538SAndroid Build Coastguard Worker bool CTLogVerifier::SignatureParametersMatch(
103*6777b538SAndroid Build Coastguard Worker     const ct::DigitallySigned& signature) const {
104*6777b538SAndroid Build Coastguard Worker   return signature.SignatureParametersMatch(hash_algorithm_,
105*6777b538SAndroid Build Coastguard Worker                                             signature_algorithm_);
106*6777b538SAndroid Build Coastguard Worker }
107*6777b538SAndroid Build Coastguard Worker 
VerifyConsistencyProof(const ct::MerkleConsistencyProof & proof,const std::string & old_tree_hash,const std::string & new_tree_hash) const108*6777b538SAndroid Build Coastguard Worker bool CTLogVerifier::VerifyConsistencyProof(
109*6777b538SAndroid Build Coastguard Worker     const ct::MerkleConsistencyProof& proof,
110*6777b538SAndroid Build Coastguard Worker     const std::string& old_tree_hash,
111*6777b538SAndroid Build Coastguard Worker     const std::string& new_tree_hash) const {
112*6777b538SAndroid Build Coastguard Worker   // Proof does not originate from this log.
113*6777b538SAndroid Build Coastguard Worker   if (key_id_ != proof.log_id)
114*6777b538SAndroid Build Coastguard Worker     return false;
115*6777b538SAndroid Build Coastguard Worker 
116*6777b538SAndroid Build Coastguard Worker   // Cannot prove consistency from a tree of a certain size to a tree smaller
117*6777b538SAndroid Build Coastguard Worker   // than that - only the other way around.
118*6777b538SAndroid Build Coastguard Worker   if (proof.first_tree_size > proof.second_tree_size)
119*6777b538SAndroid Build Coastguard Worker     return false;
120*6777b538SAndroid Build Coastguard Worker 
121*6777b538SAndroid Build Coastguard Worker   // If the proof is between trees of the same size, then the 'proof'
122*6777b538SAndroid Build Coastguard Worker   // is really just a statement that the tree hasn't changed. If this
123*6777b538SAndroid Build Coastguard Worker   // is the case, there should be no proof nodes, and both the old
124*6777b538SAndroid Build Coastguard Worker   // and new hash should be equivalent.
125*6777b538SAndroid Build Coastguard Worker   if (proof.first_tree_size == proof.second_tree_size)
126*6777b538SAndroid Build Coastguard Worker     return proof.nodes.empty() && old_tree_hash == new_tree_hash;
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker   // It is possible to call this method to prove consistency between the
129*6777b538SAndroid Build Coastguard Worker   // initial state of a log (i.e. an empty tree) and a later root. In that
130*6777b538SAndroid Build Coastguard Worker   // case, the only valid proof is an empty proof.
131*6777b538SAndroid Build Coastguard Worker   if (proof.first_tree_size == 0)
132*6777b538SAndroid Build Coastguard Worker     return proof.nodes.empty();
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker   // Implement the algorithm described in
135*6777b538SAndroid Build Coastguard Worker   // https://tools.ietf.org/html/draft-ietf-trans-rfc6962-bis-12#section-9.4.2
136*6777b538SAndroid Build Coastguard Worker   //
137*6777b538SAndroid Build Coastguard Worker   // It maintains a pair of hashes |fr| and |sr|, initialized to the same
138*6777b538SAndroid Build Coastguard Worker   // value. Each node in |proof| will be hashed to the left of both |fr| and
139*6777b538SAndroid Build Coastguard Worker   // |sr| or to the right of only |sr|. The proof is then valid if |fr| is
140*6777b538SAndroid Build Coastguard Worker   // |old_tree_hash| and |sr| is |new_tree_hash|, proving that tree nodes which
141*6777b538SAndroid Build Coastguard Worker   // make up |old_tree_hash| are a prefix of |new_tree_hash|.
142*6777b538SAndroid Build Coastguard Worker 
143*6777b538SAndroid Build Coastguard Worker   // At this point, the algorithm's preconditions must be satisfied.
144*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(0u, proof.first_tree_size);
145*6777b538SAndroid Build Coastguard Worker   DCHECK_LT(proof.first_tree_size, proof.second_tree_size);
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   // 1. If "first" is an exact power of 2, then prepend "first_hash" to the
148*6777b538SAndroid Build Coastguard Worker   // "consistency_path" array.
149*6777b538SAndroid Build Coastguard Worker   std::string_view first_proof_node = old_tree_hash;
150*6777b538SAndroid Build Coastguard Worker   auto iter = proof.nodes.begin();
151*6777b538SAndroid Build Coastguard Worker   if (!std::has_single_bit(proof.first_tree_size)) {
152*6777b538SAndroid Build Coastguard Worker     if (iter == proof.nodes.end())
153*6777b538SAndroid Build Coastguard Worker       return false;
154*6777b538SAndroid Build Coastguard Worker     first_proof_node = *iter;
155*6777b538SAndroid Build Coastguard Worker     ++iter;
156*6777b538SAndroid Build Coastguard Worker   }
157*6777b538SAndroid Build Coastguard Worker   // iter now points to the second node in the modified proof.nodes.
158*6777b538SAndroid Build Coastguard Worker 
159*6777b538SAndroid Build Coastguard Worker   // 2. Set "fn" to "first - 1" and "sn" to "second - 1".
160*6777b538SAndroid Build Coastguard Worker   uint64_t fn = proof.first_tree_size - 1;
161*6777b538SAndroid Build Coastguard Worker   uint64_t sn = proof.second_tree_size - 1;
162*6777b538SAndroid Build Coastguard Worker 
163*6777b538SAndroid Build Coastguard Worker   // 3. If "LSB(fn)" is set, then right-shift both "fn" and "sn" equally until
164*6777b538SAndroid Build Coastguard Worker   // "LSB(fn)" is not set.
165*6777b538SAndroid Build Coastguard Worker   while (fn & 1) {
166*6777b538SAndroid Build Coastguard Worker     fn >>= 1;
167*6777b538SAndroid Build Coastguard Worker     sn >>= 1;
168*6777b538SAndroid Build Coastguard Worker   }
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker   // 4. Set both "fr" and "sr" to the first value in the "consistency_path"
171*6777b538SAndroid Build Coastguard Worker   // array.
172*6777b538SAndroid Build Coastguard Worker   std::string fr(first_proof_node);
173*6777b538SAndroid Build Coastguard Worker   std::string sr(first_proof_node);
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker   // 5. For each subsequent value "c" in the "consistency_path" array:
176*6777b538SAndroid Build Coastguard Worker   for (; iter != proof.nodes.end(); ++iter) {
177*6777b538SAndroid Build Coastguard Worker     // If "sn" is 0, stop the iteration and fail the proof verification.
178*6777b538SAndroid Build Coastguard Worker     if (sn == 0)
179*6777b538SAndroid Build Coastguard Worker       return false;
180*6777b538SAndroid Build Coastguard Worker     // If "LSB(fn)" is set, or if "fn" is equal to "sn", then:
181*6777b538SAndroid Build Coastguard Worker     if ((fn & 1) || fn == sn) {
182*6777b538SAndroid Build Coastguard Worker       // 1. Set "fr" to "HASH(0x01 || c || fr)"
183*6777b538SAndroid Build Coastguard Worker       //    Set "sr" to "HASH(0x01 || c || sr)"
184*6777b538SAndroid Build Coastguard Worker       fr = ct::internal::HashNodes(*iter, fr);
185*6777b538SAndroid Build Coastguard Worker       sr = ct::internal::HashNodes(*iter, sr);
186*6777b538SAndroid Build Coastguard Worker 
187*6777b538SAndroid Build Coastguard Worker       // 2. If "LSB(fn)" is not set, then right-shift both "fn" and "sn" equally
188*6777b538SAndroid Build Coastguard Worker       // until either "LSB(fn)" is set or "fn" is "0".
189*6777b538SAndroid Build Coastguard Worker       while (!(fn & 1) && fn != 0) {
190*6777b538SAndroid Build Coastguard Worker         fn >>= 1;
191*6777b538SAndroid Build Coastguard Worker         sn >>= 1;
192*6777b538SAndroid Build Coastguard Worker       }
193*6777b538SAndroid Build Coastguard Worker     } else {  // Otherwise:
194*6777b538SAndroid Build Coastguard Worker       // Set "sr" to "HASH(0x01 || sr || c)"
195*6777b538SAndroid Build Coastguard Worker       sr = ct::internal::HashNodes(sr, *iter);
196*6777b538SAndroid Build Coastguard Worker     }
197*6777b538SAndroid Build Coastguard Worker 
198*6777b538SAndroid Build Coastguard Worker     // Finally, right-shift both "fn" and "sn" one time.
199*6777b538SAndroid Build Coastguard Worker     fn >>= 1;
200*6777b538SAndroid Build Coastguard Worker     sn >>= 1;
201*6777b538SAndroid Build Coastguard Worker   }
202*6777b538SAndroid Build Coastguard Worker 
203*6777b538SAndroid Build Coastguard Worker   // 6. After completing iterating through the "consistency_path" array as
204*6777b538SAndroid Build Coastguard Worker   // described above, verify that the "fr" calculated is equal to the
205*6777b538SAndroid Build Coastguard Worker   // "first_hash" supplied, that the "sr" calculated is equal to the
206*6777b538SAndroid Build Coastguard Worker   // "second_hash" supplied and that "sn" is 0.
207*6777b538SAndroid Build Coastguard Worker   return fr == old_tree_hash && sr == new_tree_hash && sn == 0;
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker 
VerifyAuditProof(const ct::MerkleAuditProof & proof,const std::string & root_hash,const std::string & leaf_hash) const210*6777b538SAndroid Build Coastguard Worker bool CTLogVerifier::VerifyAuditProof(const ct::MerkleAuditProof& proof,
211*6777b538SAndroid Build Coastguard Worker                                      const std::string& root_hash,
212*6777b538SAndroid Build Coastguard Worker                                      const std::string& leaf_hash) const {
213*6777b538SAndroid Build Coastguard Worker   // Implements the algorithm described in
214*6777b538SAndroid Build Coastguard Worker   // https://tools.ietf.org/html/draft-ietf-trans-rfc6962-bis-19#section-10.4.1
215*6777b538SAndroid Build Coastguard Worker   //
216*6777b538SAndroid Build Coastguard Worker   // It maintains a hash |r|, initialized to |leaf_hash|, and hashes nodes from
217*6777b538SAndroid Build Coastguard Worker   // |proof| into it. The proof is then valid if |r| is |root_hash|, proving
218*6777b538SAndroid Build Coastguard Worker   // that |root_hash| includes |leaf_hash|.
219*6777b538SAndroid Build Coastguard Worker 
220*6777b538SAndroid Build Coastguard Worker   // 1.  Compare "leaf_index" against "tree_size".  If "leaf_index" is
221*6777b538SAndroid Build Coastguard Worker   //     greater than or equal to "tree_size" fail the proof verification.
222*6777b538SAndroid Build Coastguard Worker   if (proof.leaf_index >= proof.tree_size)
223*6777b538SAndroid Build Coastguard Worker     return false;
224*6777b538SAndroid Build Coastguard Worker 
225*6777b538SAndroid Build Coastguard Worker   // 2.  Set "fn" to "leaf_index" and "sn" to "tree_size - 1".
226*6777b538SAndroid Build Coastguard Worker   uint64_t fn = proof.leaf_index;
227*6777b538SAndroid Build Coastguard Worker   uint64_t sn = proof.tree_size - 1;
228*6777b538SAndroid Build Coastguard Worker   // 3.  Set "r" to "hash".
229*6777b538SAndroid Build Coastguard Worker   std::string r = leaf_hash;
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker   // 4.  For each value "p" in the "inclusion_path" array:
232*6777b538SAndroid Build Coastguard Worker   for (const std::string& p : proof.nodes) {
233*6777b538SAndroid Build Coastguard Worker     // If "sn" is 0, stop the iteration and fail the proof verification.
234*6777b538SAndroid Build Coastguard Worker     if (sn == 0)
235*6777b538SAndroid Build Coastguard Worker       return false;
236*6777b538SAndroid Build Coastguard Worker 
237*6777b538SAndroid Build Coastguard Worker     // If "LSB(fn)" is set, or if "fn" is equal to "sn", then:
238*6777b538SAndroid Build Coastguard Worker     if ((fn & 1) || fn == sn) {
239*6777b538SAndroid Build Coastguard Worker       // 1.  Set "r" to "HASH(0x01 || p || r)"
240*6777b538SAndroid Build Coastguard Worker       r = ct::internal::HashNodes(p, r);
241*6777b538SAndroid Build Coastguard Worker 
242*6777b538SAndroid Build Coastguard Worker       // 2.  If "LSB(fn)" is not set, then right-shift both "fn" and "sn"
243*6777b538SAndroid Build Coastguard Worker       //     equally until either "LSB(fn)" is set or "fn" is "0".
244*6777b538SAndroid Build Coastguard Worker       while (!(fn & 1) && fn != 0) {
245*6777b538SAndroid Build Coastguard Worker         fn >>= 1;
246*6777b538SAndroid Build Coastguard Worker         sn >>= 1;
247*6777b538SAndroid Build Coastguard Worker       }
248*6777b538SAndroid Build Coastguard Worker     } else {  // Otherwise:
249*6777b538SAndroid Build Coastguard Worker       // Set "r" to "HASH(0x01 || r || p)"
250*6777b538SAndroid Build Coastguard Worker       r = ct::internal::HashNodes(r, p);
251*6777b538SAndroid Build Coastguard Worker     }
252*6777b538SAndroid Build Coastguard Worker 
253*6777b538SAndroid Build Coastguard Worker     // Finally, right-shift both "fn" and "sn" one time.
254*6777b538SAndroid Build Coastguard Worker     fn >>= 1;
255*6777b538SAndroid Build Coastguard Worker     sn >>= 1;
256*6777b538SAndroid Build Coastguard Worker   }
257*6777b538SAndroid Build Coastguard Worker 
258*6777b538SAndroid Build Coastguard Worker   // 5.  Compare "sn" to 0.  Compare "r" against the "root_hash".  If "sn"
259*6777b538SAndroid Build Coastguard Worker   //     is equal to 0, and "r" and the "root_hash" are equal, then the
260*6777b538SAndroid Build Coastguard Worker   //     log has proven the inclusion of "hash".  Otherwise, fail the
261*6777b538SAndroid Build Coastguard Worker   //     proof verification.
262*6777b538SAndroid Build Coastguard Worker   return sn == 0 && r == root_hash;
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker CTLogVerifier::~CTLogVerifier() = default;
266*6777b538SAndroid Build Coastguard Worker 
Init(std::string_view public_key)267*6777b538SAndroid Build Coastguard Worker bool CTLogVerifier::Init(std::string_view public_key) {
268*6777b538SAndroid Build Coastguard Worker   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
269*6777b538SAndroid Build Coastguard Worker 
270*6777b538SAndroid Build Coastguard Worker   CBS cbs;
271*6777b538SAndroid Build Coastguard Worker   CBS_init(&cbs, reinterpret_cast<const uint8_t*>(public_key.data()),
272*6777b538SAndroid Build Coastguard Worker            public_key.size());
273*6777b538SAndroid Build Coastguard Worker   public_key_.reset(EVP_parse_public_key(&cbs));
274*6777b538SAndroid Build Coastguard Worker   if (!public_key_ || CBS_len(&cbs) != 0)
275*6777b538SAndroid Build Coastguard Worker     return false;
276*6777b538SAndroid Build Coastguard Worker 
277*6777b538SAndroid Build Coastguard Worker   key_id_ = crypto::SHA256HashString(public_key);
278*6777b538SAndroid Build Coastguard Worker 
279*6777b538SAndroid Build Coastguard Worker   // Right now, only RSASSA-PKCS1v15 with SHA-256 and ECDSA with SHA-256 are
280*6777b538SAndroid Build Coastguard Worker   // supported.
281*6777b538SAndroid Build Coastguard Worker   switch (EVP_PKEY_id(public_key_.get())) {
282*6777b538SAndroid Build Coastguard Worker     case EVP_PKEY_RSA:
283*6777b538SAndroid Build Coastguard Worker       hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256;
284*6777b538SAndroid Build Coastguard Worker       signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_RSA;
285*6777b538SAndroid Build Coastguard Worker       break;
286*6777b538SAndroid Build Coastguard Worker     case EVP_PKEY_EC:
287*6777b538SAndroid Build Coastguard Worker       hash_algorithm_ = ct::DigitallySigned::HASH_ALGO_SHA256;
288*6777b538SAndroid Build Coastguard Worker       signature_algorithm_ = ct::DigitallySigned::SIG_ALGO_ECDSA;
289*6777b538SAndroid Build Coastguard Worker       break;
290*6777b538SAndroid Build Coastguard Worker     default:
291*6777b538SAndroid Build Coastguard Worker       return false;
292*6777b538SAndroid Build Coastguard Worker   }
293*6777b538SAndroid Build Coastguard Worker 
294*6777b538SAndroid Build Coastguard Worker   // Extra safety check: Require RSA keys of at least 2048 bits.
295*6777b538SAndroid Build Coastguard Worker   // EVP_PKEY_size returns the size in bytes. 256 = 2048-bit RSA key.
296*6777b538SAndroid Build Coastguard Worker   if (signature_algorithm_ == ct::DigitallySigned::SIG_ALGO_RSA &&
297*6777b538SAndroid Build Coastguard Worker       EVP_PKEY_size(public_key_.get()) < 256) {
298*6777b538SAndroid Build Coastguard Worker     return false;
299*6777b538SAndroid Build Coastguard Worker   }
300*6777b538SAndroid Build Coastguard Worker 
301*6777b538SAndroid Build Coastguard Worker   return true;
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker 
VerifySignature(std::string_view data_to_sign,std::string_view signature) const304*6777b538SAndroid Build Coastguard Worker bool CTLogVerifier::VerifySignature(std::string_view data_to_sign,
305*6777b538SAndroid Build Coastguard Worker                                     std::string_view signature) const {
306*6777b538SAndroid Build Coastguard Worker   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
307*6777b538SAndroid Build Coastguard Worker 
308*6777b538SAndroid Build Coastguard Worker   const EVP_MD* hash_alg = GetEvpAlg(hash_algorithm_);
309*6777b538SAndroid Build Coastguard Worker   bssl::ScopedEVP_MD_CTX ctx;
310*6777b538SAndroid Build Coastguard Worker   return hash_alg &&
311*6777b538SAndroid Build Coastguard Worker          EVP_DigestVerifyInit(ctx.get(), nullptr, hash_alg, nullptr,
312*6777b538SAndroid Build Coastguard Worker                               public_key_.get()) &&
313*6777b538SAndroid Build Coastguard Worker          EVP_DigestVerifyUpdate(ctx.get(), data_to_sign.data(),
314*6777b538SAndroid Build Coastguard Worker                                 data_to_sign.size()) &&
315*6777b538SAndroid Build Coastguard Worker          EVP_DigestVerifyFinal(
316*6777b538SAndroid Build Coastguard Worker              ctx.get(), reinterpret_cast<const uint8_t*>(signature.data()),
317*6777b538SAndroid Build Coastguard Worker              signature.size());
318*6777b538SAndroid Build Coastguard Worker }
319*6777b538SAndroid Build Coastguard Worker 
320*6777b538SAndroid Build Coastguard Worker }  // namespace net
321