Coverage Report

Created: 2026-05-11 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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, &params)) {
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(&params_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, &params)) {
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