| 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, ¶ms))
|
| + 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
|
|
|