/src/boringssl/pki/signature_algorithm.cc
Line | Count | Source |
1 | | // Copyright 2015 The Chromium Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include "signature_algorithm.h" |
16 | | |
17 | | #include <openssl/bytestring.h> |
18 | | #include <openssl/digest.h> |
19 | | #include <openssl/nid.h> |
20 | | |
21 | | #include "input.h" |
22 | | #include "parse_values.h" |
23 | | #include "parser.h" |
24 | | |
25 | | BSSL_NAMESPACE_BEGIN |
26 | | |
27 | | namespace { |
28 | | |
29 | | // These OIDs do not reference libcrypto's OBJ table, as that table is very |
30 | | // large and includes many more OIDs than we need. However, where OIDs are |
31 | | // already in the table, we reuse the |OBJ_ENC_*| constants to avoid needing to |
32 | | // specify them a second time. |
33 | | |
34 | | // From RFC 5912: |
35 | | // |
36 | | // sha1WithRSAEncryption OBJECT IDENTIFIER ::= { |
37 | | // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) |
38 | | // pkcs-1(1) 5 } |
39 | | // |
40 | | // In dotted notation: 1.2.840.113549.1.1.5 |
41 | | const uint8_t kOidSha1WithRsaEncryption[] = {OBJ_ENC_sha1WithRSAEncryption}; |
42 | | |
43 | | // sha1WithRSASignature is a deprecated equivalent of |
44 | | // sha1WithRSAEncryption. |
45 | | // |
46 | | // It originates from the NIST Open Systems Environment (OSE) |
47 | | // Implementor's Workshop (OIW). |
48 | | // |
49 | | // It is supported for compatibility with Microsoft's certificate APIs and |
50 | | // tools, particularly makecert.exe, which default(ed/s) to this OID for SHA-1. |
51 | | // |
52 | | // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1042479 |
53 | | // |
54 | | // In dotted notation: 1.3.14.3.2.29 |
55 | | const uint8_t kOidSha1WithRsaSignature[] = {OBJ_ENC_sha1WithRSA}; |
56 | | |
57 | | // From RFC 5912: |
58 | | // |
59 | | // pkcs-1 OBJECT IDENTIFIER ::= |
60 | | // { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } |
61 | | |
62 | | // From RFC 5912: |
63 | | // |
64 | | // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } |
65 | | // |
66 | | // In dotted notation: 1.2.840.113549.1.1.11 |
67 | | const uint8_t kOidSha256WithRsaEncryption[] = {OBJ_ENC_sha256WithRSAEncryption}; |
68 | | |
69 | | // From RFC 5912: |
70 | | // |
71 | | // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } |
72 | | // |
73 | | // In dotted notation: 1.2.840.113549.1.1.11 |
74 | | const uint8_t kOidSha384WithRsaEncryption[] = {OBJ_ENC_sha384WithRSAEncryption}; |
75 | | |
76 | | // From RFC 5912: |
77 | | // |
78 | | // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } |
79 | | // |
80 | | // In dotted notation: 1.2.840.113549.1.1.13 |
81 | | const uint8_t kOidSha512WithRsaEncryption[] = {OBJ_ENC_sha512WithRSAEncryption}; |
82 | | |
83 | | // From RFC 5912: |
84 | | // |
85 | | // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { |
86 | | // iso(1) member-body(2) us(840) ansi-X9-62(10045) |
87 | | // signatures(4) 1 } |
88 | | // |
89 | | // In dotted notation: 1.2.840.10045.4.1 |
90 | | const uint8_t kOidEcdsaWithSha1[] = {OBJ_ENC_ecdsa_with_SHA1}; |
91 | | |
92 | | // From RFC 5912: |
93 | | // |
94 | | // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { |
95 | | // iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) |
96 | | // ecdsa-with-SHA2(3) 2 } |
97 | | // |
98 | | // In dotted notation: 1.2.840.10045.4.3.2 |
99 | | const uint8_t kOidEcdsaWithSha256[] = {OBJ_ENC_ecdsa_with_SHA256}; |
100 | | |
101 | | // From RFC 5912: |
102 | | // |
103 | | // ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { |
104 | | // iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) |
105 | | // ecdsa-with-SHA2(3) 3 } |
106 | | // |
107 | | // In dotted notation: 1.2.840.10045.4.3.3 |
108 | | const uint8_t kOidEcdsaWithSha384[] = {OBJ_ENC_ecdsa_with_SHA384}; |
109 | | |
110 | | // From RFC 5912: |
111 | | // |
112 | | // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { |
113 | | // iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) |
114 | | // ecdsa-with-SHA2(3) 4 } |
115 | | // |
116 | | // In dotted notation: 1.2.840.10045.4.3.4 |
117 | | const uint8_t kOidEcdsaWithSha512[] = {OBJ_ENC_ecdsa_with_SHA512}; |
118 | | |
119 | | // From RFC 5912: |
120 | | // |
121 | | // id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 } |
122 | | // |
123 | | // In dotted notation: 1.2.840.113549.1.1.10 |
124 | | const uint8_t kOidRsaSsaPss[] = {OBJ_ENC_rsassaPss}; |
125 | | |
126 | | // From RFC 5912: |
127 | | // |
128 | | // id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 } |
129 | | // |
130 | | // In dotted notation: 1.2.840.113549.1.1.8 |
131 | | const uint8_t kOidMgf1[] = {OBJ_ENC_mgf1}; |
132 | | |
133 | | // From RFC 9881: |
134 | | // |
135 | | // id-ml-dsa-44 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) |
136 | | // country(16) us(840) organization(1) gov(101) csor(3) |
137 | | // nistAlgorithm(4) sigAlgs(3) id-ml-dsa-44(17) } |
138 | | // |
139 | | // In dotted notation: 2.16.840.1.101.3.4.3.17 |
140 | | const uint8_t kOidAlgMldsa44[] = {OBJ_ENC_ML_DSA_44}; |
141 | | |
142 | | // From RFC 9881: |
143 | | // |
144 | | // id-ml-dsa-65 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) |
145 | | // country(16) us(840) organization(1) gov(101) csor(3) |
146 | | // nistAlgorithm(4) sigAlgs(3) id-ml-dsa-65(18) } |
147 | | // |
148 | | // In dotted notation: 2.16.840.1.101.3.4.3.18 |
149 | | const uint8_t kOidAlgMldsa65[] = {OBJ_ENC_ML_DSA_65}; |
150 | | |
151 | | // From RFC 9881: |
152 | | // |
153 | | // id-ml-dsa-87 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) |
154 | | // country(16) us(840) organization(1) gov(101) csor(3) |
155 | | // nistAlgorithm(4) sigAlgs(3) id-ml-dsa-87(19) } |
156 | | // |
157 | | // In dotted notation: 2.16.840.1.101.3.4.3.19 |
158 | | const uint8_t kOidAlgMldsa87[] = {OBJ_ENC_ML_DSA_87}; |
159 | | |
160 | | // From draft-davidben-tls-merkle-tree-certs-08: |
161 | | // |
162 | | // id-alg-mtcProof OBJECT IDENTIFIER ::= { |
163 | | // iso(1) identified-organization(3) dod(6) internet(1) security(5) |
164 | | // mechanisms(5) pkix(7) algorithms(6) TBD} |
165 | | // |
166 | | // Also from said draft: |
167 | | // For initial experimentation, early implementations of this design will use |
168 | | // the OID 1.3.6.1.4.1.44363.47.0 instead of id-alg-mtcProof. |
169 | | const uint8_t kOidAlgMtcProofDraftDavidben08[] = {0x2b, 0x06, 0x01, 0x04, 0x01, |
170 | | 0x82, 0xda, 0x4b, 0x2f, 0x00}; |
171 | | |
172 | | // Returns true if the entirety of the input is a NULL value. |
173 | 271 | [[nodiscard]] bool IsNull(der::Input input) { |
174 | 271 | der::Parser parser(input); |
175 | 271 | der::Input null_value; |
176 | 271 | if (!parser.ReadTag(CBS_ASN1_NULL, &null_value)) { |
177 | 165 | return false; |
178 | 165 | } |
179 | | |
180 | | // NULL values are TLV encoded; the value is expected to be empty. |
181 | 106 | if (!null_value.empty()) { |
182 | 40 | return false; |
183 | 40 | } |
184 | | |
185 | | // By definition of this function, the entire input must be a NULL. |
186 | 66 | return !parser.HasMore(); |
187 | 106 | } |
188 | | |
189 | 271 | [[nodiscard]] bool IsNullOrEmpty(der::Input input) { |
190 | 271 | return IsNull(input) || input.empty(); |
191 | 271 | } |
192 | | |
193 | | // Parses a MaskGenAlgorithm as defined by RFC 5912: |
194 | | // |
195 | | // MaskGenAlgorithm ::= AlgorithmIdentifier{ALGORITHM, |
196 | | // {PKCS1MGFAlgorithms}} |
197 | | // |
198 | | // mgf1SHA1 MaskGenAlgorithm ::= { |
199 | | // algorithm id-mgf1, |
200 | | // parameters HashAlgorithm : sha1Identifier |
201 | | // } |
202 | | // |
203 | | // -- |
204 | | // -- Define the set of mask generation functions |
205 | | // -- |
206 | | // -- If the identifier is id-mgf1, any of the listed hash |
207 | | // -- algorithms may be used. |
208 | | // -- |
209 | | // |
210 | | // PKCS1MGFAlgorithms ALGORITHM ::= { |
211 | | // { IDENTIFIER id-mgf1 PARAMS TYPE HashAlgorithm ARE required }, |
212 | | // ... |
213 | | // } |
214 | | // |
215 | | // Note that the possible mask gen algorithms is extensible. However at present |
216 | | // the only function supported is MGF1, as that is the singular mask gen |
217 | | // function defined by RFC 4055 / RFC 5912. |
218 | | [[nodiscard]] bool ParseMaskGenAlgorithm(const der::Input input, |
219 | 175 | DigestAlgorithm *mgf1_hash) { |
220 | 175 | der::Input oid; |
221 | 175 | der::Input params; |
222 | 175 | if (!ParseAlgorithmIdentifier(input, &oid, ¶ms)) { |
223 | 4 | return false; |
224 | 4 | } |
225 | | |
226 | | // MGF1 is the only supported mask generation algorithm. |
227 | 171 | if (oid != der::Input(kOidMgf1)) { |
228 | 8 | return false; |
229 | 8 | } |
230 | | |
231 | 163 | return ParseHashAlgorithm(params, mgf1_hash); |
232 | 171 | } |
233 | | |
234 | | // Parses the parameters for an RSASSA-PSS signature algorithm, as defined by |
235 | | // RFC 5912: |
236 | | // |
237 | | // sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= { |
238 | | // IDENTIFIER id-RSASSA-PSS |
239 | | // PARAMS TYPE RSASSA-PSS-params ARE required |
240 | | // HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384 |
241 | | // | mda-sha512 } |
242 | | // PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS } |
243 | | // SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS } |
244 | | // } |
245 | | // |
246 | | // RSASSA-PSS-params ::= SEQUENCE { |
247 | | // hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, |
248 | | // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, |
249 | | // saltLength [2] INTEGER DEFAULT 20, |
250 | | // trailerField [3] INTEGER DEFAULT 1 |
251 | | // } |
252 | | // |
253 | | // Which is to say the parameters MUST be present, and of type |
254 | | // RSASSA-PSS-params. Additionally, we only support the RSA-PSS parameter |
255 | | // combinations representable by TLS 1.3 (RFC 8446). |
256 | | // |
257 | | // Note also that DER encoding (ITU-T X.690 section 11.5) prohibits |
258 | | // specifying default values explicitly. The parameter should instead be |
259 | | // omitted to indicate a default value. |
260 | 342 | std::optional<SignatureAlgorithm> ParseRsaPss(der::Input params) { |
261 | 342 | der::Parser parser(params); |
262 | 342 | der::Parser params_parser; |
263 | 342 | if (!parser.ReadSequence(¶ms_parser)) { |
264 | 18 | return std::nullopt; |
265 | 18 | } |
266 | | |
267 | | // There shouldn't be anything after the sequence (by definition the |
268 | | // parameters is a single sequence). |
269 | 324 | if (parser.HasMore()) { |
270 | 0 | return std::nullopt; |
271 | 0 | } |
272 | | |
273 | | // The default values for hashAlgorithm, maskGenAlgorithm, and saltLength |
274 | | // correspond to SHA-1, which we do not support with RSA-PSS, so treat them as |
275 | | // required fields. Explicitly-specified defaults will be rejected later, when |
276 | | // we limit combinations. Additionally, as the trailerField is required to be |
277 | | // the default, we simply ignore it and reject it as any other trailing data. |
278 | | // |
279 | | // hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, |
280 | | // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1, |
281 | | // saltLength [2] INTEGER DEFAULT 20, |
282 | | // trailerField [3] INTEGER DEFAULT 1 |
283 | 324 | der::Input field; |
284 | 324 | DigestAlgorithm hash, mgf1_hash; |
285 | 324 | der::Parser salt_length_parser; |
286 | 324 | uint64_t salt_length; |
287 | 324 | if (!params_parser.ReadTag( |
288 | 324 | CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, &field) || |
289 | 322 | !ParseHashAlgorithm(field, &hash) || |
290 | 178 | !params_parser.ReadTag( |
291 | 178 | CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, &field) || |
292 | 175 | !ParseMaskGenAlgorithm(field, &mgf1_hash) || |
293 | 148 | !params_parser.ReadConstructed( |
294 | 148 | CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 2, |
295 | 148 | &salt_length_parser) || |
296 | 143 | !salt_length_parser.ReadUint64(&salt_length) || |
297 | 193 | salt_length_parser.HasMore() || params_parser.HasMore()) { |
298 | 193 | return std::nullopt; |
299 | 193 | } |
300 | | |
301 | | // Only combinations of RSASSA-PSS-params specified by TLS 1.3 (RFC 8446) are |
302 | | // supported. |
303 | 131 | if (hash != mgf1_hash) { |
304 | 3 | return std::nullopt; // TLS 1.3 always matches MGF-1 and message hash. |
305 | 3 | } |
306 | 128 | if (hash == DigestAlgorithm::Sha256 && salt_length == 32) { |
307 | 2 | return SignatureAlgorithm::kRsaPssSha256; |
308 | 2 | } |
309 | 126 | if (hash == DigestAlgorithm::Sha384 && salt_length == 48) { |
310 | 2 | return SignatureAlgorithm::kRsaPssSha384; |
311 | 2 | } |
312 | 124 | if (hash == DigestAlgorithm::Sha512 && salt_length == 64) { |
313 | 2 | return SignatureAlgorithm::kRsaPssSha512; |
314 | 2 | } |
315 | | |
316 | 122 | return std::nullopt; |
317 | 124 | } |
318 | | |
319 | | } // namespace |
320 | | |
321 | | [[nodiscard]] bool ParseAlgorithmIdentifier(der::Input input, |
322 | | der::Input *algorithm, |
323 | 2.61k | der::Input *parameters) { |
324 | 2.61k | der::Parser parser(input); |
325 | | |
326 | 2.61k | der::Parser algorithm_identifier_parser; |
327 | 2.61k | if (!parser.ReadSequence(&algorithm_identifier_parser)) { |
328 | 5 | return false; |
329 | 5 | } |
330 | | |
331 | | // There shouldn't be anything after the sequence. This is by definition, |
332 | | // as the input to this function is expected to be a single |
333 | | // AlgorithmIdentifier. |
334 | 2.61k | if (parser.HasMore()) { |
335 | 2 | return false; |
336 | 2 | } |
337 | | |
338 | 2.60k | if (!algorithm_identifier_parser.ReadTag(CBS_ASN1_OBJECT, algorithm)) { |
339 | 1.40k | return false; |
340 | 1.40k | } |
341 | | |
342 | | // Read the optional parameters to a der::Input. The parameters can be at |
343 | | // most one TLV (for instance NULL or a sequence). |
344 | | // |
345 | | // Note that nothing is allowed after the single optional "parameters" TLV. |
346 | | // This is because RFC 5912's notation for AlgorithmIdentifier doesn't |
347 | | // explicitly list an extension point after "parameters". |
348 | 1.20k | *parameters = der::Input(); |
349 | 1.20k | if (algorithm_identifier_parser.HasMore() && |
350 | 874 | !algorithm_identifier_parser.ReadRawTLV(parameters)) { |
351 | 86 | return false; |
352 | 86 | } |
353 | 1.11k | return !algorithm_identifier_parser.HasMore(); |
354 | 1.20k | } |
355 | | |
356 | 775 | [[nodiscard]] bool ParseHashAlgorithm(der::Input input, DigestAlgorithm *out) { |
357 | 775 | CBS cbs; |
358 | 775 | CBS_init(&cbs, input.data(), input.size()); |
359 | 775 | const EVP_MD *md = EVP_parse_digest_algorithm(&cbs); |
360 | | |
361 | 775 | if (md == EVP_sha1()) { |
362 | 72 | *out = DigestAlgorithm::Sha1; |
363 | 703 | } else if (md == EVP_sha256()) { |
364 | 112 | *out = DigestAlgorithm::Sha256; |
365 | 591 | } else if (md == EVP_sha384()) { |
366 | 100 | *out = DigestAlgorithm::Sha384; |
367 | 491 | } else if (md == EVP_sha512()) { |
368 | 111 | *out = DigestAlgorithm::Sha512; |
369 | 380 | } else { |
370 | | // TODO(eroman): Support MD2, MD4, MD5 for completeness? |
371 | | // Unsupported digest algorithm. |
372 | 380 | return false; |
373 | 380 | } |
374 | | |
375 | 395 | return true; |
376 | 775 | } |
377 | | |
378 | | std::optional<SignatureAlgorithm> ParseSignatureAlgorithm( |
379 | 2.44k | der::Input algorithm_identifier) { |
380 | 2.44k | der::Input oid; |
381 | 2.44k | der::Input params; |
382 | 2.44k | if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, ¶ms)) { |
383 | 1.50k | return std::nullopt; |
384 | 1.50k | } |
385 | | |
386 | | // TODO(eroman): Each OID is tested for equality in order, which is not |
387 | | // particularly efficient. |
388 | | |
389 | | // RFC 5912 requires that the parameters for RSA PKCS#1 v1.5 algorithms be |
390 | | // NULL ("PARAMS TYPE NULL ARE required"), however an empty parameter is also |
391 | | // allowed for compatibility with non-compliant OCSP responders. |
392 | | // |
393 | | // TODO(svaldez): Add warning about non-strict parsing. |
394 | 939 | if (oid == der::Input(kOidSha1WithRsaEncryption) && IsNullOrEmpty(params)) { |
395 | 33 | return SignatureAlgorithm::kRsaPkcs1Sha1; |
396 | 33 | } |
397 | 906 | if (oid == der::Input(kOidSha256WithRsaEncryption) && IsNullOrEmpty(params)) { |
398 | 14 | return SignatureAlgorithm::kRsaPkcs1Sha256; |
399 | 14 | } |
400 | 892 | if (oid == der::Input(kOidSha384WithRsaEncryption) && IsNullOrEmpty(params)) { |
401 | 17 | return SignatureAlgorithm::kRsaPkcs1Sha384; |
402 | 17 | } |
403 | 875 | if (oid == der::Input(kOidSha512WithRsaEncryption) && IsNullOrEmpty(params)) { |
404 | 8 | return SignatureAlgorithm::kRsaPkcs1Sha512; |
405 | 8 | } |
406 | 867 | if (oid == der::Input(kOidSha1WithRsaSignature) && IsNullOrEmpty(params)) { |
407 | 106 | return SignatureAlgorithm::kRsaPkcs1Sha1; |
408 | 106 | } |
409 | | |
410 | | // RFC 5912 requires that the parameters for ECDSA algorithms be absent |
411 | | // ("PARAMS TYPE NULL ARE absent"): |
412 | 761 | if (oid == der::Input(kOidEcdsaWithSha1) && params.empty()) { |
413 | 2 | return SignatureAlgorithm::kEcdsaSha1; |
414 | 2 | } |
415 | 759 | if (oid == der::Input(kOidEcdsaWithSha256) && params.empty()) { |
416 | 9 | return SignatureAlgorithm::kEcdsaSha256; |
417 | 9 | } |
418 | 750 | if (oid == der::Input(kOidEcdsaWithSha384) && params.empty()) { |
419 | 5 | return SignatureAlgorithm::kEcdsaSha384; |
420 | 5 | } |
421 | 745 | if (oid == der::Input(kOidEcdsaWithSha512) && params.empty()) { |
422 | 5 | return SignatureAlgorithm::kEcdsaSha512; |
423 | 5 | } |
424 | | |
425 | | // RFC 9881 requires that the parameters for ML-DSA algorithms be absent |
426 | | // ("The contents of the parameters component for each algorithm MUST be |
427 | | // absent."); |
428 | 740 | if (oid == der::Input(kOidAlgMldsa44) && params.empty()) { |
429 | 3 | return SignatureAlgorithm::kMldsa44; |
430 | 3 | } |
431 | 737 | if (oid == der::Input(kOidAlgMldsa65) && params.empty()) { |
432 | 3 | return SignatureAlgorithm::kMldsa65; |
433 | 3 | } |
434 | 734 | if (oid == der::Input(kOidAlgMldsa87) && params.empty()) { |
435 | 3 | return SignatureAlgorithm::kMldsa87; |
436 | 3 | } |
437 | | |
438 | 731 | if (oid == der::Input(kOidRsaSsaPss)) { |
439 | 342 | return ParseRsaPss(params); |
440 | 342 | } |
441 | | |
442 | 389 | if (oid == der::Input(kOidAlgMtcProofDraftDavidben08) && params.empty()) { |
443 | 1 | return SignatureAlgorithm::kMtcProofDraftDavidben08; |
444 | 1 | } |
445 | | |
446 | | // Unknown signature algorithm. |
447 | 388 | return std::nullopt; |
448 | 389 | } |
449 | | |
450 | | std::optional<DigestAlgorithm> GetTlsServerEndpointDigestAlgorithm( |
451 | 0 | SignatureAlgorithm alg) { |
452 | | // See RFC 5929, section 4.1. RFC 5929 breaks the signature algorithm |
453 | | // abstraction by trying to extract individual digest algorithms. (While |
454 | | // common, this is not a universal property of signature algorithms.) We |
455 | | // implement this within the library, so callers do not need to condition over |
456 | | // all algorithms. |
457 | 0 | switch (alg) { |
458 | | // If the single digest algorithm is SHA-1, use SHA-256. |
459 | 0 | case SignatureAlgorithm::kRsaPkcs1Sha1: |
460 | 0 | case SignatureAlgorithm::kEcdsaSha1: |
461 | 0 | return DigestAlgorithm::Sha256; |
462 | | |
463 | 0 | case SignatureAlgorithm::kRsaPkcs1Sha256: |
464 | 0 | case SignatureAlgorithm::kEcdsaSha256: |
465 | 0 | return DigestAlgorithm::Sha256; |
466 | | |
467 | 0 | case SignatureAlgorithm::kRsaPkcs1Sha384: |
468 | 0 | case SignatureAlgorithm::kEcdsaSha384: |
469 | 0 | return DigestAlgorithm::Sha384; |
470 | | |
471 | 0 | case SignatureAlgorithm::kRsaPkcs1Sha512: |
472 | 0 | case SignatureAlgorithm::kEcdsaSha512: |
473 | 0 | return DigestAlgorithm::Sha512; |
474 | | |
475 | | // It is ambiguous whether hash-matching RSASSA-PSS instantiations count as |
476 | | // using one or multiple digests, but the corresponding digest is the only |
477 | | // reasonable interpretation. |
478 | 0 | case SignatureAlgorithm::kRsaPssSha256: |
479 | 0 | return DigestAlgorithm::Sha256; |
480 | 0 | case SignatureAlgorithm::kRsaPssSha384: |
481 | 0 | return DigestAlgorithm::Sha384; |
482 | 0 | case SignatureAlgorithm::kRsaPssSha512: |
483 | 0 | return DigestAlgorithm::Sha512; |
484 | | |
485 | | // RFC 5929 (nor other references) does not define digests to use for these |
486 | | // signature algorithms: |
487 | 0 | case SignatureAlgorithm::kMtcProofDraftDavidben08: |
488 | 0 | case SignatureAlgorithm::kMldsa44: |
489 | 0 | case SignatureAlgorithm::kMldsa65: |
490 | 0 | case SignatureAlgorithm::kMldsa87: |
491 | 0 | return std::nullopt; |
492 | 0 | } |
493 | 0 | return std::nullopt; |
494 | 0 | } |
495 | | |
496 | | BSSL_NAMESPACE_END |