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

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

Issue 1217653006: Add DER parsing for rsaPss signature algorithms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@sign_parse_alg
Patch Set: rebase and use results of "git cl format" from new clang-format 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 | « no previous file | 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
index 62d50eaf0f60d66ace3c0b40b06d34414ca5c87f..468fa16c3a62b8d8eb84fdbedabf6648ecff606f 100644
--- a/net/cert/internal/signature_algorithm.cc
+++ b/net/cert/internal/signature_algorithm.cc
@@ -4,7 +4,9 @@
#include "net/cert/internal/signature_algorithm.h"
+#include "base/numerics/safe_math.h"
#include "net/der/input.h"
+#include "net/der/parse_values.h"
#include "net/der/parser.h"
namespace net {
@@ -103,6 +105,61 @@ const uint8_t kOidEcdsaWithSha384[] =
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-sha1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) oiw(14) secsig(3)
+// algorithm(2) 26 }
+//
+// In dotted notation: 1.3.14.3.2.26
+const uint8_t kOidSha1[] = {0x2B, 0x0E, 0x03, 0x02, 0x1A};
+
+// From RFC 5912:
+//
+// id-sha256 OBJECT IDENTIFIER ::=
+// { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
+// csor(3) nistAlgorithms(4) hashalgs(2) 1 }
+//
+// In dotted notation: 2.16.840.1.101.3.4.2.1
+const uint8_t kOidSha256[] = {0x60, 0x86, 0x48, 0x01, 0x65,
+ 0x03, 0x04, 0x02, 0x01};
+
+// From RFC 5912:
+//
+// id-sha384 OBJECT IDENTIFIER ::=
+// { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
+// csor(3) nistAlgorithms(4) hashalgs(2) 2 }
+//
+// In dotted notation: 2.16.840.1.101.3.4.2.2
+const uint8_t kOidSha384[] = {0x60, 0x86, 0x48, 0x01, 0x65,
+ 0x03, 0x04, 0x02, 0x02};
+
+// From RFC 5912:
+//
+// id-sha512 OBJECT IDENTIFIER ::=
+// { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)
+// csor(3) nistAlgorithms(4) hashalgs(2) 3 }
+//
+// In dotted notation: 2.16.840.1.101.3.4.2.3
+const uint8_t kOidSha512[] = {0x60, 0x86, 0x48, 0x01, 0x65,
+ 0x03, 0x04, 0x02, 0x03};
+
+// 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};
+
// RFC 5280 section 4.1.1.2 defines signatureAlgorithm as:
//
// AlgorithmIdentifier ::= SEQUENCE {
@@ -260,6 +317,222 @@ scoped_ptr<SignatureAlgorithm> ParseEcdsa(DigestAlgorithm digest,
return SignatureAlgorithm::CreateEcdsa(digest);
}
+// Parses a HashAlgorithm as defined by RFC 5912:
+//
+// HashAlgorithm ::= AlgorithmIdentifier{DIGEST-ALGORITHM,
+// {HashAlgorithms}}
+//
+// HashAlgorithms DIGEST-ALGORITHM ::= {
+// { IDENTIFIER id-sha1 PARAMS TYPE NULL ARE preferredPresent } |
+// { IDENTIFIER id-sha224 PARAMS TYPE NULL ARE preferredPresent } |
+// { IDENTIFIER id-sha256 PARAMS TYPE NULL ARE preferredPresent } |
+// { IDENTIFIER id-sha384 PARAMS TYPE NULL ARE preferredPresent } |
+// { IDENTIFIER id-sha512 PARAMS TYPE NULL ARE preferredPresent }
+// }
+WARN_UNUSED_RESULT bool ParseHashAlgorithm(const der::Input input,
+ DigestAlgorithm* out) {
+ der::Input oid;
+ der::Input params;
+ if (!ParseAlgorithmIdentifier(input, &oid, &params))
+ return false;
+
+ DigestAlgorithm hash;
+
+ if (oid.Equals(der::Input(kOidSha1))) {
+ hash = DigestAlgorithm::Sha1;
+ } else if (oid.Equals(der::Input(kOidSha256))) {
+ hash = DigestAlgorithm::Sha256;
+ } else if (oid.Equals(der::Input(kOidSha384))) {
+ hash = DigestAlgorithm::Sha384;
+ } else if (oid.Equals(der::Input(kOidSha512))) {
+ hash = DigestAlgorithm::Sha512;
+ } else {
+ // Unsupported digest algorithm.
+ return false;
+ }
+
+ // From RFC 5912: "PARAMS TYPE NULL ARE preferredPresent". Which is to say
+ // the can either be absent, or NULL.
+ if (!IsEmpty(params) && !IsNull(params))
+ return false;
+
+ *out = hash;
+ return true;
+}
+
+// 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.
+WARN_UNUSED_RESULT bool ParseMaskGenAlgorithm(const der::Input input,
+ DigestAlgorithm* mgf1_hash) {
+ der::Input oid;
+ der::Input params;
+ if (!ParseAlgorithmIdentifier(input, &oid, &params))
+ return false;
+
+ // MGF1 is the only supported mask generation algorithm.
+ if (!oid.Equals(der::Input(kOidMgf1)))
+ return false;
+
+ return ParseHashAlgorithm(params, mgf1_hash);
+}
+
+// Consumes an optional, explicitly-tagged INTEGER from |parser|, using the
+// indicated context-specific class number. Values greater than 32-bits will be
+// rejected.
+//
+// Returns true on success and sets |*present| to true if the field was present.
+WARN_UNUSED_RESULT bool ReadOptionalContextSpecificUint32(der::Parser* parser,
+ uint8_t class_number,
+ uint32_t* out,
+ bool* present) {
+ der::Input value;
+ bool has_value;
+
+ // Read the context specific value.
+ if (!parser->ReadOptionalTag(der::ContextSpecificConstructed(class_number),
+ &value, &has_value)) {
+ return false;
+ }
+
+ if (has_value) {
+ // Parse the integer contained in it.
+ der::Parser number_parser(value);
+ uint64_t uint64_value;
+
+ if (!number_parser.ReadUint64(&uint64_value))
+ return false;
+ if (number_parser.HasMore())
+ return false;
+
+ // Cast the number to a uint32_t
+ base::CheckedNumeric<uint32_t> casted(uint64_value);
+ if (!casted.IsValid())
+ return false;
+ *out = casted.ValueOrDie();
+ }
+
+ *present = has_value;
+ return true;
+}
+
+// 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.
+scoped_ptr<SignatureAlgorithm> ParseRsaPss(const der::Input& params) {
+ der::Parser parser(params);
+ der::Parser params_parser;
+ if (!parser.ReadSequence(&params_parser))
+ return nullptr;
+
+ // There shouldn't be anything after the sequence (by definition the
+ // parameters is a single sequence).
+ if (parser.HasMore())
+ return nullptr;
+
+ bool has_field;
+ der::Input field;
+
+ // Parse:
+ // hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier,
+ DigestAlgorithm hash = DigestAlgorithm::Sha1;
+ if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(0), &field,
+ &has_field)) {
+ return nullptr;
+ }
+ if (has_field && !ParseHashAlgorithm(field, &hash))
+ return nullptr;
+
+ // Parse:
+ // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
+ DigestAlgorithm mgf1_hash = DigestAlgorithm::Sha1;
+ if (!params_parser.ReadOptionalTag(der::ContextSpecificConstructed(1), &field,
+ &has_field)) {
+ return nullptr;
+ }
+ if (has_field && !ParseMaskGenAlgorithm(field, &mgf1_hash))
+ return nullptr;
+
+ // Parse:
+ // saltLength [2] INTEGER DEFAULT 20,
+ uint32_t salt_length = 20u;
+ if (!ReadOptionalContextSpecificUint32(&params_parser, 2, &salt_length,
+ &has_field)) {
+ return nullptr;
+ }
+
+ // Parse:
+ // trailerField [3] INTEGER DEFAULT 1
+ uint32_t trailer_field = 1u;
+ if (!ReadOptionalContextSpecificUint32(&params_parser, 3, &trailer_field,
+ &has_field)) {
+ return nullptr;
+ }
+
+ // RFC 4055 says that the trailer field must be 1:
+ //
+ // The trailerField field is an integer. It provides
+ // compatibility with IEEE Std 1363a-2004 [P1363A]. The value
+ // MUST be 1, which represents the trailer field with hexadecimal
+ // value 0xBC. Other trailer fields, including the trailer field
+ // composed of HashID concatenated with 0xCC that is specified in
+ // IEEE Std 1363a, are not supported. Implementations that
+ // perform signature generation MUST omit the trailerField field,
+ // indicating that the default trailer field value was used.
+ // Implementations that perform signature validation MUST
+ // recognize both a present trailerField field with value 1 and an
+ // absent trailerField field.
+ if (trailer_field != 1)
+ return nullptr;
+
+ // There must not be any unconsumed data left. (RFC 5912 does not explicitly
+ // include an extensibility point for RSASSA-PSS-params)
+ if (params_parser.HasMore())
+ return nullptr;
+
+ return SignatureAlgorithm::CreateRsaPss(hash, mgf1_hash, salt_length);
+}
+
} // namespace
RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash,
@@ -308,7 +581,8 @@ scoped_ptr<SignatureAlgorithm> SignatureAlgorithm::CreateFromDer(
if (oid.Equals(der::Input(kOidEcdsaWithSha512)))
return ParseEcdsa(DigestAlgorithm::Sha512, params);
- // TODO(eroman): Add parsing of RSASSA-PSS
+ if (oid.Equals(der::Input(kOidRsaSsaPss)))
+ return ParseRsaPss(params);
if (oid.Equals(der::Input(kOidSha1WithRsaSignature)))
return ParseRsaPkcs1(DigestAlgorithm::Sha1, params);
« no previous file with comments | « no previous file | net/cert/internal/signature_algorithm_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698