blob: 73d8bc1bc6390b3a31cf8af4d8f881135eeea088 [file] [log] [blame]
Bob Beckbc97b7a2023-04-18 08:35:15 -06001// Copyright 2015 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 "signature_algorithm.h"
6
Bob Beck5c7a2a02023-11-20 17:28:21 -07007#include <openssl/bytestring.h>
8#include <openssl/digest.h>
David Benjamin2a5db682024-02-06 21:56:57 -05009
Bob Beckbc97b7a2023-04-18 08:35:15 -060010#include "input.h"
11#include "parse_values.h"
12#include "parser.h"
Bob Beckbc97b7a2023-04-18 08:35:15 -060013
14namespace bssl {
15
16namespace {
17
18// From RFC 5912:
19//
20// sha1WithRSAEncryption OBJECT IDENTIFIER ::= {
21// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
22// pkcs-1(1) 5 }
23//
24// In dotted notation: 1.2.840.113549.1.1.5
25const uint8_t kOidSha1WithRsaEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
26 0x0d, 0x01, 0x01, 0x05};
27
28// sha1WithRSASignature is a deprecated equivalent of
29// sha1WithRSAEncryption.
30//
31// It originates from the NIST Open Systems Environment (OSE)
32// Implementor's Workshop (OIW).
33//
34// It is supported for compatibility with Microsoft's certificate APIs and
35// tools, particularly makecert.exe, which default(ed/s) to this OID for SHA-1.
36//
37// See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1042479
38//
39// In dotted notation: 1.3.14.3.2.29
40const uint8_t kOidSha1WithRsaSignature[] = {0x2b, 0x0e, 0x03, 0x02, 0x1d};
41
42// From RFC 5912:
43//
44// pkcs-1 OBJECT IDENTIFIER ::=
45// { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
46
47// From RFC 5912:
48//
49// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
50//
51// In dotted notation: 1.2.840.113549.1.1.11
52const uint8_t kOidSha256WithRsaEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
53 0x0d, 0x01, 0x01, 0x0b};
54
55// From RFC 5912:
56//
57// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
58//
59// In dotted notation: 1.2.840.113549.1.1.11
60const uint8_t kOidSha384WithRsaEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
61 0x0d, 0x01, 0x01, 0x0c};
62
63// From RFC 5912:
64//
65// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
66//
67// In dotted notation: 1.2.840.113549.1.1.13
68const uint8_t kOidSha512WithRsaEncryption[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
69 0x0d, 0x01, 0x01, 0x0d};
70
71// From RFC 5912:
72//
73// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
74// iso(1) member-body(2) us(840) ansi-X9-62(10045)
75// signatures(4) 1 }
76//
77// In dotted notation: 1.2.840.10045.4.1
78const uint8_t kOidEcdsaWithSha1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01};
79
80// From RFC 5912:
81//
82// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= {
83// iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
84// ecdsa-with-SHA2(3) 2 }
85//
86// In dotted notation: 1.2.840.10045.4.3.2
87const uint8_t kOidEcdsaWithSha256[] = {0x2a, 0x86, 0x48, 0xce,
88 0x3d, 0x04, 0x03, 0x02};
89
90// From RFC 5912:
91//
92// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= {
93// iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
94// ecdsa-with-SHA2(3) 3 }
95//
96// In dotted notation: 1.2.840.10045.4.3.3
97const uint8_t kOidEcdsaWithSha384[] = {0x2a, 0x86, 0x48, 0xce,
98 0x3d, 0x04, 0x03, 0x03};
99
100// From RFC 5912:
101//
102// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= {
103// iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
104// ecdsa-with-SHA2(3) 4 }
105//
106// In dotted notation: 1.2.840.10045.4.3.4
107const uint8_t kOidEcdsaWithSha512[] = {0x2a, 0x86, 0x48, 0xce,
108 0x3d, 0x04, 0x03, 0x04};
109
110// From RFC 5912:
111//
112// id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 }
113//
114// In dotted notation: 1.2.840.113549.1.1.10
115const uint8_t kOidRsaSsaPss[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
116 0x0d, 0x01, 0x01, 0x0a};
117
118// From RFC 5912:
119//
120// id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
121//
122// In dotted notation: 1.2.840.113549.1.1.8
123const uint8_t kOidMgf1[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
124 0x0d, 0x01, 0x01, 0x08};
125
Bob Beckbc97b7a2023-04-18 08:35:15 -0600126// Returns true if the entirety of the input is a NULL value.
David Benjamin81138bc2024-01-23 14:53:40 -0500127[[nodiscard]] bool IsNull(der::Input input) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600128 der::Parser parser(input);
129 der::Input null_value;
David Benjamin2a5db682024-02-06 21:56:57 -0500130 if (!parser.ReadTag(CBS_ASN1_NULL, &null_value)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600131 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700132 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600133
134 // NULL values are TLV encoded; the value is expected to be empty.
David Benjamin90ceeb02024-01-23 14:25:39 -0500135 if (!null_value.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600136 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700137 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600138
139 // By definition of this function, the entire input must be a NULL.
140 return !parser.HasMore();
141}
142
David Benjamin81138bc2024-01-23 14:53:40 -0500143[[nodiscard]] bool IsNullOrEmpty(der::Input input) {
David Benjamin90ceeb02024-01-23 14:25:39 -0500144 return IsNull(input) || input.empty();
Bob Beckbc97b7a2023-04-18 08:35:15 -0600145}
146
147// Parses a MaskGenAlgorithm as defined by RFC 5912:
148//
149// MaskGenAlgorithm ::= AlgorithmIdentifier{ALGORITHM,
150// {PKCS1MGFAlgorithms}}
151//
152// mgf1SHA1 MaskGenAlgorithm ::= {
153// algorithm id-mgf1,
154// parameters HashAlgorithm : sha1Identifier
155// }
156//
157// --
158// -- Define the set of mask generation functions
159// --
160// -- If the identifier is id-mgf1, any of the listed hash
161// -- algorithms may be used.
162// --
163//
164// PKCS1MGFAlgorithms ALGORITHM ::= {
165// { IDENTIFIER id-mgf1 PARAMS TYPE HashAlgorithm ARE required },
166// ...
167// }
168//
169// Note that the possible mask gen algorithms is extensible. However at present
170// the only function supported is MGF1, as that is the singular mask gen
171// function defined by RFC 4055 / RFC 5912.
172[[nodiscard]] bool ParseMaskGenAlgorithm(const der::Input input,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700173 DigestAlgorithm *mgf1_hash) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600174 der::Input oid;
175 der::Input params;
Bob Beck6beabf32023-11-21 09:43:52 -0700176 if (!ParseAlgorithmIdentifier(input, &oid, &params)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600177 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700178 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600179
180 // MGF1 is the only supported mask generation algorithm.
Bob Beck6beabf32023-11-21 09:43:52 -0700181 if (oid != der::Input(kOidMgf1)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600182 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700183 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600184
185 return ParseHashAlgorithm(params, mgf1_hash);
186}
187
188// Parses the parameters for an RSASSA-PSS signature algorithm, as defined by
189// RFC 5912:
190//
191// sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= {
192// IDENTIFIER id-RSASSA-PSS
193// PARAMS TYPE RSASSA-PSS-params ARE required
194// HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384
195// | mda-sha512 }
196// PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS }
197// SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS }
198// }
199//
200// RSASSA-PSS-params ::= SEQUENCE {
201// hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier,
202// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
203// saltLength [2] INTEGER DEFAULT 20,
204// trailerField [3] INTEGER DEFAULT 1
205// }
206//
207// Which is to say the parameters MUST be present, and of type
208// RSASSA-PSS-params. Additionally, we only support the RSA-PSS parameter
209// combinations representable by TLS 1.3 (RFC 8446).
210//
211// Note also that DER encoding (ITU-T X.690 section 11.5) prohibits
212// specifying default values explicitly. The parameter should instead be
213// omitted to indicate a default value.
David Benjamin81138bc2024-01-23 14:53:40 -0500214std::optional<SignatureAlgorithm> ParseRsaPss(der::Input params) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600215 der::Parser parser(params);
216 der::Parser params_parser;
217 if (!parser.ReadSequence(&params_parser)) {
218 return std::nullopt;
219 }
220
221 // There shouldn't be anything after the sequence (by definition the
222 // parameters is a single sequence).
223 if (parser.HasMore()) {
224 return std::nullopt;
225 }
226
227 // The default values for hashAlgorithm, maskGenAlgorithm, and saltLength
228 // correspond to SHA-1, which we do not support with RSA-PSS, so treat them as
229 // required fields. Explicitly-specified defaults will be rejected later, when
230 // we limit combinations. Additionally, as the trailerField is required to be
231 // the default, we simply ignore it and reject it as any other trailing data.
232 //
233 // hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier,
234 // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
235 // saltLength [2] INTEGER DEFAULT 20,
236 // trailerField [3] INTEGER DEFAULT 1
237 der::Input field;
238 DigestAlgorithm hash, mgf1_hash;
239 der::Parser salt_length_parser;
240 uint64_t salt_length;
David Benjamin2a5db682024-02-06 21:56:57 -0500241 if (!params_parser.ReadTag(
242 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, &field) ||
Bob Beckbc97b7a2023-04-18 08:35:15 -0600243 !ParseHashAlgorithm(field, &hash) ||
David Benjamin2a5db682024-02-06 21:56:57 -0500244 !params_parser.ReadTag(
245 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, &field) ||
Bob Beckbc97b7a2023-04-18 08:35:15 -0600246 !ParseMaskGenAlgorithm(field, &mgf1_hash) ||
David Benjamin2a5db682024-02-06 21:56:57 -0500247 !params_parser.ReadConstructed(
248 CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 2,
249 &salt_length_parser) ||
Bob Beckbc97b7a2023-04-18 08:35:15 -0600250 !salt_length_parser.ReadUint64(&salt_length) ||
251 salt_length_parser.HasMore() || params_parser.HasMore()) {
252 return std::nullopt;
253 }
254
255 // Only combinations of RSASSA-PSS-params specified by TLS 1.3 (RFC 8446) are
256 // supported.
257 if (hash != mgf1_hash) {
258 return std::nullopt; // TLS 1.3 always matches MGF-1 and message hash.
259 }
260 if (hash == DigestAlgorithm::Sha256 && salt_length == 32) {
261 return SignatureAlgorithm::kRsaPssSha256;
262 }
263 if (hash == DigestAlgorithm::Sha384 && salt_length == 48) {
264 return SignatureAlgorithm::kRsaPssSha384;
265 }
266 if (hash == DigestAlgorithm::Sha512 && salt_length == 64) {
267 return SignatureAlgorithm::kRsaPssSha512;
268 }
269
270 return std::nullopt;
271}
272
273} // namespace
274
David Benjamin81138bc2024-01-23 14:53:40 -0500275[[nodiscard]] bool ParseAlgorithmIdentifier(der::Input input,
Bob Beck5c7a2a02023-11-20 17:28:21 -0700276 der::Input *algorithm,
277 der::Input *parameters) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600278 der::Parser parser(input);
279
280 der::Parser algorithm_identifier_parser;
Bob Beck6beabf32023-11-21 09:43:52 -0700281 if (!parser.ReadSequence(&algorithm_identifier_parser)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600282 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700283 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600284
285 // There shouldn't be anything after the sequence. This is by definition,
286 // as the input to this function is expected to be a single
287 // AlgorithmIdentifier.
Bob Beck6beabf32023-11-21 09:43:52 -0700288 if (parser.HasMore()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600289 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700290 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600291
David Benjamin2a5db682024-02-06 21:56:57 -0500292 if (!algorithm_identifier_parser.ReadTag(CBS_ASN1_OBJECT, algorithm)) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600293 return false;
Bob Beck6beabf32023-11-21 09:43:52 -0700294 }
Bob Beckbc97b7a2023-04-18 08:35:15 -0600295
296 // Read the optional parameters to a der::Input. The parameters can be at
297 // most one TLV (for instance NULL or a sequence).
298 //
299 // Note that nothing is allowed after the single optional "parameters" TLV.
300 // This is because RFC 5912's notation for AlgorithmIdentifier doesn't
301 // explicitly list an extension point after "parameters".
302 *parameters = der::Input();
303 if (algorithm_identifier_parser.HasMore() &&
304 !algorithm_identifier_parser.ReadRawTLV(parameters)) {
305 return false;
306 }
307 return !algorithm_identifier_parser.HasMore();
308}
309
David Benjamin81138bc2024-01-23 14:53:40 -0500310[[nodiscard]] bool ParseHashAlgorithm(der::Input input, DigestAlgorithm *out) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600311 CBS cbs;
David Benjamin90ceeb02024-01-23 14:25:39 -0500312 CBS_init(&cbs, input.data(), input.size());
Bob Beck5c7a2a02023-11-20 17:28:21 -0700313 const EVP_MD *md = EVP_parse_digest_algorithm(&cbs);
Bob Beckbc97b7a2023-04-18 08:35:15 -0600314
315 if (md == EVP_sha1()) {
316 *out = DigestAlgorithm::Sha1;
317 } else if (md == EVP_sha256()) {
318 *out = DigestAlgorithm::Sha256;
319 } else if (md == EVP_sha384()) {
320 *out = DigestAlgorithm::Sha384;
321 } else if (md == EVP_sha512()) {
322 *out = DigestAlgorithm::Sha512;
323 } else {
324 // TODO(eroman): Support MD2, MD4, MD5 for completeness?
325 // Unsupported digest algorithm.
326 return false;
327 }
328
329 return true;
330}
331
332std::optional<SignatureAlgorithm> ParseSignatureAlgorithm(
David Benjamin81138bc2024-01-23 14:53:40 -0500333 der::Input algorithm_identifier) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600334 der::Input oid;
335 der::Input params;
336 if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, &params)) {
337 return std::nullopt;
338 }
339
340 // TODO(eroman): Each OID is tested for equality in order, which is not
341 // particularly efficient.
342
343 // RFC 5912 requires that the parameters for RSA PKCS#1 v1.5 algorithms be
344 // NULL ("PARAMS TYPE NULL ARE required"), however an empty parameter is also
345 // allowed for compatibility with non-compliant OCSP responders.
346 //
347 // TODO(svaldez): Add warning about non-strict parsing.
348 if (oid == der::Input(kOidSha1WithRsaEncryption) && IsNullOrEmpty(params)) {
349 return SignatureAlgorithm::kRsaPkcs1Sha1;
350 }
351 if (oid == der::Input(kOidSha256WithRsaEncryption) && IsNullOrEmpty(params)) {
352 return SignatureAlgorithm::kRsaPkcs1Sha256;
353 }
354 if (oid == der::Input(kOidSha384WithRsaEncryption) && IsNullOrEmpty(params)) {
355 return SignatureAlgorithm::kRsaPkcs1Sha384;
356 }
357 if (oid == der::Input(kOidSha512WithRsaEncryption) && IsNullOrEmpty(params)) {
358 return SignatureAlgorithm::kRsaPkcs1Sha512;
359 }
360 if (oid == der::Input(kOidSha1WithRsaSignature) && IsNullOrEmpty(params)) {
361 return SignatureAlgorithm::kRsaPkcs1Sha1;
362 }
363
364 // RFC 5912 requires that the parameters for ECDSA algorithms be absent
365 // ("PARAMS TYPE NULL ARE absent"):
David Benjamin90ceeb02024-01-23 14:25:39 -0500366 if (oid == der::Input(kOidEcdsaWithSha1) && params.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600367 return SignatureAlgorithm::kEcdsaSha1;
368 }
David Benjamin90ceeb02024-01-23 14:25:39 -0500369 if (oid == der::Input(kOidEcdsaWithSha256) && params.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600370 return SignatureAlgorithm::kEcdsaSha256;
371 }
David Benjamin90ceeb02024-01-23 14:25:39 -0500372 if (oid == der::Input(kOidEcdsaWithSha384) && params.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600373 return SignatureAlgorithm::kEcdsaSha384;
374 }
David Benjamin90ceeb02024-01-23 14:25:39 -0500375 if (oid == der::Input(kOidEcdsaWithSha512) && params.empty()) {
Bob Beckbc97b7a2023-04-18 08:35:15 -0600376 return SignatureAlgorithm::kEcdsaSha512;
377 }
378
379 if (oid == der::Input(kOidRsaSsaPss)) {
380 return ParseRsaPss(params);
381 }
382
383 // Unknown signature algorithm.
384 return std::nullopt;
385}
386
387std::optional<DigestAlgorithm> GetTlsServerEndpointDigestAlgorithm(
388 SignatureAlgorithm alg) {
389 // See RFC 5929, section 4.1. RFC 5929 breaks the signature algorithm
390 // abstraction by trying to extract individual digest algorithms. (While
391 // common, this is not a universal property of signature algorithms.) We
392 // implement this within the library, so callers do not need to condition over
393 // all algorithms.
394 switch (alg) {
395 // If the single digest algorithm is SHA-1, use SHA-256.
396 case SignatureAlgorithm::kRsaPkcs1Sha1:
397 case SignatureAlgorithm::kEcdsaSha1:
398 return DigestAlgorithm::Sha256;
399
400 case SignatureAlgorithm::kRsaPkcs1Sha256:
401 case SignatureAlgorithm::kEcdsaSha256:
402 return DigestAlgorithm::Sha256;
403
404 case SignatureAlgorithm::kRsaPkcs1Sha384:
405 case SignatureAlgorithm::kEcdsaSha384:
406 return DigestAlgorithm::Sha384;
407
408 case SignatureAlgorithm::kRsaPkcs1Sha512:
409 case SignatureAlgorithm::kEcdsaSha512:
410 return DigestAlgorithm::Sha512;
411
412 // It is ambiguous whether hash-matching RSASSA-PSS instantiations count as
413 // using one or multiple digests, but the corresponding digest is the only
414 // reasonable interpretation.
415 case SignatureAlgorithm::kRsaPssSha256:
416 return DigestAlgorithm::Sha256;
417 case SignatureAlgorithm::kRsaPssSha384:
418 return DigestAlgorithm::Sha384;
419 case SignatureAlgorithm::kRsaPssSha512:
420 return DigestAlgorithm::Sha512;
421 }
422 return std::nullopt;
423}
424
Bob Beck5c7a2a02023-11-20 17:28:21 -0700425} // namespace bssl