Chromium Code Reviews| Index: net/cert/internal/signature_algorithm.cc |
| diff --git a/net/cert/internal/signature_algorithm.cc b/net/cert/internal/signature_algorithm.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..99c5f3f98b681e6e5c9642e217814074ab7701e4 |
| --- /dev/null |
| +++ b/net/cert/internal/signature_algorithm.cc |
| @@ -0,0 +1,219 @@ |
| +// 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 <stdint.h> |
| + |
| +#include "net/der/input.h" |
| +#include "net/der/parser.h" |
| + |
| +namespace net { |
| + |
| +namespace { |
| + |
| +// From RFC 3279 section 2.2.1: |
| +// sha-1WithRSAEncryption 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}; |
| + |
| +// From RFC 4055 section 6: |
| +// pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) |
| +// us(840) rsadsi(113549) pkcs(1) 1 } |
| + |
| +// From RFC 4055 section 5: |
| +// 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 4055 section 5: |
| +// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } |
| +// In dotted notation: 1.2.840.113549.1.1.12 |
| +const uint8_t kOidSha384WithRsaEncryption[] = |
| + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c}; |
| + |
| +// From RFC 4055 section 5: |
| +// 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 3279 section 2.2.3: |
| +// ansi-X9-62 OBJECT IDENTIFIER ::= { |
| +// iso(1) member-body(2) us(840) 10045 } |
| +// |
| +// id-ecSigType OBJECT IDENTIFIER ::= { |
| +// ansi-X9-62 signatures(4) } |
| +// |
| +// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { |
| +// id-ecSigType 1 } |
| +// In dotted notation: 1.2.840.10045.4.1 |
| +const uint8_t kOidEcdsaWithSha1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01}; |
| + |
| +// From RFC 5758 section 3.2: |
| +// 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 5758 section 3.2: |
| +// 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 5758 section 3.2: |
| +// 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}; |
| + |
| +// Assigns |out| with the values |algorithm| and |digest|. The passed in |
| +// |algorithm_identifier_parser| is expected to be positioned after the |
| +// algorithm OID. The parameters field will be consumed, and it must be either |
| +// NULL or missing. |
| +// |
| +// Returns true on success. |
| +WARN_UNUSED_RESULT bool AssignFromDerEmptyParams( |
|
Ryan Sleevi
2015/06/29 14:45:24
end of line, not beginning.
eroman
2015/06/29 15:19:00
OK, I changed the other instance, but had to leave
Ryan Sleevi
2015/06/29 16:06:57
Yeah, this is part of why Peter and several others
|
| + SignatureAlgorithmId algorithm, |
| + DigestAlgorithmId digest, |
| + der::Parser* algorithm_identifier_parser, |
| + SignatureAlgorithm* out) { |
| + // The specifications for RSA PKCS #1 v1.5 and ECDSA signature algorithm are |
| + // inconsistent on whether the parameters field must be NULL, omitted, or can |
| + // be either. |
| + // |
| + // This implementation is more permissive, and will accept both NULL and |
| + // omitted parameters. |
| + // |
| + // For reference... |
| + // |
| + // RFC 5758 section-3.2: |
| + // When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or |
| + // ecdsa-with-SHA512 algorithm identifier appears in the algorithm field |
| + // as an AlgorithmIdentifier, the encoding MUST omit the parameters |
| + // field. That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one |
| + // component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with- |
| + // SHA384, or ecdsa-with-SHA512. |
| + // |
| + // RFC 3279 section 2.2.1 (in reference to sha-1WithRSAEncryption): |
| + // When any of these three OIDs appears within the ASN.1 type |
| + // AlgorithmIdentifier, the parameters component of that type SHALL be |
| + // the ASN.1 type NULL. |
| + // |
| + // RFC 3279 section 2.2.3: |
| + // When the ecdsa-with-SHA1 algorithm identifier appears as the |
| + // algorithm field in an AlgorithmIdentifier, the encoding MUST omit the |
| + // parameters field. That is, the AlgorithmIdentifier SHALL be a |
| + // SEQUENCE of one component: the OBJECT IDENTIFIER ecdsa-with-SHA1. |
| + // |
| + // RFC 4055 section 5 (in reference to sha256WithRSAEncryption et al): |
| + // When any of these four object identifiers appears within an |
| + // AlgorithmIdentifier, the parameters MUST be NULL. Implementations |
| + // MUST accept the parameters being absent as well as present. |
| + |
| + if (algorithm_identifier_parser->HasMore()) { |
| + der::Input null_value; |
| + if (!algorithm_identifier_parser->ReadTag(der::kNull, &null_value)) |
| + return false; |
| + |
| + if (null_value.Length() != 0) |
| + return false; // Not a NULL value |
| + |
| + // After consuming the NULL params there shouldn't be anything left. |
| + if (algorithm_identifier_parser->HasMore()) |
| + return false; |
| + } |
| + |
| + out->algorithm = algorithm; |
| + out->digest = digest; |
| + |
| + return true; |
| +} |
| + |
| +} // namespace |
| + |
| +bool SignatureAlgorithm::AssignFromDer(const der::Input& in) { |
| + // RFC 5280 section 4.1.1.2 defines signatureAlgorithm as: |
| + // |
| + // AlgorithmIdentifier ::= SEQUENCE { |
| + // algorithm OBJECT IDENTIFIER, |
| + // parameters ANY DEFINED BY algorithm OPTIONAL } |
| + |
| + der::Parser parser(in); |
| + |
| + der::Parser algorithm_identifier_parser; |
| + if (!parser.ReadSequence(&algorithm_identifier_parser)) |
| + return false; |
| + |
| + der::Input oid; |
| + if (!algorithm_identifier_parser.ReadTag(der::kOid, &oid)) |
| + return false; |
| + |
| + // TODO(eroman): Each OID is tested for equality in order, which is not |
| + // particularly efficient. |
| + |
| + if (oid.Equals(kOidSha1WithRsaEncryption)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::RsaPkcs1_5, |
| + DigestAlgorithmId::Sha1, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + if (oid.Equals(kOidSha256WithRsaEncryption)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::RsaPkcs1_5, |
| + DigestAlgorithmId::Sha256, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + if (oid.Equals(kOidSha384WithRsaEncryption)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::RsaPkcs1_5, |
| + DigestAlgorithmId::Sha384, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + if (oid.Equals(kOidSha512WithRsaEncryption)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::RsaPkcs1_5, |
| + DigestAlgorithmId::Sha512, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + if (oid.Equals(kOidEcdsaWithSha1)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::Ecdsa, |
| + DigestAlgorithmId::Sha1, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + if (oid.Equals(kOidEcdsaWithSha256)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::Ecdsa, |
| + DigestAlgorithmId::Sha256, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + if (oid.Equals(kOidEcdsaWithSha384)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::Ecdsa, |
| + DigestAlgorithmId::Sha384, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + if (oid.Equals(kOidEcdsaWithSha512)) { |
| + return AssignFromDerEmptyParams(SignatureAlgorithmId::Ecdsa, |
| + DigestAlgorithmId::Sha512, |
| + &algorithm_identifier_parser, this); |
| + } |
| + |
| + return false; // Unsupported OID. |
| +} |
| + |
| +bool SignatureAlgorithm::Equals(const SignatureAlgorithm& other) const { |
| + return algorithm == other.algorithm && digest == other.digest; |
| +} |
| + |
| +} // namespace net |