summaryrefslogtreecommitdiffstats
path: root/net/cert/internal/signature_algorithm.cc
blob: d36eebe627bcf67f696ca2237ddf4b839b55439e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/cert/internal/signature_algorithm.h"

#include "base/numerics/safe_math.h"
#include "net/der/input.h"
#include "net/der/parse_values.h"
#include "net/der/parser.h"

namespace net {

namespace {

// From RFC 5912:
//
//     sha1WithRSAEncryption OBJECT IDENTIFIER ::= {
//      iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
//      pkcs-1(1) 5 }
//
// In dotted notation: 1.2.840.113549.1.1.5
const uint8_t kOidSha1WithRsaEncryption[] =
    {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05};

// sha1WithRSASignature is a deprecated equivalent of
// sha1WithRSAEncryption.
//
// It originates from the NIST Open Systems Environment (OSE)
// Implementor's Workshop (OIW).
//
// It is supported for compatibility with Microsoft's certificate APIs and
// tools, particularly makecert.exe, which default(ed/s) to this OID for SHA-1.
//
// See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1042479
//
// In dotted notation: 1.3.14.3.2.29
const uint8_t kOidSha1WithRsaSignature[] = {0x2b, 0x0e, 0x03, 0x02, 0x1d};

// From RFC 5912:
//
//     pkcs-1  OBJECT IDENTIFIER  ::=
//         { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }

// From RFC 5912:
//
//     sha256WithRSAEncryption  OBJECT IDENTIFIER  ::=  { pkcs-1 11 }
//
// In dotted notation: 1.2.840.113549.1.1.11
const uint8_t kOidSha256WithRsaEncryption[] =
    {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b};

// From RFC 5912:
//
//     sha384WithRSAEncryption  OBJECT IDENTIFIER  ::=  { pkcs-1 12 }
//
// In dotted notation: 1.2.840.113549.1.1.11
const uint8_t kOidSha384WithRsaEncryption[] =
    {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c};

// From RFC 5912:
//
//     sha512WithRSAEncryption  OBJECT IDENTIFIER  ::=  { pkcs-1 13 }
//
// In dotted notation: 1.2.840.113549.1.1.13
const uint8_t kOidSha512WithRsaEncryption[] =
    {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d};

// From RFC 5912:
//
//     ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
//      iso(1) member-body(2) us(840) ansi-X9-62(10045)
//      signatures(4) 1 }
//
// In dotted notation: 1.2.840.10045.4.1
const uint8_t kOidEcdsaWithSha1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01};

// From RFC 5912:
//
//     ecdsa-with-SHA256 OBJECT IDENTIFIER ::= {
//      iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
//      ecdsa-with-SHA2(3) 2 }
//
// In dotted notation: 1.2.840.10045.4.3.2
const uint8_t kOidEcdsaWithSha256[] =
    {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02};

// From RFC 5912:
//
//     ecdsa-with-SHA384 OBJECT IDENTIFIER ::= {
//      iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
//      ecdsa-with-SHA2(3) 3 }
//
// In dotted notation: 1.2.840.10045.4.3.3
const uint8_t kOidEcdsaWithSha384[] =
    {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03};

// From RFC 5912:
//
//     ecdsa-with-SHA512 OBJECT IDENTIFIER ::= {
//      iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
//      ecdsa-with-SHA2(3) 4 }
//
// In dotted notation: 1.2.840.10045.4.3.4
const uint8_t kOidEcdsaWithSha512[] =
    {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04};

// From RFC 5912:
//
//     id-RSASSA-PSS  OBJECT IDENTIFIER  ::=  { pkcs-1 10 }
//
// In dotted notation: 1.2.840.113549.1.1.10
const uint8_t kOidRsaSsaPss[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                                 0x0d, 0x01, 0x01, 0x0a};

// From RFC 5912:
//
//     id-sha1 OBJECT IDENTIFIER ::= {
//      iso(1) identified-organization(3) oiw(14) secsig(3)
//      algorithm(2) 26 }
//
// In dotted notation: 1.3.14.3.2.26
const uint8_t kOidSha1[] = {0x2B, 0x0E, 0x03, 0x02, 0x1A};

// From RFC 5912:
//
//     id-sha256  OBJECT IDENTIFIER  ::=
//         { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
//         csor(3) nistAlgorithms(4) hashalgs(2) 1 }
//
// In dotted notation: 2.16.840.1.101.3.4.2.1
const uint8_t kOidSha256[] = {0x60, 0x86, 0x48, 0x01, 0x65,
                              0x03, 0x04, 0x02, 0x01};

// From RFC 5912:
//
//     id-sha384  OBJECT IDENTIFIER  ::=
//         { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
//         csor(3) nistAlgorithms(4) hashalgs(2) 2 }
//
// In dotted notation: 2.16.840.1.101.3.4.2.2
const uint8_t kOidSha384[] = {0x60, 0x86, 0x48, 0x01, 0x65,
                              0x03, 0x04, 0x02, 0x02};

// From RFC 5912:
//
//     id-sha512  OBJECT IDENTIFIER  ::=
//         { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
//         csor(3) nistAlgorithms(4) hashalgs(2) 3 }
//
// In dotted notation: 2.16.840.1.101.3.4.2.3
const uint8_t kOidSha512[] = {0x60, 0x86, 0x48, 0x01, 0x65,
                              0x03, 0x04, 0x02, 0x03};

// From RFC 5912:
//
//     id-mgf1  OBJECT IDENTIFIER  ::=  { pkcs-1 8 }
//
// In dotted notation: 1.2.840.113549.1.1.8
const uint8_t kOidMgf1[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
                            0x0d, 0x01, 0x01, 0x08};

// RFC 5280 section 4.1.1.2 defines signatureAlgorithm as:
//
//     AlgorithmIdentifier  ::=  SEQUENCE  {
//          algorithm               OBJECT IDENTIFIER,
//          parameters              ANY DEFINED BY algorithm OPTIONAL  }
WARN_UNUSED_RESULT bool ParseAlgorithmIdentifier(const der::Input& input,
                                                 der::Input* algorithm,
                                                 der::Input* parameters) {
  der::Parser parser(input);

  der::Parser algorithm_identifier_parser;
  if (!parser.ReadSequence(&algorithm_identifier_parser))
    return false;

  // There shouldn't be anything after the sequence. This is by definition,
  // as the input to this function is expected to be a single
  // AlgorithmIdentifier.
  if (parser.HasMore())
    return false;

  if (!algorithm_identifier_parser.ReadTag(der::kOid, algorithm))
    return false;

  // Read the optional parameters to a der::Input. The parameters can be at
  // most one TLV (for instance NULL or a sequence).
  //
  // Note that nothing is allowed after the single optional "parameters" TLV.
  // This is because RFC 5912's notation for AlgorithmIdentifier doesn't
  // explicitly list an extension point after "parameters".
  *parameters = der::Input();
  if (algorithm_identifier_parser.HasMore() &&
      !algorithm_identifier_parser.ReadRawTLV(parameters)) {
    return false;
  }
  return !algorithm_identifier_parser.HasMore();
}

// Returns true if |input| is empty.
WARN_UNUSED_RESULT bool IsEmpty(const der::Input& input) {
  return input.Length() == 0;
}

// Returns true if the entirety of the input is a NULL value.
WARN_UNUSED_RESULT bool IsNull(const der::Input& input) {
  der::Parser parser(input);
  der::Input null_value;
  if (!parser.ReadTag(der::kNull, &null_value))
    return false;

  // NULL values are TLV encoded; the value is expected to be empty.
  if (!IsEmpty(null_value))
    return false;

  // By definition of this function, the entire input must be a NULL.
  return !parser.HasMore();
}

// Parses an RSA PKCS#1 v1.5 signature algorithm given the DER-encoded
// "parameters" from the parsed AlgorithmIdentifier, and the hash algorithm
// that was implied by the AlgorithmIdentifier's OID.
//
// Returns a nullptr on failure.
//
// RFC 5912 requires that the parameters for RSA PKCS#1 v1.5 algorithms be NULL
// ("PARAMS TYPE NULL ARE required"):
//
//     sa-rsaWithSHA1 SIGNATURE-ALGORITHM ::= {
//      IDENTIFIER sha1WithRSAEncryption
//      PARAMS TYPE NULL ARE required
//      HASHES { mda-sha1 }
//      PUBLIC-KEYS { pk-rsa }
//      SMIME-CAPS {IDENTIFIED BY sha1WithRSAEncryption }
//     }
//
//     sa-sha256WithRSAEncryption SIGNATURE-ALGORITHM ::= {
//         IDENTIFIER sha256WithRSAEncryption
//         PARAMS TYPE NULL ARE required
//         HASHES { mda-sha256 }
//         PUBLIC-KEYS { pk-rsa }
//         SMIME-CAPS { IDENTIFIED BY sha256WithRSAEncryption }
//     }
//
//     sa-sha384WithRSAEncryption SIGNATURE-ALGORITHM ::= {
//         IDENTIFIER sha384WithRSAEncryption
//         PARAMS TYPE NULL ARE required
//         HASHES { mda-sha384 }
//         PUBLIC-KEYS { pk-rsa }
//         SMIME-CAPS { IDENTIFIED BY sha384WithRSAEncryption }
//     }
//
//     sa-sha512WithRSAEncryption SIGNATURE-ALGORITHM ::= {
//         IDENTIFIER sha512WithRSAEncryption
//         PARAMS TYPE NULL ARE required
//         HASHES { mda-sha512 }
//         PUBLIC-KEYS { pk-rsa }
//         SMIME-CAPS { IDENTIFIED BY sha512WithRSAEncryption }
//     }
scoped_ptr<SignatureAlgorithm> ParseRsaPkcs1(DigestAlgorithm digest,
                                             const der::Input& params) {
  if (!IsNull(params))
    return nullptr;

  return SignatureAlgorithm::CreateRsaPkcs1(digest);
}

// Parses an ECDSA signature algorithm given the DER-encoded "parameters" from
// the parsed AlgorithmIdentifier, and the hash algorithm that was implied by
// the AlgorithmIdentifier's OID.
//
// On failure returns a nullptr.
//
// RFC 5912 requires that the parameters for ECDSA algorithms be absent
// ("PARAMS TYPE NULL ARE absent"):
//
//     sa-ecdsaWithSHA1 SIGNATURE-ALGORITHM ::= {
//      IDENTIFIER ecdsa-with-SHA1
//      VALUE ECDSA-Sig-Value
//      PARAMS TYPE NULL ARE absent
//      HASHES { mda-sha1 }
//      PUBLIC-KEYS { pk-ec }
//      SMIME-CAPS {IDENTIFIED BY ecdsa-with-SHA1 }
//     }
//
//     sa-ecdsaWithSHA256 SIGNATURE-ALGORITHM ::= {
//      IDENTIFIER ecdsa-with-SHA256
//      VALUE ECDSA-Sig-Value
//      PARAMS TYPE NULL ARE absent
//      HASHES { mda-sha256 }
//      PUBLIC-KEYS { pk-ec }
//      SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA256 }
//     }
//
//     sa-ecdsaWithSHA384 SIGNATURE-ALGORITHM ::= {
//      IDENTIFIER ecdsa-with-SHA384
//      VALUE ECDSA-Sig-Value
//      PARAMS TYPE NULL ARE absent
//      HASHES { mda-sha384 }
//      PUBLIC-KEYS { pk-ec }
//      SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA384 }
//     }
//
//     sa-ecdsaWithSHA512 SIGNATURE-ALGORITHM ::= {
//      IDENTIFIER ecdsa-with-SHA512
//      VALUE ECDSA-Sig-Value
//      PARAMS TYPE NULL ARE absent
//      HASHES { mda-sha512 }
//      PUBLIC-KEYS { pk-ec }
//      SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA512 }
//     }
scoped_ptr<SignatureAlgorithm> ParseEcdsa(DigestAlgorithm digest,
                                          const der::Input& params) {
  if (!IsEmpty(params))
    return nullptr;

  return SignatureAlgorithm::CreateEcdsa(digest);
}

// Parses a HashAlgorithm as defined by RFC 5912:
//
//     HashAlgorithm  ::=  AlgorithmIdentifier{DIGEST-ALGORITHM,
//                             {HashAlgorithms}}
//
//     HashAlgorithms DIGEST-ALGORITHM ::=  {
//         { IDENTIFIER id-sha1 PARAMS TYPE NULL ARE preferredPresent } |
//         { IDENTIFIER id-sha224 PARAMS TYPE NULL ARE preferredPresent } |
//         { IDENTIFIER id-sha256 PARAMS TYPE NULL ARE preferredPresent } |
//         { IDENTIFIER id-sha384 PARAMS TYPE NULL ARE preferredPresent } |
//         { IDENTIFIER id-sha512 PARAMS TYPE NULL ARE preferredPresent }
//     }
WARN_UNUSED_RESULT bool ParseHashAlgorithm(const der::Input input,
                                           DigestAlgorithm* out) {
  der::Input oid;
  der::Input params;
  if (!ParseAlgorithmIdentifier(input, &oid, &params))
    return false;

  DigestAlgorithm hash;

  if (oid.Equals(der::Input(kOidSha1))) {
    hash = DigestAlgorithm::Sha1;
  } else if (oid.Equals(der::Input(kOidSha256))) {
    hash = DigestAlgorithm::Sha256;
  } else if (oid.Equals(der::Input(kOidSha384))) {
    hash = DigestAlgorithm::Sha384;
  } else if (oid.Equals(der::Input(kOidSha512))) {
    hash = DigestAlgorithm::Sha512;
  } else {
    // Unsupported digest algorithm.
    return false;
  }

  // From RFC 5912: "PARAMS TYPE NULL ARE preferredPresent". Which is to say
  // the can either be absent, or NULL.
  if (!IsEmpty(params) && !IsNull(params))
    return false;

  *out = hash;
  return true;
}

// Parses a MaskGenAlgorithm as defined by RFC 5912:
//
//     MaskGenAlgorithm ::= AlgorithmIdentifier{ALGORITHM,
//                             {PKCS1MGFAlgorithms}}
//
//     mgf1SHA1 MaskGenAlgorithm ::= {
//         algorithm id-mgf1,
//         parameters HashAlgorithm : sha1Identifier
//     }
//
//     --
//     --  Define the set of mask generation functions
//     --
//     --  If the identifier is id-mgf1, any of the listed hash
//     --    algorithms may be used.
//     --
//
//     PKCS1MGFAlgorithms ALGORITHM ::= {
//         { IDENTIFIER id-mgf1 PARAMS TYPE HashAlgorithm ARE required },
//         ...
//     }
//
// Note that the possible mask gen algorithms is extensible. However at present
// the only function supported is MGF1, as that is the singular mask gen
// function defined by RFC 4055 / RFC 5912.
WARN_UNUSED_RESULT bool ParseMaskGenAlgorithm(const der::Input input,
                                              DigestAlgorithm* mgf1_hash) {
  der::Input oid;
  der::Input params;
  if (!ParseAlgorithmIdentifier(input, &oid, &params))
    return false;

  // MGF1 is the only supported mask generation algorithm.
  if (!oid.Equals(der::Input(kOidMgf1)))
    return false;

  return ParseHashAlgorithm(params, mgf1_hash);
}

// Consumes an optional, explicitly-tagged INTEGER from |parser|, using the
// indicated context-specific class number. Values greater than 32-bits will be
// rejected.
//
// Returns true on success and sets |*present| to true if the field was present.
WARN_UNUSED_RESULT bool ReadOptionalContextSpecificUint32(der::Parser* parser,
                                                          uint8_t class_number,
                                                          uint32_t* out,
                                                          bool* present) {
  der::Input value;
  bool has_value;

  // Read the context specific value.
  if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(class_number),
                               &value, &has_value)) {
    return false;
  }

  if (has_value) {
    // Parse the integer contained in it.
    der::Parser number_parser(value);
    uint64_t uint64_value;

    if (!number_parser.ReadUint64(&uint64_value))
      return false;
    if (number_parser.HasMore())
      return false;

    // Cast the number to a uint32_t
    base::CheckedNumeric<uint32_t> casted(uint64_value);
    if (!casted.IsValid())
      return false;
    *out = casted.ValueOrDie();
  }

  *present = has_value;
  return true;
}

