Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include "base/numerics/safe_math.h" | |
| 9 #include "net/der/input.h" | 10 #include "net/der/input.h" |
| 11 #include "net/der/parse_values.h" | |
| 10 #include "net/der/parser.h" | 12 #include "net/der/parser.h" |
| 11 | 13 |
| 12 namespace net { | 14 namespace net { |
| 13 | 15 |
| 14 namespace { | 16 namespace { |
| 15 | 17 |
| 16 // From RFC 3279 section 2.2.1: | 18 // From RFC 3279 section 2.2.1: |
| 17 // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { | 19 // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { |
| 18 // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) | 20 // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) |
| 19 // pkcs-1(1) 5 } | 21 // pkcs-1(1) 5 } |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 75 // In dotted notation: 1.2.840.10045.4.3.4 | 77 // In dotted notation: 1.2.840.10045.4.3.4 |
| 76 const uint8_t kOidEcdsaWithSha512[] = | 78 const uint8_t kOidEcdsaWithSha512[] = |
| 77 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04}; | 79 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04}; |
| 78 | 80 |
| 79 // From RFC 4055 section 3.1: | 81 // From RFC 4055 section 3.1: |
| 80 // id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 } | 82 // id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 } |
| 81 // In dotted notation: 1.2.840.113549.1.1.10 | 83 // In dotted notation: 1.2.840.113549.1.1.10 |
| 82 const uint8_t kOidRsaSsaPss[] = | 84 const uint8_t kOidRsaSsaPss[] = |
| 83 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a}; | 85 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a}; |
| 84 | 86 |
| 87 // From RFC 4055: | |
| 88 // id-sha1 OBJECT IDENTIFIER ::= { iso(1) | |
| 89 // identified-organization(3) oiw(14) | |
| 90 // secsig(3) algorithms(2) 26 } | |
| 91 // In dotted notation: 1.3.14.3.2.26 | |
| 92 const uint8_t kOidSha1[] = {0x2B, 0x0E, 0x03, 0x02, 0x1A}; | |
| 93 | |
| 94 // From RFC 4055: | |
| 95 // id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) | |
| 96 // country(16) us(840) organization(1) gov(101) | |
| 97 // csor(3) nistalgorithm(4) hashalgs(2) 1 } | |
| 98 // In dotted notation: 2.16.840.1.101.3.4.2.1 | |
| 99 const uint8_t kOidSha256[] = | |
| 100 {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}; | |
| 101 | |
| 102 // From RFC 4055: | |
| 103 // id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) | |
| 104 // country(16) us(840) organization(1) gov(101) | |
| 105 // csor(3) nistalgorithm(4) hashalgs(2) 2 } | |
| 106 // In dotted notation: 2.16.840.1.101.3.4.2.2 | |
| 107 const uint8_t kOidSha384[] = | |
| 108 {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}; | |
| 109 | |
| 110 // From RFC 4055: | |
| 111 // id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) | |
| 112 // country(16) us(840) organization(1) gov(101) | |
| 113 // csor(3) nistalgorithm(4) hashalgs(2) 3 } | |
| 114 // In dotted notation: 2.16.840.1.101.3.4.2.3 | |
| 115 const uint8_t kOidSha512[] = | |
| 116 {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}; | |
| 117 | |
| 118 // From RFC 4055: | |
| 119 // id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 } | |
| 120 // In dotted notation: 1.2.840.113549.1.1.8 | |
| 121 const uint8_t kOidMgf1[] = | |
| 122 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08}; | |
| 123 | |
| 85 // RFC 5280 section 4.1.1.2 defines signatureAlgorithm as: | 124 // RFC 5280 section 4.1.1.2 defines signatureAlgorithm as: |
| 86 // | 125 // |
| 87 // AlgorithmIdentifier ::= SEQUENCE { | 126 // AlgorithmIdentifier ::= SEQUENCE { |
| 88 // algorithm OBJECT IDENTIFIER, | 127 // algorithm OBJECT IDENTIFIER, |
| 89 // parameters ANY DEFINED BY algorithm OPTIONAL } | 128 // parameters ANY DEFINED BY algorithm OPTIONAL } |
| 90 WARN_UNUSED_RESULT bool ParseAlgorithmIdentifier(const der::Input& input, | 129 WARN_UNUSED_RESULT bool ParseAlgorithmIdentifier(const der::Input& input, |
| 91 der::Input* algorithm, | 130 der::Input* algorithm, |
| 92 der::Input* parameters) { | 131 der::Input* parameters) { |
| 93 der::Parser parser(input); | 132 der::Parser parser(input); |
| 94 | 133 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 186 WARN_UNUSED_RESULT bool ParseEcdsa(DigestAlgorithm digest, | 225 WARN_UNUSED_RESULT bool ParseEcdsa(DigestAlgorithm digest, |
| 187 const der::Input& params, | 226 const der::Input& params, |
| 188 SignatureAlgorithm* out) { | 227 SignatureAlgorithm* out) { |
| 189 if (!IsNullOrEmpty(params)) | 228 if (!IsNullOrEmpty(params)) |
| 190 return false; | 229 return false; |
| 191 | 230 |
| 192 out->AssignEcdsa(digest); | 231 out->AssignEcdsa(digest); |
| 193 return true; | 232 return true; |
| 194 } | 233 } |
| 195 | 234 |
| 235 // Parses an AlgorithmIdentifier representing an RFC 4055 "HashAlgorithm". | |
| 236 // Examples of HashAlgorithms are: | |
| 237 // | |
| 238 // sha1Identifier AlgorithmIdentifier ::= { id-sha1, NULL } | |
| 239 // sha224Identifier AlgorithmIdentifier ::= { id-sha224, NULL } | |
| 240 // sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL } | |
| 241 // sha384Identifier AlgorithmIdentifier ::= { id-sha384, NULL } | |
| 242 // sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL } | |
| 243 // | |
| 244 // Note that the parameters needn't be NULL as in the examples above. RFC 4055 | |
| 245 // says that: | |
| 246 // | |
| 247 // All implementations MUST accept both NULL and absent parameters as | |
| 248 // legal and equivalent encodings. | |
| 249 WARN_UNUSED_RESULT bool ParseHashAlgorithm(const der::Input input, | |
| 250 DigestAlgorithm* out) { | |
| 251 der::Input oid; | |
| 252 der::Input params; | |
| 253 if (!ParseAlgorithmIdentifier(input, &oid, ¶ms)) | |
| 254 return false; | |
| 255 | |
| 256 DigestAlgorithm hash; | |
| 257 | |
| 258 if (oid.Equals(der::Input(kOidSha1))) { | |
| 259 hash = DigestAlgorithm::Sha1; | |
| 260 } else if (oid.Equals(der::Input(kOidSha256))) { | |
| 261 hash = DigestAlgorithm::Sha256; | |
| 262 } else if (oid.Equals(der::Input(kOidSha384))) { | |
| 263 hash = DigestAlgorithm::Sha384; | |
| 264 } else if (oid.Equals(der::Input(kOidSha512))) { | |
| 265 hash = DigestAlgorithm::Sha512; | |
| 266 } else { | |
| 267 // Unsupported digest algorithm. | |
| 268 return false; | |
| 269 } | |
| 270 | |
| 271 if (!IsNullOrEmpty(params)) | |
| 272 return false; | |
| 273 | |
| 274 *out = hash; | |
| 275 return true; | |
| 276 } | |
| 277 | |
| 278 // Parses a MaskGenAlgorithm as defined by RFC 4055. It is expected that the | |
|
Ryan Sleevi
2015/07/06 15:03:18
Worth mentioning (somewhere) that MaskGenAlgorithm
eroman
2015/07/07 01:24:22
Done.
| |
| 279 // mask gen is for MGF1, as this is the only function allowed for in RFC 4055. | |
|
Ryan Sleevi
2015/07/06 15:03:17
Comment wise, this reads weird. RFC 4055 totally a
eroman
2015/07/07 01:24:22
How about this:
// Parses a MaskGenAlgorithm as d
| |
| 280 // | |
| 281 // RFC 4055 section 2.2: | |
| 282 // | |
| 283 // One mask generation function is used with the RSASSA-PSS signature | |
| 284 // algorithm and the RSAES-OAEP key transport algorithm: MGF1 [P1v2.1]. | |
| 285 // No other mask generation functions are supported by this | |
| 286 // specification. | |
| 287 // | |
| 288 // MGF1 is identified by the following object identifier: | |
| 289 // | |
| 290 // id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 } | |
| 291 // | |
| 292 // The parameters field associated with id-mgf1 MUST have a | |
| 293 // hashAlgorithm value which identifies the hash function being used | |
| 294 // with MGF1. This value MUST be sha1Identifier, sha224Identifier, | |
| 295 // sha256Identifier, sha384Identifier, or sha512Identifier, as specified | |
| 296 // in Section 2.1. Implementations MUST support the default value, | |
| 297 // sha1Identifier, and MAY support the other four values. | |
| 298 WARN_UNUSED_RESULT bool ParseMaskGenAlgorithm(const der::Input input, | |
| 299 DigestAlgorithm* mgf1_hash) { | |
| 300 der::Input oid; | |
| 301 der::Input params; | |
| 302 if (!ParseAlgorithmIdentifier(input, &oid, ¶ms)) | |
| 303 return false; | |
| 304 | |
| 305 // MGF1 is the only supported mask generation algorithm. | |
| 306 if (!oid.Equals(der::Input(kOidMgf1))) | |
| 307 return false; | |
| 308 | |
| 309 return ParseHashAlgorithm(params, mgf1_hash); | |
| 310 } | |
| 311 | |
| 312 // Consumes an optional integer from |parser| using the indicated | |
| 313 // (context-specific) tag number. | |
|
Ryan Sleevi
2015/07/06 15:03:18
// Consumes an optional, explicitly-tagged INTEGER
eroman
2015/07/07 01:24:23
Done.
| |
| 314 // | |
| 315 // Returns true on success and sets |*present| to true if the field was present. | |
| 316 WARN_UNUSED_RESULT bool ReadOptionalContextSpecificUint32(der::Parser* parser, | |
| 317 uint8_t tag_base, | |
|
Ryan Sleevi
2015/07/06 15:03:17
naming nit: tag_base originally suggested to me so
eroman
2015/07/07 01:24:22
Done.
| |
| 318 uint32_t* out, | |
| 319 bool* present) { | |
| 320 der::Input value; | |
| 321 bool has_value; | |
| 322 | |
| 323 // Read the context specific value. | |
| 324 if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(tag_base), | |
| 325 &value, &has_value)) { | |
| 326 return false; | |
| 327 } | |
| 328 | |
| 329 if (has_value) { | |
| 330 // Parse the integer contained in it. | |
| 331 der::Parser number_parser(value); | |
| 332 uint64_t uint64_value; | |
| 333 | |
| 334 if (!number_parser.ReadUint64(&uint64_value)) | |
| 335 return false; | |
| 336 if (number_parser.HasMore()) | |
| 337 return false; | |
| 338 | |
| 339 // Cast the number to a uint32_t | |
| 340 base::CheckedNumeric<uint32_t> casted(uint64_value); | |
| 341 if (!casted.IsValid()) | |
| 342 return false; | |
| 343 *out = casted.ValueOrDie(); | |
| 344 } | |
| 345 | |
| 346 *present = has_value; | |
| 347 return true; | |
| 348 } | |
| 349 | |
| 196 // From RFC 4055: | 350 // From RFC 4055: |
| 197 // RSASSA-PSS-params ::= SEQUENCE { | 351 // RSASSA-PSS-params ::= SEQUENCE { |
| 198 // hashAlgorithm [0] HashAlgorithm DEFAULT | 352 // hashAlgorithm [0] HashAlgorithm DEFAULT |
| 199 // sha1Identifier, | 353 // sha1Identifier, |
| 200 // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT | 354 // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT |
| 201 // mgf1SHA1Identifier, | 355 // mgf1SHA1Identifier, |
| 202 // saltLength [2] INTEGER DEFAULT 20, | 356 // saltLength [2] INTEGER DEFAULT 20, |
| 203 // trailerField [3] INTEGER DEFAULT 1 } | 357 // trailerField [3] INTEGER DEFAULT 1 } |
| 204 // | 358 // |
| 205 // HashAlgorithm ::= AlgorithmIdentifier | 359 // HashAlgorithm ::= AlgorithmIdentifier |
| 206 // | 360 // |
| 207 // MaskGenAlgorithm ::= AlgorithmIdentifier | 361 // MaskGenAlgorithm ::= AlgorithmIdentifier |
| 208 WARN_UNUSED_RESULT bool ParseRsaPss(const der::Input& params, | 362 WARN_UNUSED_RESULT bool ParseRsaPss(const der::Input& params, |
| 209 SignatureAlgorithm* out) { | 363 SignatureAlgorithm* out) { |
| 210 // TODO(eroman): Implement. | 364 // RFC 4055 says that the RSASSA-PSS-params must be present in signature |
| 211 return false; | 365 // algorithms. (However because each field is optional, the sequence could be |
| 366 // empty when using all the defaults). | |
| 367 // | |
| 368 // Section 3.1: | |
| 369 // | |
| 370 // When RSASSA-PSS is used in an AlgorithmIdentifier, the parameters | |
| 371 // MUST employ the RSASSA-PSS-params syntax. The parameters may be | |
| 372 // either absent or present when used as subject public key information. | |
| 373 // The parameters MUST be present when used in the algorithm identifier | |
| 374 // associated with a signature value. | |
| 375 der::Parser parser(params); | |
| 376 der::Parser params_parser; | |
| 377 if (!parser.ReadSequence(¶ms_parser)) | |
| 378 return false; | |
| 379 | |
| 380 // There shouldn't be anything after the sequence. | |
| 381 if (parser.HasMore()) | |
| 382 return false; | |
| 383 | |
| 384 // Initialize parameters to their default values. | |
| 385 DigestAlgorithm hash = DigestAlgorithm::Sha1; | |
| 386 DigestAlgorithm mgf1_hash = DigestAlgorithm::Sha1; | |
| 387 uint32_t salt_length = 20; | |
|
Ryan Sleevi
2015/07/06 15:03:17
pedantry: 20u
eroman
2015/07/07 01:24:23
Done.
| |
| 388 uint32_t trailer_field = 1; | |
|
Ryan Sleevi
2015/07/06 15:03:17
pedantry: 1u
eroman
2015/07/07 01:24:23
Done.
| |
| 389 | |
| 390 bool has_field; | |
| 391 der::Input field; | |
| 392 | |
| 393 // Parse hashAlgorithm [0] | |
| 394 if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &field, | |
|
Ryan Sleevi
2015/07/06 15:03:17
When Nick and I originally had discussed this, the
eroman
2015/07/07 01:24:23
My API suggestion depends on understanding a few t
| |
| 395 &has_field)) { | |
| 396 return false; | |
| 397 } | |
| 398 if (has_field) { | |
| 399 if (!ParseHashAlgorithm(field, &hash)) | |
|
Ryan Sleevi
2015/07/06 15:03:18
simplify
if (has_field && !ParseHashAlgorithm(fie
eroman
2015/07/07 01:24:22
Done.
| |
| 400 return false; | |
| 401 } | |
| 402 | |
| 403 // Parse maskGenAlgorithm [1] | |
| 404 if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(1), &field, | |
| 405 &has_field)) { | |
| 406 return false; | |
| 407 } | |
| 408 if (has_field) { | |
| 409 if (!ParseMaskGenAlgorithm(field, &mgf1_hash)) | |
| 410 return false; | |
|
Ryan Sleevi
2015/07/06 15:03:17
Simplify
if (has_field && !ParseMaskGenAlgorithm(
eroman
2015/07/07 01:24:22
Done.
| |
| 411 } | |
| 412 | |
| 413 // Parse saltLength [2] | |
| 414 if (!ReadOptionalContextSpecificUint32(¶ms_parser, 2, &salt_length, | |
| 415 &has_field)) { | |
| 416 return false; | |
| 417 } | |
| 418 | |
| 419 // Parse trailerField [3] | |
| 420 if (!ReadOptionalContextSpecificUint32(¶ms_parser, 3, &trailer_field, | |
| 421 &has_field)) { | |
| 422 return false; | |
| 423 } | |
| 424 | |
| 425 // The trailer field MUST be 1 per RFC 4055. | |
| 426 if (trailer_field != 1) | |
| 427 return false; | |
| 428 | |
| 429 // There must not be any unconsumed data left. | |
| 430 if (params_parser.HasMore()) | |
|
Ryan Sleevi
2015/07/06 15:03:17
BUG: This is unnecessarily strict, since it's tota
eroman
2015/07/07 01:24:23
Thanks.
I have some concerns with leaving unconsu
Ryan Sleevi
2015/07/07 15:27:23
This is all covered by the ASN.1 schema, which is
eroman
2015/07/08 00:22:39
Thanks for the information, I will try to absorb t
| |
| 431 return false; | |
| 432 | |
| 433 out->AssignRsaPss(hash, mgf1_hash, salt_length); | |
| 434 return true; | |
| 212 } | 435 } |
| 213 | 436 |
| 214 } // namespace | 437 } // namespace |
| 215 | 438 |
| 216 RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash, | 439 RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash, |
| 217 uint32_t salt_length) | 440 uint32_t salt_length) |
| 218 : mgf1_hash_(mgf1_hash), salt_length_(salt_length) { | 441 : mgf1_hash_(mgf1_hash), salt_length_(salt_length) { |
| 219 } | 442 } |
| 220 | 443 |
| 221 bool RsaPssParameters::Equals(const SignatureAlgorithmParameters* other) const { | 444 bool RsaPssParameters::Equals(const SignatureAlgorithmParameters* other) const { |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 328 return nullptr; | 551 return nullptr; |
| 329 } | 552 } |
| 330 | 553 |
| 331 void SignatureAlgorithm::AssignInvalid() { | 554 void SignatureAlgorithm::AssignInvalid() { |
| 332 algorithm_ = static_cast<SignatureAlgorithmId>(-1); | 555 algorithm_ = static_cast<SignatureAlgorithmId>(-1); |
| 333 digest_ = static_cast<DigestAlgorithm>(-1); | 556 digest_ = static_cast<DigestAlgorithm>(-1); |
| 334 params_.reset(); | 557 params_.reset(); |
| 335 } | 558 } |
| 336 | 559 |
| 337 } // namespace net | 560 } // namespace net |
| OLD | NEW |