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

Unified Diff: net/cert/internal/signature_algorithm.cc

Issue 1218753002: Add DER parsing of AlgorithmId for signatures. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 5 years, 6 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 side-by-side diff with in-line comments
Download patch
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, &params))
+ 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

Powered by Google App Engine
This is Rietveld 408576698