Mirror of BoringSSL (grpc依赖)
https://boringssl.googlesource.com/boringssl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
421 lines
14 KiB
421 lines
14 KiB
2 years ago
|
// Copyright 2015 The Chromium Authors
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
|
#include "signature_algorithm.h"
|
||
|
|
||
|
#include "input.h"
|
||
|
#include "parse_values.h"
|
||
|
#include "parser.h"
|
||
|
#include <openssl/bytestring.h>
|
||
|
#include <openssl/digest.h>
|
||
|
|
||
|
namespace bssl {
|
||
|
|
||
|
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};
|
||
|
|
||
|
// sha1WithRSASignature is a deprecated equivalent of
|
||
|
// sha1WithRSAEncryption.
|
||
|
//
|
||
|
// It originates from the NIST Open Systems Environment (OSE)
|
||
|
// Implementor's Workshop (OIW).
|
||
|
//
|
||
|
// It is supported for compatibility with Microsoft's certificate APIs and
|
||
|
// tools, particularly makecert.exe, which default(ed/s) to this OID for SHA-1.
|
||
|
//
|
||
|
// See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1042479
|
||
|
//
|
||
|
// In dotted notation: 1.3.14.3.2.29
|
||
|
const uint8_t kOidSha1WithRsaSignature[] = {0x2b, 0x0e, 0x03, 0x02, 0x1d};
|
||
|
|
||
|
// 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};
|
||
|
|
||
|
// From RFC 5912:
|
||
|
//
|
||
|
// 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};
|
||
|
|
||
|
// From RFC 5912:
|
||
|
//
|
||
|
// id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 }
|
||
|
//
|
||
|
// In dotted notation: 1.2.840.113549.1.1.8
|
||
|
const uint8_t kOidMgf1[] = {0x2a, 0x86, 0x48, 0x86, 0xf7,
|
||
|
0x0d, 0x01, 0x01, 0x08};
|
||
|
|
||
|
// Returns true if |input| is empty.
|
||
|
[[nodiscard]] bool IsEmpty(const der::Input& input) {
|
||
|
return input.Length() == 0;
|
||
|
}
|
||
|
|
||
|
// Returns true if the entirety of the input is a NULL value.
|
||
|
[[nodiscard]] 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();
|
||
|
}
|
||
|
|
||
|
[[nodiscard]] bool IsNullOrEmpty(const der::Input& input) {
|
||
|
return IsNull(input) || IsEmpty(input);
|
||
|
}
|
||
|
|
||
|
// Parses a MaskGenAlgorithm as defined by RFC 5912:
|
||
|
//
|
||
|
// MaskGenAlgorithm ::= AlgorithmIdentifier{ALGORITHM,
|
||
|
// {PKCS1MGFAlgorithms}}
|
||
|
//
|
||
|
// mgf1SHA1 MaskGenAlgorithm ::= {
|
||
|
// algorithm id-mgf1,
|
||
|
// parameters HashAlgorithm : sha1Identifier
|
||
|
// }
|
||
|
//
|
||
|
// --
|
||
|
// -- Define the set of mask generation functions
|
||
|
// --
|
||
|
// -- If the identifier is id-mgf1, any of the listed hash
|
||
|
// -- algorithms may be used.
|
||
|
// --
|
||
|
//
|
||
|
// PKCS1MGFAlgorithms ALGORITHM ::= {
|
||
|
// { IDENTIFIER id-mgf1 PARAMS TYPE HashAlgorithm ARE required },
|
||
|
// ...
|
||
|
// }
|
||
|
//
|
||
|
// Note that the possible mask gen algorithms is extensible. However at present
|
||
|
// the only function supported is MGF1, as that is the singular mask gen
|
||
|
// function defined by RFC 4055 / RFC 5912.
|
||
|
[[nodiscard]] bool ParseMaskGenAlgorithm(const der::Input input,
|
||
|
DigestAlgorithm* mgf1_hash) {
|
||
|
der::Input oid;
|
||
|
der::Input params;
|
||
|
if (!ParseAlgorithmIdentifier(input, &oid, ¶ms))
|
||
|
return false;
|
||
|
|
||
|
// MGF1 is the only supported mask generation algorithm.
|
||
|
if (oid != der::Input(kOidMgf1))
|
||
|
return false;
|
||
|
|
||
|
return ParseHashAlgorithm(params, mgf1_hash);
|
||
|
}
|
||
|
|
||
|
// Parses the parameters for an RSASSA-PSS signature algorithm, as defined by
|
||
|
// RFC 5912:
|
||
|
//
|
||
|
// sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= {
|
||
|
// IDENTIFIER id-RSASSA-PSS
|
||
|
// PARAMS TYPE RSASSA-PSS-params ARE required
|
||
|
// HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384
|
||
|
// | mda-sha512 }
|
||
|
// PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS }
|
||
|
// SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS }
|
||
|
// }
|
||
|
//
|
||
|
// RSASSA-PSS-params ::= SEQUENCE {
|
||
|
// hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier,
|
||
|
// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
|
||
|
// saltLength [2] INTEGER DEFAULT 20,
|
||
|
// trailerField [3] INTEGER DEFAULT 1
|
||
|
// }
|
||
|
//
|
||
|
// Which is to say the parameters MUST be present, and of type
|
||
|
// RSASSA-PSS-params. Additionally, we only support the RSA-PSS parameter
|
||
|
// combinations representable by TLS 1.3 (RFC 8446).
|
||
|
//
|
||
|
// Note also that DER encoding (ITU-T X.690 section 11.5) prohibits
|
||
|
// specifying default values explicitly. The parameter should instead be
|
||
|
// omitted to indicate a default value.
|
||
|
std::optional<SignatureAlgorithm> ParseRsaPss(const der::Input& params) {
|
||
|
der::Parser parser(params);
|
||
|
der::Parser params_parser;
|
||
|
if (!parser.ReadSequence(¶ms_parser)) {
|
||
|
return std::nullopt;
|
||
|
}
|
||
|
|
||
|
// There shouldn't be anything after the sequence (by definition the
|
||
|
// parameters is a single sequence).
|
||
|
if (parser.HasMore()) {
|
||
|
return std::nullopt;
|
||
|
}
|
||
|
|
||
|
// The default values for hashAlgorithm, maskGenAlgorithm, and saltLength
|
||
|
// correspond to SHA-1, which we do not support with RSA-PSS, so treat them as
|
||
|
// required fields. Explicitly-specified defaults will be rejected later, when
|
||
|
// we limit combinations. Additionally, as the trailerField is required to be
|
||
|
// the default, we simply ignore it and reject it as any other trailing data.
|
||
|
//
|
||
|
// hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier,
|
||
|
// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
|
||
|
// saltLength [2] INTEGER DEFAULT 20,
|
||
|
// trailerField [3] INTEGER DEFAULT 1
|
||
|
der::Input field;
|
||
|
DigestAlgorithm hash, mgf1_hash;
|
||
|
der::Parser salt_length_parser;
|
||
|
uint64_t salt_length;
|
||
|
if (!params_parser.ReadTag(der::ContextSpecificConstructed(0), &field) ||
|
||
|
!ParseHashAlgorithm(field, &hash) ||
|
||
|
!params_parser.ReadTag(der::ContextSpecificConstructed(1), &field) ||
|
||
|
!ParseMaskGenAlgorithm(field, &mgf1_hash) ||
|
||
|
!params_parser.ReadConstructed(der::ContextSpecificConstructed(2),
|
||
|
&salt_length_parser) ||
|
||
|
!salt_length_parser.ReadUint64(&salt_length) ||
|
||
|
salt_length_parser.HasMore() || params_parser.HasMore()) {
|
||
|
return std::nullopt;
|
||
|
}
|
||
|
|
||
|
// Only combinations of RSASSA-PSS-params specified by TLS 1.3 (RFC 8446) are
|
||
|
// supported.
|
||
|
if (hash != mgf1_hash) {
|
||
|
return std::nullopt; // TLS 1.3 always matches MGF-1 and message hash.
|
||
|
}
|
||
|
if (hash == DigestAlgorithm::Sha256 && salt_length == 32) {
|
||
|
return SignatureAlgorithm::kRsaPssSha256;
|
||
|
}
|
||
|
if (hash == DigestAlgorithm::Sha384 && salt_length == 48) {
|
||
|
return SignatureAlgorithm::kRsaPssSha384;
|
||
|
}
|
||
|
if (hash == DigestAlgorithm::Sha512 && salt_length == 64) {
|
||
|
return SignatureAlgorithm::kRsaPssSha512;
|
||
|
}
|
||
|
|
||
|
return std::nullopt;
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
[[nodiscard]] 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();
|
||
|
}
|
||
|
|
||
|
[[nodiscard]] bool ParseHashAlgorithm(const der::Input& input,
|
||
|
DigestAlgorithm* out) {
|
||
|
CBS cbs;
|
||
|
CBS_init(&cbs, input.UnsafeData(), input.Length());
|
||
|
const EVP_MD* md = EVP_parse_digest_algorithm(&cbs);
|
||
|
|
||
|
if (md == EVP_sha1()) {
|
||
|
*out = DigestAlgorithm::Sha1;
|
||
|
} else if (md == EVP_sha256()) {
|
||
|
*out = DigestAlgorithm::Sha256;
|
||
|
} else if (md == EVP_sha384()) {
|
||
|
*out = DigestAlgorithm::Sha384;
|
||
|
} else if (md == EVP_sha512()) {
|
||
|
*out = DigestAlgorithm::Sha512;
|
||
|
} else {
|
||
|
// TODO(eroman): Support MD2, MD4, MD5 for completeness?
|
||
|
// Unsupported digest algorithm.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
std::optional<SignatureAlgorithm> ParseSignatureAlgorithm(
|
||
|
const der::Input& algorithm_identifier) {
|
||
|
der::Input oid;
|
||
|
der::Input params;
|
||
|
if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, ¶ms)) {
|
||
|
return std::nullopt;
|
||
|
}
|
||
|
|
||
|
// TODO(eroman): Each OID is tested for equality in order, which is not
|
||
|
// particularly efficient.
|
||
|
|
||
|
// RFC 5912 requires that the parameters for RSA PKCS#1 v1.5 algorithms be
|
||
|
// NULL ("PARAMS TYPE NULL ARE required"), however an empty parameter is also
|
||
|
// allowed for compatibility with non-compliant OCSP responders.
|
||
|
//
|
||
|
// TODO(svaldez): Add warning about non-strict parsing.
|
||
|
if (oid == der::Input(kOidSha1WithRsaEncryption) && IsNullOrEmpty(params)) {
|
||
|
return SignatureAlgorithm::kRsaPkcs1Sha1;
|
||
|
}
|
||
|
if (oid == der::Input(kOidSha256WithRsaEncryption) && IsNullOrEmpty(params)) {
|
||
|
return SignatureAlgorithm::kRsaPkcs1Sha256;
|
||
|
}
|
||
|
if (oid == der::Input(kOidSha384WithRsaEncryption) && IsNullOrEmpty(params)) {
|
||
|
return SignatureAlgorithm::kRsaPkcs1Sha384;
|
||
|
}
|
||
|
if (oid == der::Input(kOidSha512WithRsaEncryption) && IsNullOrEmpty(params)) {
|
||
|
return SignatureAlgorithm::kRsaPkcs1Sha512;
|
||
|
}
|
||
|
if (oid == der::Input(kOidSha1WithRsaSignature) && IsNullOrEmpty(params)) {
|
||
|
return SignatureAlgorithm::kRsaPkcs1Sha1;
|
||
|
}
|
||
|
|
||
|
// RFC 5912 requires that the parameters for ECDSA algorithms be absent
|
||
|
// ("PARAMS TYPE NULL ARE absent"):
|
||
|
if (oid == der::Input(kOidEcdsaWithSha1) && IsEmpty(params)) {
|
||
|
return SignatureAlgorithm::kEcdsaSha1;
|
||
|
}
|
||
|
if (oid == der::Input(kOidEcdsaWithSha256) && IsEmpty(params)) {
|
||
|
return SignatureAlgorithm::kEcdsaSha256;
|
||
|
}
|
||
|
if (oid == der::Input(kOidEcdsaWithSha384) && IsEmpty(params)) {
|
||
|
return SignatureAlgorithm::kEcdsaSha384;
|
||
|
}
|
||
|
if (oid == der::Input(kOidEcdsaWithSha512) && IsEmpty(params)) {
|
||
|
return SignatureAlgorithm::kEcdsaSha512;
|
||
|
}
|
||
|
|
||
|
if (oid == der::Input(kOidRsaSsaPss)) {
|
||
|
return ParseRsaPss(params);
|
||
|
}
|
||
|
|
||
|
// Unknown signature algorithm.
|
||
|
return std::nullopt;
|
||
|
}
|
||
|
|
||
|
std::optional<DigestAlgorithm> GetTlsServerEndpointDigestAlgorithm(
|
||
|
SignatureAlgorithm alg) {
|
||
|
// See RFC 5929, section 4.1. RFC 5929 breaks the signature algorithm
|
||
|
// abstraction by trying to extract individual digest algorithms. (While
|
||
|
// common, this is not a universal property of signature algorithms.) We
|
||
|
// implement this within the library, so callers do not need to condition over
|
||
|
// all algorithms.
|
||
|
switch (alg) {
|
||
|
// If the single digest algorithm is SHA-1, use SHA-256.
|
||
|
case SignatureAlgorithm::kRsaPkcs1Sha1:
|
||
|
case SignatureAlgorithm::kEcdsaSha1:
|
||
|
return DigestAlgorithm::Sha256;
|
||
|
|
||
|
case SignatureAlgorithm::kRsaPkcs1Sha256:
|
||
|
case SignatureAlgorithm::kEcdsaSha256:
|
||
|
return DigestAlgorithm::Sha256;
|
||
|
|
||
|
case SignatureAlgorithm::kRsaPkcs1Sha384:
|
||
|
case SignatureAlgorithm::kEcdsaSha384:
|
||
|
return DigestAlgorithm::Sha384;
|
||
|
|
||
|
case SignatureAlgorithm::kRsaPkcs1Sha512:
|
||
|
case SignatureAlgorithm::kEcdsaSha512:
|
||
|
return DigestAlgorithm::Sha512;
|
||
|
|
||
|
// It is ambiguous whether hash-matching RSASSA-PSS instantiations count as
|
||
|
// using one or multiple digests, but the corresponding digest is the only
|
||
|
// reasonable interpretation.
|
||
|
case SignatureAlgorithm::kRsaPssSha256:
|
||
|
return DigestAlgorithm::Sha256;
|
||
|
case SignatureAlgorithm::kRsaPssSha384:
|
||
|
return DigestAlgorithm::Sha384;
|
||
|
case SignatureAlgorithm::kRsaPssSha512:
|
||
|
return DigestAlgorithm::Sha512;
|
||
|
}
|
||
|
return std::nullopt;
|
||
|
}
|
||
|
|
||
|
} // namespace net
|