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 |