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..4ea2e390d598efd3cceceb18291901fc0b2ed181 |
--- /dev/null |
+++ b/net/cert/internal/signature_algorithm.cc |
@@ -0,0 +1,337 @@ |
+// 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}; |
+ |
+// From RFC 4055 section 3.1: |
+// 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}; |
+ |
+// 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. |
+ 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). |
+ *parameters = der::Input(); |
+ if (algorithm_identifier_parser.HasMore() && |
+ !algorithm_identifier_parser.ReadRawTLV(parameters)) { |
+ return false; |
+ } |
+ return !algorithm_identifier_parser.HasMore(); |
Ryan Sleevi
2015/07/07 13:55:15
It's perfectly fine for an algorithm to have addit
eroman
2015/07/08 01:09:34
For anyone following, this is the same conversatio
Ryan Sleevi
2015/07/08 11:44:01
The result being that as a result if we adopt the
eroman
2015/07/14 20:31:38
I have added comments to each place in the code th
|
+} |
+ |
+// Returns true if the entirety of the input is a NULL value, or is empty. |
+WARN_UNUSED_RESULT bool IsNullOrEmpty(const der::Input& input) { |
+ if (input.Length() == 0) |
+ return true; |
+ |
+ 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 (null_value.Length() != 0) |
+ return false; |
+ |
+ return !parser.HasMore(); |
+} |
+ |
+// Parses parameters for RSA PKCS#1 v1.5 from |parameters_parser| (ensure there |
+// are none), and assigns the resulting algorithm identifier to |*out|. |
+// |
+// Returns true on success. |
+// |
+// Note that the parameter parsing used is more permissive than the specs with |
+// regards to sha-1WithRSAEncryption - it accepts both NULL and empty |
+// parameters. |
+// |
+// Relevant specs: |
+// |
+// 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. |
+// |
+// 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. |
+WARN_UNUSED_RESULT bool ParseRsaPkcs1(DigestAlgorithm digest, |
+ const der::Input& params, |
+ SignatureAlgorithm* out) { |
+ if (!IsNullOrEmpty(params)) |
+ return false; |
+ |
+ out->AssignRsaPkcs1(digest); |
+ return true; |
+} |
+ |
+// Parses parameters for ECDSA from |parameters_parser| (ensure there |
+// are none), and assigns the resulting algorithm identifier to |*out|. |
+// |
+// Returns true on success. |
+// |
+// Note that the parameter parsing used is more permissive than the specs with |
+// regards - it additionally accepts NULL parameters. |
Ryan Sleevi
2015/07/07 13:55:15
Why?
eroman
2015/07/08 01:09:34
Isn't this a moot point based on your earlier comm
Ryan Sleevi
2015/07/08 11:44:01
So if we're adopting the 5912 rules (as discussed
eroman
2015/07/14 20:31:38
I have re-written most of the RFC references in te
|
+// |
+// Relevant specs: |
+// |
+// 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.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. |
+WARN_UNUSED_RESULT bool ParseEcdsa(DigestAlgorithm digest, |
+ const der::Input& params, |
+ SignatureAlgorithm* out) { |
+ if (!IsNullOrEmpty(params)) |
+ return false; |
+ |
+ out->AssignEcdsa(digest); |
+ return true; |
+} |
+ |
+// From RFC 4055: |
+// RSASSA-PSS-params ::= SEQUENCE { |
+// hashAlgorithm [0] HashAlgorithm DEFAULT |
+// sha1Identifier, |
+// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT |
+// mgf1SHA1Identifier, |
+// saltLength [2] INTEGER DEFAULT 20, |
+// trailerField [3] INTEGER DEFAULT 1 } |
+// |
+// HashAlgorithm ::= AlgorithmIdentifier |
+// |
+// MaskGenAlgorithm ::= AlgorithmIdentifier |
+WARN_UNUSED_RESULT bool ParseRsaPss(const der::Input& params, |
+ SignatureAlgorithm* out) { |
+ // TODO(eroman): Implement. |
+ return false; |
+} |
+ |
+} // namespace |
+ |
+RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash, |
+ uint32_t salt_length) |
+ : mgf1_hash_(mgf1_hash), salt_length_(salt_length) { |
+} |
+ |
+bool RsaPssParameters::Equals(const SignatureAlgorithmParameters* other) const { |
+ const RsaPssParameters* params = static_cast<const RsaPssParameters*>(other); |
+ return mgf1_hash_ == params->mgf1_hash_ && |
+ salt_length_ == params->salt_length_; |
+} |
+ |
+SignatureAlgorithm::SignatureAlgorithm() { |
+ AssignInvalid(); |
+} |
+ |
+SignatureAlgorithm::~SignatureAlgorithm() { |
+} |
+ |
+bool SignatureAlgorithm::IsValid() const { |
+ return params_; |
+} |
+ |
+SignatureAlgorithmId SignatureAlgorithm::algorithm() const { |
+ DCHECK(IsValid()); |
+ return algorithm_; |
+} |
+ |
+DigestAlgorithm SignatureAlgorithm::digest() const { |
+ DCHECK(IsValid()); |
+ return digest_; |
+} |
+ |
+bool SignatureAlgorithm::ParseDer(const der::Input& algorithm_identifier) { |
+ AssignInvalid(); |
+ |
+ der::Input oid; |
+ der::Input params; |
+ if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, ¶ms)) |
+ return false; |
+ |
+ // 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, this); |
+ |
+ if (oid.Equals(der::Input(kOidSha256WithRsaEncryption))) |
+ return ParseRsaPkcs1(DigestAlgorithm::Sha256, params, this); |
+ |
+ if (oid.Equals(der::Input(kOidSha384WithRsaEncryption))) |
+ return ParseRsaPkcs1(DigestAlgorithm::Sha384, params, this); |
+ |
+ if (oid.Equals(der::Input(kOidSha512WithRsaEncryption))) |
+ return ParseRsaPkcs1(DigestAlgorithm::Sha512, params, this); |
+ |
+ if (oid.Equals(der::Input(kOidEcdsaWithSha1))) |
+ return ParseEcdsa(DigestAlgorithm::Sha1, params, this); |
+ |
+ if (oid.Equals(der::Input(kOidEcdsaWithSha256))) |
+ return ParseEcdsa(DigestAlgorithm::Sha256, params, this); |
+ |
+ if (oid.Equals(der::Input(kOidEcdsaWithSha384))) |
+ return ParseEcdsa(DigestAlgorithm::Sha384, params, this); |
+ |
+ if (oid.Equals(der::Input(kOidEcdsaWithSha512))) |
+ return ParseEcdsa(DigestAlgorithm::Sha512, params, this); |
+ |
+ if (oid.Equals(der::Input(kOidRsaSsaPss))) |
+ return ParseRsaPss(params, this); |
+ |
+ return false; // Unsupported OID. |
+} |
+ |
+void SignatureAlgorithm::AssignRsaPkcs1(DigestAlgorithm digest) { |
+ algorithm_ = SignatureAlgorithmId::RsaPkcs1; |
+ digest_ = digest; |
+ params_.reset(); |
+} |
+ |
+void SignatureAlgorithm::AssignEcdsa(DigestAlgorithm digest) { |
+ algorithm_ = SignatureAlgorithmId::Ecdsa; |
+ digest_ = digest; |
+ params_.reset(); |
+} |
+ |
+void SignatureAlgorithm::AssignRsaPss(DigestAlgorithm digest, |
+ DigestAlgorithm mgf1_hash, |
+ uint32_t salt_length) { |
+ algorithm_ = SignatureAlgorithmId::RsaPss; |
+ digest_ = digest; |
+ params_.reset(new RsaPssParameters(mgf1_hash, salt_length)); |
+} |
+ |
+bool SignatureAlgorithm::Equals(const SignatureAlgorithm& other) const { |
+ if (algorithm_ != other.algorithm_) |
+ return false; |
+ |
+ if (digest_ != other.digest_) |
+ return false; |
+ |
+ if (!params_ != !other.params_) |
+ return false; |
+ |
+ if (params_ && !params_->Equals(other.params_.get())) |
+ return false; |
+ |
+ return true; |
+} |
+ |
+const RsaPssParameters* SignatureAlgorithm::ParamsForRsaPss() const { |
+ if (algorithm_ == SignatureAlgorithmId::RsaPss) |
+ return static_cast<RsaPssParameters*>(params_.get()); |
+ return nullptr; |
+} |
+ |
+void SignatureAlgorithm::AssignInvalid() { |
+ algorithm_ = static_cast<SignatureAlgorithmId>(-1); |
+ digest_ = static_cast<DigestAlgorithm>(-1); |
+ params_.reset(); |
+} |
+ |
+} // namespace net |