Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: net/cert/internal/signature_algorithm.cc

Issue 1217653006: Add DER parsing for rsaPss signature algorithms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@sign_parse_alg
Patch Set: rebase and use results of "git cl format" from new clang-format Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | net/cert/internal/signature_algorithm_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/cert/internal/signature_algorithm.h" 5 #include "net/cert/internal/signature_algorithm.h"
6 6
7 #include "base/numerics/safe_math.h"
7 #include "net/der/input.h" 8 #include "net/der/input.h"
9 #include "net/der/parse_values.h"
8 #include "net/der/parser.h" 10 #include "net/der/parser.h"
9 11
10 namespace net { 12 namespace net {
11 13
12 namespace { 14 namespace {
13 15
14 // From RFC 5912: 16 // From RFC 5912:
15 // 17 //
16 // sha1WithRSAEncryption OBJECT IDENTIFIER ::= { 18 // sha1WithRSAEncryption OBJECT IDENTIFIER ::= {
17 // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 19 // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 // From RFC 5912: 98 // From RFC 5912:
97 // 99 //
98 // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { 100 // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= {
99 // iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 101 // iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4)
100 // ecdsa-with-SHA2(3) 4 } 102 // ecdsa-with-SHA2(3) 4 }
101 // 103 //
102 // In dotted notation: 1.2.840.10045.4.3.4 104 // In dotted notation: 1.2.840.10045.4.3.4
103 const uint8_t kOidEcdsaWithSha512[] = 105 const uint8_t kOidEcdsaWithSha512[] =
104 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04}; 106 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04};
105 107
108 // From RFC 5912:
109 //
110 // id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 }
111 //
112 // In dotted notation: 1.2.840.113549.1.1.10
113 const uint8_t kOidRsaSsaPss[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
114 0x0d, 0x01, 0x01, 0x0a};
115
116 // From RFC 5912:
117 //
118 // id-sha1 OBJECT IDENTIFIER ::= {
119 // iso(1) identified-organization(3) oiw(14) secsig(3)
120 // algorithm(2) 26 }
121 //
122 // In dotted notation: 1.3.14.3.2.26
123 const uint8_t kOidSha1[] = {0x2B, 0x0E, 0x03, 0x02, 0x1A};
124
125 // From RFC 5912:
126 //
127 // id-sha256 OBJECT IDENTIFIER ::=
128 // { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
129 // csor(3) nistAlgorithms(4) hashalgs(2) 1 }
130 //
131 // In dotted notation: 2.16.840.1.101.3.4.2.1
132 const uint8_t kOidSha256[] = {0x60, 0x86, 0x48, 0x01, 0x65,
133 0x03, 0x04, 0x02, 0x01};
134
135 // From RFC 5912:
136 //
137 // id-sha384 OBJECT IDENTIFIER ::=
138 // { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
139 // csor(3) nistAlgorithms(4) hashalgs(2) 2 }
140 //
141 // In dotted notation: 2.16.840.1.101.3.4.2.2
142 const uint8_t kOidSha384[] = {0x60, 0x86, 0x48, 0x01, 0x65,
143 0x03, 0x04, 0x02, 0x02};
144
145 // From RFC 5912:
146 //
147 // id-sha512 OBJECT IDENTIFIER ::=
148 // { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
149 // csor(3) nistAlgorithms(4) hashalgs(2) 3 }
150 //
151 // In dotted notation: 2.16.840.1.101.3.4.2.3
152 const uint8_t kOidSha512[] = {0x60, 0x86, 0x48, 0x01, 0x65,
153 0x03, 0x04, 0x02, 0x03};
154
155 // From RFC 5912:
156 //
157 // id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
158 //
159 // In dotted notation: 1.2.840.113549.1.1.8
160 const uint8_t kOidMgf1[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
161 0x0d, 0x01, 0x01, 0x08};
162
106 // RFC 5280 section 4.1.1.2 defines signatureAlgorithm as: 163 // RFC 5280 section 4.1.1.2 defines signatureAlgorithm as:
107 // 164 //
108 // AlgorithmIdentifier ::= SEQUENCE { 165 // AlgorithmIdentifier ::= SEQUENCE {
109 // algorithm OBJECT IDENTIFIER, 166 // algorithm OBJECT IDENTIFIER,
110 // parameters ANY DEFINED BY algorithm OPTIONAL } 167 // parameters ANY DEFINED BY algorithm OPTIONAL }
111 WARN_UNUSED_RESULT bool ParseAlgorithmIdentifier(const der::Input& input, 168 WARN_UNUSED_RESULT bool ParseAlgorithmIdentifier(const der::Input& input,
112 der::Input* algorithm, 169 der::Input* algorithm,
113 der::Input* parameters) { 170 der::Input* parameters) {
114 der::Parser parser(input); 171 der::Parser parser(input);
115 172
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 // SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA512 } 310 // SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA512 }
254 // } 311 // }
255 scoped_ptr<SignatureAlgorithm> ParseEcdsa(DigestAlgorithm digest, 312 scoped_ptr<SignatureAlgorithm> ParseEcdsa(DigestAlgorithm digest,
256 const der::Input& params) { 313 const der::Input& params) {
257 if (!IsEmpty(params)) 314 if (!IsEmpty(params))
258 return nullptr; 315 return nullptr;
259 316
260 return SignatureAlgorithm::CreateEcdsa(digest); 317 return SignatureAlgorithm::CreateEcdsa(digest);
261 } 318 }
262 319
320 // Parses a HashAlgorithm as defined by RFC 5912:
321 //
322 // HashAlgorithm ::= AlgorithmIdentifier{DIGEST-ALGORITHM,
323 // {HashAlgorithms}}
324 //
325 // HashAlgorithms DIGEST-ALGORITHM ::= {
326 // { IDENTIFIER id-sha1 PARAMS TYPE NULL ARE preferredPresent } |
327 // { IDENTIFIER id-sha224 PARAMS TYPE NULL ARE preferredPresent } |
328 // { IDENTIFIER id-sha256 PARAMS TYPE NULL ARE preferredPresent } |
329 // { IDENTIFIER id-sha384 PARAMS TYPE NULL ARE preferredPresent } |
330 // { IDENTIFIER id-sha512 PARAMS TYPE NULL ARE preferredPresent }
331 // }
332 WARN_UNUSED_RESULT bool ParseHashAlgorithm(const der::Input input,
333 DigestAlgorithm* out) {
334 der::Input oid;
335 der::Input params;
336 if (!ParseAlgorithmIdentifier(input, &oid, &params))
337 return false;
338
339 DigestAlgorithm hash;
340
341 if (oid.Equals(der::Input(kOidSha1))) {
342 hash = DigestAlgorithm::Sha1;
343 } else if (oid.Equals(der::Input(kOidSha256))) {
344 hash = DigestAlgorithm::Sha256;
345 } else if (oid.Equals(der::Input(kOidSha384))) {
346 hash = DigestAlgorithm::Sha384;
347 } else if (oid.Equals(der::Input(kOidSha512))) {
348 hash = DigestAlgorithm::Sha512;
349 } else {
350 // Unsupported digest algorithm.
351 return false;
352 }
353
354 // From RFC 5912: "PARAMS TYPE NULL ARE preferredPresent". Which is to say
355 // the can either be absent, or NULL.
356 if (!IsEmpty(params) && !IsNull(params))
357 return false;
358
359 *out = hash;
360 return true;
361 }
362
363 // Parses a MaskGenAlgorithm as defined by RFC 5912:
364 //
365 // MaskGenAlgorithm ::= AlgorithmIdentifier{ALGORITHM,
366 // {PKCS1MGFAlgorithms}}
367 //
368 // mgf1SHA1 MaskGenAlgorithm ::= {
369 // algorithm id-mgf1,
370 // parameters HashAlgorithm : sha1Identifier
371 // }
372 //
373 // --
374 // -- Define the set of mask generation functions
375 // --
376 // -- If the identifier is id-mgf1, any of the listed hash
377 // -- algorithms may be used.
378 // --
379 //
380 // PKCS1MGFAlgorithms ALGORITHM ::= {
381 // { IDENTIFIER id-mgf1 PARAMS TYPE HashAlgorithm ARE required },
382 // ...
383 // }
384 //
385 // Note that the possible mask gen algorithms is extensible. However at present
386 // the only function supported is MGF1, as that is the singular mask gen
387 // function defined by RFC 4055 / RFC 5912.
388 WARN_UNUSED_RESULT bool ParseMaskGenAlgorithm(const der::Input input,
389 DigestAlgorithm* mgf1_hash) {
390 der::Input oid;
391 der::Input params;
392 if (!ParseAlgorithmIdentifier(input, &oid, &params))
393 return false;
394
395 // MGF1 is the only supported mask generation algorithm.
396 if (!oid.Equals(der::Input(kOidMgf1)))
397 return false;
398
399 return ParseHashAlgorithm(params, mgf1_hash);
400 }
401
402 // Consumes an optional, explicitly-tagged INTEGER from |parser|, using the
403 // indicated context-specific class number. Values greater than 32-bits will be
404 // rejected.
405 //
406 // Returns true on success and sets |*present| to true if the field was present.
407 WARN_UNUSED_RESULT bool ReadOptionalContextSpecificUint32(der::Parser* parser,
408 uint8_t class_number,
409 uint32_t* out,
410 bool* present) {
411 der::Input value;
412 bool has_value;
413
414 // Read the context specific value.
415 if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(class_number),
416 &value, &has_value)) {
417 return false;
418 }
419
420 if (has_value) {
421 // Parse the integer contained in it.
422 der::Parser number_parser(value);
423 uint64_t uint64_value;
424
425 if (!number_parser.ReadUint64(&uint64_value))
426 return false;
427 if (number_parser.HasMore())
428 return false;
429
430 // Cast the number to a uint32_t
431 base::CheckedNumeric<uint32_t> casted(uint64_value);
432 if (!casted.IsValid())
433 return false;
434 *out = casted.ValueOrDie();
435 }
436
437 *present = has_value;
438 return true;
439 }
440
441 // Parses the parameters for an RSASSA-PSS signature algorithm, as defined by
442 // RFC 5912:
443 //
444 // sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= {
445 // IDENTIFIER id-RSASSA-PSS
446 // PARAMS TYPE RSASSA-PSS-params ARE required
447 // HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384
448 // | mda-sha512 }
449 // PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS }
450 // SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS }
451 // }
452 //
453 // RSASSA-PSS-params ::= SEQUENCE {
454 // hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier,
455 // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
456 // saltLength [2] INTEGER DEFAULT 20,
457 // trailerField [3] INTEGER DEFAULT 1
458 // }
459 //
460 // Which is to say the parameters MUST be present, and of type
461 // RSASSA-PSS-params.
462 scoped_ptr<SignatureAlgorithm> ParseRsaPss(const der::Input& params) {
463 der::Parser parser(params);
464 der::Parser params_parser;
465 if (!parser.ReadSequence(&params_parser))
466 return nullptr;
467
468 // There shouldn't be anything after the sequence (by definition the
469 // parameters is a single sequence).
470 if (parser.HasMore())
471 return nullptr;
472
473 bool has_field;
474 der::Input field;
475
476 // Parse:
477 // hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier,
478 DigestAlgorithm hash = DigestAlgorithm::Sha1;
479 if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &field,
480 &has_field)) {
481 return nullptr;
482 }
483 if (has_field && !ParseHashAlgorithm(field, &hash))
484 return nullptr;
485
486 // Parse:
487 // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
488 DigestAlgorithm mgf1_hash = DigestAlgorithm::Sha1;
489 if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(1), &field,
490 &has_field)) {
491 return nullptr;
492 }
493 if (has_field && !ParseMaskGenAlgorithm(field, &mgf1_hash))
494 return nullptr;
495
496 // Parse:
497 // saltLength [2] INTEGER DEFAULT 20,
498 uint32_t salt_length = 20u;
499 if (!ReadOptionalContextSpecificUint32(&params_parser, 2, &salt_length,
500 &has_field)) {
501 return nullptr;
502 }
503
504 // Parse:
505 // trailerField [3] INTEGER DEFAULT 1
506 uint32_t trailer_field = 1u;
507 if (!ReadOptionalContextSpecificUint32(&params_parser, 3, &trailer_field,
508 &has_field)) {
509 return nullptr;
510 }
511
512 // RFC 4055 says that the trailer field must be 1:
513 //
514 // The trailerField field is an integer. It provides
515 // compatibility with IEEE Std 1363a-2004 [P1363A]. The value
516 // MUST be 1, which represents the trailer field with hexadecimal
517 // value 0xBC. Other trailer fields, including the trailer field
518 // composed of HashID concatenated with 0xCC that is specified in
519 // IEEE Std 1363a, are not supported. Implementations that
520 // perform signature generation MUST omit the trailerField field,
521 // indicating that the default trailer field value was used.
522 // Implementations that perform signature validation MUST
523 // recognize both a present trailerField field with value 1 and an
524 // absent trailerField field.
525 if (trailer_field != 1)
526 return nullptr;
527
528 // There must not be any unconsumed data left. (RFC 5912 does not explicitly
529 // include an extensibility point for RSASSA-PSS-params)
530 if (params_parser.HasMore())
531 return nullptr;
532
533 return SignatureAlgorithm::CreateRsaPss(hash, mgf1_hash, salt_length);
534 }
535
263 } // namespace 536 } // namespace
264 537
265 RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash, 538 RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash,
266 uint32_t salt_length) 539 uint32_t salt_length)
267 : mgf1_hash_(mgf1_hash), salt_length_(salt_length) { 540 : mgf1_hash_(mgf1_hash), salt_length_(salt_length) {
268 } 541 }
269 542
270 bool RsaPssParameters::Equals(const RsaPssParameters* other) const { 543 bool RsaPssParameters::Equals(const RsaPssParameters* other) const {
271 return mgf1_hash_ == other->mgf1_hash_ && salt_length_ == other->salt_length_; 544 return mgf1_hash_ == other->mgf1_hash_ && salt_length_ == other->salt_length_;
272 } 545 }
(...skipping 28 matching lines...) Expand all
301 574
302 if (oid.Equals(der::Input(kOidEcdsaWithSha256))) 575 if (oid.Equals(der::Input(kOidEcdsaWithSha256)))
303 return ParseEcdsa(DigestAlgorithm::Sha256, params); 576 return ParseEcdsa(DigestAlgorithm::Sha256, params);
304 577
305 if (oid.Equals(der::Input(kOidEcdsaWithSha384))) 578 if (oid.Equals(der::Input(kOidEcdsaWithSha384)))
306 return ParseEcdsa(DigestAlgorithm::Sha384, params); 579 return ParseEcdsa(DigestAlgorithm::Sha384, params);
307 580
308 if (oid.Equals(der::Input(kOidEcdsaWithSha512))) 581 if (oid.Equals(der::Input(kOidEcdsaWithSha512)))
309 return ParseEcdsa(DigestAlgorithm::Sha512, params); 582 return ParseEcdsa(DigestAlgorithm::Sha512, params);
310 583
311 // TODO(eroman): Add parsing of RSASSA-PSS 584 if (oid.Equals(der::Input(kOidRsaSsaPss)))
585 return ParseRsaPss(params);
312 586
313 if (oid.Equals(der::Input(kOidSha1WithRsaSignature))) 587 if (oid.Equals(der::Input(kOidSha1WithRsaSignature)))
314 return ParseRsaPkcs1(DigestAlgorithm::Sha1, params); 588 return ParseRsaPkcs1(DigestAlgorithm::Sha1, params);
315 589
316 return nullptr; // Unsupported OID. 590 return nullptr; // Unsupported OID.
317 } 591 }
318 592
319 scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateRsaPkcs1( 593 scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateRsaPkcs1(
320 DigestAlgorithm digest) { 594 DigestAlgorithm digest) {
321 return make_scoped_ptr( 595 return make_scoped_ptr(
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 } 646 }
373 647
374 SignatureAlgorithm::SignatureAlgorithm( 648 SignatureAlgorithm::SignatureAlgorithm(
375 SignatureAlgorithmId algorithm, 649 SignatureAlgorithmId algorithm,
376 DigestAlgorithm digest, 650 DigestAlgorithm digest,
377 scoped_ptr<SignatureAlgorithmParameters> params) 651 scoped_ptr<SignatureAlgorithmParameters> params)
378 : algorithm_(algorithm), digest_(digest), params_(params.Pass()) { 652 : algorithm_(algorithm), digest_(digest), params_(params.Pass()) {
379 } 653 }
380 654
381 } // namespace net 655 } // namespace net
OLDNEW
« no previous file with comments | « no previous file | net/cert/internal/signature_algorithm_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698