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

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: de-virtualize Equals() Created 5 years, 5 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
« no previous file with comments | « net/cert/internal/signature_algorithm.h ('k') | net/cert/internal/signature_algorithm_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..0ef171d72bb3d08f7a739185b9663afa17add123
--- /dev/null
+++ b/net/cert/internal/signature_algorithm.cc
@@ -0,0 +1,364 @@
+// 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 "net/der/input.h"
+#include "net/der/parser.h"
+
+namespace net {
+
+namespace {
+
+// From RFC 5912:
+//
+// sha1WithRSAEncryption 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 5912:
+//
+// pkcs-1 OBJECT IDENTIFIER ::=
+// { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+
+// From RFC 5912:
+//
+// 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 5912:
+//
+// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+//
+// In dotted notation: 1.2.840.113549.1.1.11
+const uint8_t kOidSha384WithRsaEncryption[] =
+ {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c};
+
+// From RFC 5912:
+//
+// 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 5912:
+//
+// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) ansi-X9-62(10045)
+// signatures(4) 1 }
+//
+// In dotted notation: 1.2.840.10045.4.1
+const uint8_t kOidEcdsaWithSha1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01};
+
+// From RFC 5912:
+//
+// 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 5912:
+//
+// 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 5912:
+//
+// 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};
+
+// 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. This is by definition,
+ // as the input to this function is expected to be a single
+ // AlgorithmIdentifier.
+ 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).
+ //
+ // Note that nothing is allowed after the single optional "parameters" TLV.
+ // This is because RFC 5912's notation for AlgorithmIdentifier doesn't
+ // explicitly list an extension point after "parameters".
+ *parameters = der::Input();
+ if (algorithm_identifier_parser.HasMore() &&
+ !algorithm_identifier_parser.ReadRawTLV(parameters)) {
+ return false;
+ }
+ return !algorithm_identifier_parser.HasMore();
+}
+
+// Returns true if |input| is empty.
+WARN_UNUSED_RESULT bool IsEmpty(const der::Input& input) {
+ return input.Length() == 0;
+}
+
+// Returns true if the entirety of the input is a NULL value.
+WARN_UNUSED_RESULT bool IsNull(const der::Input& input) {
+ 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 (!IsEmpty(null_value))
+ return false;
+
+ // By definition of this function, the entire input must be a NULL.
+ return !parser.HasMore();
+}
+
+// Parses an RSA PKCS#1 v1.5 signature algorithm given the DER-encoded
+// "parameters" from the parsed AlgorithmIdentifier, and the hash algorithm
+// that was implied by the AlgorithmIdentifier's OID.
+//
+// Returns a nullptr on failure.
+//
+// RFC 5912 requires that the parameters for RSA PKCS#1 v1.5 algorithms be NULL
+// ("PARAMS TYPE NULL ARE required"):
+//
+// sa-rsaWithSHA1 SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER sha1WithRSAEncryption
+// PARAMS TYPE NULL ARE required
+// HASHES { mda-sha1 }
+// PUBLIC-KEYS { pk-rsa }
+// SMIME-CAPS {IDENTIFIED BY sha1WithRSAEncryption }
+// }
+//
+// sa-sha256WithRSAEncryption SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER sha256WithRSAEncryption
+// PARAMS TYPE NULL ARE required
+// HASHES { mda-sha256 }
+// PUBLIC-KEYS { pk-rsa }
+// SMIME-CAPS { IDENTIFIED BY sha256WithRSAEncryption }
+// }
+//
+// sa-sha384WithRSAEncryption SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER sha384WithRSAEncryption
+// PARAMS TYPE NULL ARE required
+// HASHES { mda-sha384 }
+// PUBLIC-KEYS { pk-rsa }
+// SMIME-CAPS { IDENTIFIED BY sha384WithRSAEncryption }
+// }
+//
+// sa-sha512WithRSAEncryption SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER sha512WithRSAEncryption
+// PARAMS TYPE NULL ARE required
+// HASHES { mda-sha512 }
+// PUBLIC-KEYS { pk-rsa }
+// SMIME-CAPS { IDENTIFIED BY sha512WithRSAEncryption }
+// }
+scoped_ptr<SignatureAlgorithm> ParseRsaPkcs1(DigestAlgorithm digest,
+ const der::Input& params) {
+ if (!IsNull(params))
+ return nullptr;
+
+ return SignatureAlgorithm::CreateRsaPkcs1(digest);
+}
+
+// Parses an ECDSA signature algorithm given the DER-encoded "parameters" from
+// the parsed AlgorithmIdentifier, and the hash algorithm that was implied by
+// the AlgorithmIdentifier's OID.
+//
+// On failure returns a nullptr.
+//
+// RFC 5912 requires that the parameters for ECDSA algorithms be absent
+// ("PARAMS TYPE NULL ARE absent"):
+//
+// sa-ecdsaWithSHA1 SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER ecdsa-with-SHA1
+// VALUE ECDSA-Sig-Value
+// PARAMS TYPE NULL ARE absent
+// HASHES { mda-sha1 }
+// PUBLIC-KEYS { pk-ec }
+// SMIME-CAPS {IDENTIFIED BY ecdsa-with-SHA1 }
+// }
+//
+// sa-ecdsaWithSHA256 SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER ecdsa-with-SHA256
+// VALUE ECDSA-Sig-Value
+// PARAMS TYPE NULL ARE absent
+// HASHES { mda-sha256 }
+// PUBLIC-KEYS { pk-ec }
+// SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA256 }
+// }
+//
+// sa-ecdsaWithSHA384 SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER ecdsa-with-SHA384
+// VALUE ECDSA-Sig-Value
+// PARAMS TYPE NULL ARE absent
+// HASHES { mda-sha384 }
+// PUBLIC-KEYS { pk-ec }
+// SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA384 }
+// }
+//
+// sa-ecdsaWithSHA512 SIGNATURE-ALGORITHM ::= {
+// IDENTIFIER ecdsa-with-SHA512
+// VALUE ECDSA-Sig-Value
+// PARAMS TYPE NULL ARE absent
+// HASHES { mda-sha512 }
+// PUBLIC-KEYS { pk-ec }
+// SMIME-CAPS { IDENTIFIED BY ecdsa-with-SHA512 }
+// }
+scoped_ptr<SignatureAlgorithm> ParseEcdsa(DigestAlgorithm digest,
+ const der::Input& params) {
+ if (!IsEmpty(params))
+ return nullptr;
+
+ return SignatureAlgorithm::CreateEcdsa(digest);
+}
+
+} // namespace
+
+RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash,
+ uint32_t salt_length)
+ : mgf1_hash_(mgf1_hash), salt_length_(salt_length) {
+}
+
+bool RsaPssParameters::Equals(const RsaPssParameters* other) const {
+ return mgf1_hash_ == other->mgf1_hash_ && salt_length_ == other->salt_length_;
+}
+
+SignatureAlgorithm::~SignatureAlgorithm() {
+}
+
+scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateFromDer(
+ const der::Input& algorithm_identifier) {
+ der::Input oid;
+ der::Input params;
+ if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, &params))
+ return nullptr;
+
+ // 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);
+
+ if (oid.Equals(der::Input(kOidSha256WithRsaEncryption)))
+ return ParseRsaPkcs1(DigestAlgorithm::Sha256, params);
+
+ if (oid.Equals(der::Input(kOidSha384WithRsaEncryption)))
+ return ParseRsaPkcs1(DigestAlgorithm::Sha384, params);
+
+ if (oid.Equals(der::Input(kOidSha512WithRsaEncryption)))
+ return ParseRsaPkcs1(DigestAlgorithm::Sha512, params);
+
+ if (oid.Equals(der::Input(kOidEcdsaWithSha1)))
+ return ParseEcdsa(DigestAlgorithm::Sha1, params);
+
+ if (oid.Equals(der::Input(kOidEcdsaWithSha256)))
+ return ParseEcdsa(DigestAlgorithm::Sha256, params);
+
+ if (oid.Equals(der::Input(kOidEcdsaWithSha384)))
+ return ParseEcdsa(DigestAlgorithm::Sha384, params);
+
+ if (oid.Equals(der::Input(kOidEcdsaWithSha512)))
+ return ParseEcdsa(DigestAlgorithm::Sha512, params);
+
+ // TODO(eroman): Add parsing of RSASSA-PSS
+
+ return nullptr; // Unsupported OID.
+}
+
+scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateRsaPkcs1(
+ DigestAlgorithm digest) {
+ return make_scoped_ptr(
+ new SignatureAlgorithm(SignatureAlgorithmId::RsaPkcs1, digest, nullptr));
+}
+
+scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateEcdsa(
+ DigestAlgorithm digest) {
+ return make_scoped_ptr(
+ new SignatureAlgorithm(SignatureAlgorithmId::Ecdsa, digest, nullptr));
+}
+
+scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateRsaPss(
+ DigestAlgorithm digest,
+ DigestAlgorithm mgf1_hash,
+ uint32_t salt_length) {
+ return make_scoped_ptr(new SignatureAlgorithm(
+ SignatureAlgorithmId::RsaPss, digest,
+ make_scoped_ptr(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;
+
+ // Check that the parameters are equal.
+ switch (algorithm_) {
+ case SignatureAlgorithmId::RsaPss: {
+ const RsaPssParameters* params1 = ParamsForRsaPss();
+ const RsaPssParameters* params2 = other.ParamsForRsaPss();
+ if (!params1 || !params2 || !params1->Equals(params2))
+ return false;
+ break;
+ }
+
+ // There shouldn't be any parameters.
+ case SignatureAlgorithmId::RsaPkcs1:
+ case SignatureAlgorithmId::Ecdsa:
+ if (params_ || other.params_)
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+const RsaPssParameters* SignatureAlgorithm::ParamsForRsaPss() const {
+ if (algorithm_ == SignatureAlgorithmId::RsaPss)
+ return static_cast<RsaPssParameters*>(params_.get());
+ return nullptr;
+}
+
+SignatureAlgorithm::SignatureAlgorithm(
+ SignatureAlgorithmId algorithm,
+ DigestAlgorithm digest,
+ scoped_ptr<SignatureAlgorithmParameters> params)
+ : algorithm_(algorithm), digest_(digest), params_(params.Pass()) {
+}
+
+} // namespace net
« no previous file with comments | « net/cert/internal/signature_algorithm.h ('k') | net/cert/internal/signature_algorithm_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698