// Parses the parameters for an RSASSA-PSS signature algorithm, as defined by
// RFC 5912:
//
//     sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= {
//         IDENTIFIER id-RSASSA-PSS
//         PARAMS TYPE RSASSA-PSS-params ARE required
//         HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384
//                      | mda-sha512 }
//         PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS }
//         SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS }
//     }
//
//     RSASSA-PSS-params  ::=  SEQUENCE  {
//         hashAlgorithm     [0] HashAlgorithm DEFAULT sha1Identifier,
//         maskGenAlgorithm  [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
//         saltLength        [2] INTEGER DEFAULT 20,
//         trailerField      [3] INTEGER DEFAULT 1
//     }
//
// Which is to say the parameters MUST be present, and of type
// RSASSA-PSS-params.
scoped_ptr<SignatureAlgorithm> ParseRsaPss(const der::Input& params) {
  der::Parser parser(params);
  der::Parser params_parser;
  if (!parser.ReadSequence(&params_parser))
    return nullptr;

  // There shouldn't be anything after the sequence (by definition the
  // parameters is a single sequence).
  if (parser.HasMore())
    return nullptr;

  bool has_field;
  der::Input field;

  // Parse:
  //     hashAlgorithm     [0] HashAlgorithm DEFAULT sha1Identifier,
  DigestAlgorithm hash = DigestAlgorithm::Sha1;
  if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &field,
                                     &has_field)) {
    return nullptr;
  }
  if (has_field && !ParseHashAlgorithm(field, &hash))
    return nullptr;

  // Parse:
  //     maskGenAlgorithm  [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
  DigestAlgorithm mgf1_hash = DigestAlgorithm::Sha1;
  if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(1), &field,
                                     &has_field)) {
    return nullptr;
  }
  if (has_field && !ParseMaskGenAlgorithm(field, &mgf1_hash))
    return nullptr;

  // Parse:
  //     saltLength        [2] INTEGER DEFAULT 20,
  uint32_t salt_length = 20u;
  if (!ReadOptionalContextSpecificUint32(&params_parser, 2, &salt_length,
                                         &has_field)) {
    return nullptr;
  }

  // Parse:
  //     trailerField      [3] INTEGER DEFAULT 1
  uint32_t trailer_field = 1u;
  if (!ReadOptionalContextSpecificUint32(&params_parser, 3, &trailer_field,
                                         &has_field)) {
    return nullptr;
  }

  // RFC 4055 says that the trailer field must be 1:
  //
  //     The trailerField field is an integer.  It provides
  //     compatibility with IEEE Std 1363a-2004 [P1363A].  The value
  //     MUST be 1, which represents the trailer field with hexadecimal
  //     value 0xBC.  Other trailer fields, including the trailer field
  //     composed of HashID concatenated with 0xCC that is specified in
  //     IEEE Std 1363a, are not supported.  Implementations that
  //     perform signature generation MUST omit the trailerField field,
  //     indicating that the default trailer field value was used.
  //     Implementations that perform signature validation MUST
  //     recognize both a present trailerField field with value 1 and an
  //     absent trailerField field.
  if (trailer_field != 1)
    return nullptr;

  // There must not be any unconsumed data left. (RFC 5912 does not explicitly
  // include an extensibility point for RSASSA-PSS-params)
  if (params_parser.HasMore())
    return nullptr;

  return SignatureAlgorithm::CreateRsaPss(hash, mgf1_hash, salt_length);
}

}  // namespace

RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash,
                                   uint32_t salt_length)
    : mgf1_hash_(mgf1_hash), salt_length_(salt_length) {
}

SignatureAlgorithm::~SignatureAlgorithm() {
}

scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateFromDer(
    const der::Input& algorithm_identifier) {
  der::Input oid;
  der::Input params;
  if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, &params))
    return nullptr;

  // TODO(eroman): Each OID is tested for equality in order, which is not
  // particularly efficient.

  if (oid.Equals(der::Input(kOidSha1WithRsaEncryption)))
    return ParseRsaPkcs1(DigestAlgorithm::Sha1, params);

  if (oid.Equals(der::Input(kOidSha256WithRsaEncryption)))
    return ParseRsaPkcs1(DigestAlgorithm::Sha256, params);

  if (oid.Equals(der::Input(kOidSha384WithRsaEncryption)))
    return ParseRsaPkcs1(DigestAlgorithm::Sha384, params);

  if (oid.Equals(der::Input(kOidSha512WithRsaEncryption)))
    return ParseRsaPkcs1(DigestAlgorithm::Sha512, params);

  if (oid.Equals(der::Input(kOidEcdsaWithSha1)))
    return ParseEcdsa(DigestAlgorithm::Sha1, params);

  if (oid.Equals(der::Input(kOidEcdsaWithSha256)))
    return ParseEcdsa(DigestAlgorithm::Sha256, params);

  if (oid.Equals(der::Input(kOidEcdsaWithSha384)))
    return ParseEcdsa(DigestAlgorithm::Sha384, params);

  if (oid.Equals(der::Input(kOidEcdsaWithSha512)))
    return ParseEcdsa(DigestAlgorithm::Sha512, params);

  if (oid.Equals(der::Input(kOidRsaSsaPss)))
    return ParseRsaPss(params);

  if (oid.Equals(der::Input(kOidSha1WithRsaSignature)))
    return ParseRsaPkcs1(DigestAlgorithm::Sha1, params);

  return nullptr;  // Unsupported OID.
}

scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateRsaPkcs1(
    DigestAlgorithm digest) {
  return make_scoped_ptr(
      new SignatureAlgorithm(SignatureAlgorithmId::RsaPkcs1, digest, nullptr));
}

scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateEcdsa(
    DigestAlgorithm digest) {
  return make_scoped_ptr(
      new SignatureAlgorithm(SignatureAlgorithmId::Ecdsa, digest, nullptr));
}

scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateRsaPss(
    DigestAlgorithm digest,
    DigestAlgorithm mgf1_hash,
    uint32_t salt_length) {
  return make_scoped_ptr(new SignatureAlgorithm(
      SignatureAlgorithmId::RsaPss, digest,
      make_scoped_ptr(new RsaPssParameters(mgf1_hash, salt_length))));
}

const RsaPssParameters* SignatureAlgorithm::ParamsForRsaPss() const {
  if (algorithm_ == SignatureAlgorithmId::RsaPss)
    return static_cast<RsaPssParameters*>(params_.get());
  return nullptr;
}

SignatureAlgorithm::SignatureAlgorithm(
    SignatureAlgorithmId algorithm,
    DigestAlgorithm digest,
    scoped_ptr<SignatureAlgorithmParameters> params)
    : algorithm_(algorithm), digest_(digest), params_(params.Pass()) {
}

}  // namespace net