Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/cert/internal/signature_algorithm.h" | |
| 6 | |
| 7 #include <stdint.h> | |
| 8 | |
| 9 #include "net/der/input.h" | |
| 10 #include "net/der/parser.h" | |
| 11 | |
| 12 namespace net { | |
| 13 | |
| 14 namespace { | |
| 15 | |
| 16 // From RFC 3279 section 2.2.1: | |
| 17 // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { | |
| 18 // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) | |
| 19 // pkcs-1(1) 5 } | |
| 20 // In dotted notation: 1.2.840.113549.1.1.5 | |
| 21 const uint8_t kOidSha1WithRsaEncryption[] = | |
| 22 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05}; | |
| 23 | |
| 24 // From RFC 4055 section 6: | |
| 25 // pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) | |
| 26 // us(840) rsadsi(113549) pkcs(1) 1 } | |
| 27 | |
| 28 // From RFC 4055 section 5: | |
| 29 // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } | |
| 30 // In dotted notation: 1.2.840.113549.1.1.11 | |
| 31 const uint8_t kOidSha256WithRsaEncryption[] = | |
| 32 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b}; | |
| 33 | |
| 34 // From RFC 4055 section 5: | |
| 35 // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } | |
| 36 // In dotted notation: 1.2.840.113549.1.1.12 | |
| 37 const uint8_t kOidSha384WithRsaEncryption[] = | |
| 38 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c}; | |
| 39 | |
| 40 // From RFC 4055 section 5: | |
| 41 // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } | |
| 42 // In dotted notation: 1.2.840.113549.1.1.13 | |
| 43 const uint8_t kOidSha512WithRsaEncryption[] = | |
| 44 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d}; | |
| 45 | |
| 46 // From RFC 3279 section 2.2.3: | |
| 47 // ansi-X9-62 OBJECT IDENTIFIER ::= { | |
| 48 // iso(1) member-body(2) us(840) 10045 } | |
| 49 // | |
| 50 // id-ecSigType OBJECT IDENTIFIER ::= { | |
| 51 // ansi-X9-62 signatures(4) } | |
| 52 // | |
| 53 // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { | |
| 54 // id-ecSigType 1 } | |
| 55 // In dotted notation: 1.2.840.10045.4.1 | |
| 56 const uint8_t kOidEcdsaWithSha1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01}; | |
| 57 | |
| 58 // From RFC 5758 section 3.2: | |
| 59 // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) | |
| 60 // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } | |
| 61 // In dotted notation: 1.2.840.10045.4.3.2 | |
| 62 const uint8_t kOidEcdsaWithSha256[] = | |
| 63 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02}; | |
| 64 | |
| 65 // From RFC 5758 section 3.2: | |
| 66 // ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) | |
| 67 // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } | |
| 68 // In dotted notation: 1.2.840.10045.4.3.3 | |
| 69 const uint8_t kOidEcdsaWithSha384[] = | |
| 70 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03}; | |
| 71 | |
| 72 // From RFC 5758 section 3.2: | |
| 73 // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) | |
| 74 // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } | |
| 75 // In dotted notation: 1.2.840.10045.4.3.4 | |
| 76 const uint8_t kOidEcdsaWithSha512[] = | |
| 77 {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04}; | |
| 78 | |
| 79 // From RFC 4055 section 3.1: | |
| 80 // id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 } | |
| 81 // In dotted notation: 1.2.840.113549.1.1.10 | |
| 82 const uint8_t kOidRsaSsaPss[] = | |
| 83 {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0a}; | |
| 84 | |
| 85 // RFC 5280 section 4.1.1.2 defines signatureAlgorithm as: | |
| 86 // | |
| 87 // AlgorithmIdentifier ::= SEQUENCE { | |
| 88 // algorithm OBJECT IDENTIFIER, | |
| 89 // parameters ANY DEFINED BY algorithm OPTIONAL } | |
| 90 WARN_UNUSED_RESULT bool ParseAlgorithmIdentifier(const der::Input& input, | |
| 91 der::Input* algorithm, | |
| 92 der::Input* parameters) { | |
| 93 der::Parser parser(input); | |
| 94 | |
| 95 der::Parser algorithm_identifier_parser; | |
| 96 if (!parser.ReadSequence(&algorithm_identifier_parser)) | |
| 97 return false; | |
| 98 | |
| 99 // There shouldn't be anything after the sequence. | |
| 100 if (parser.HasMore()) | |
| 101 return false; | |
| 102 | |
| 103 if (!algorithm_identifier_parser.ReadTag(der::kOid, algorithm)) | |
| 104 return false; | |
| 105 | |
| 106 // Read the optional parameters to a der::Input. The parameters can be at | |
| 107 // most one TLV (for instance NULL or a sequence). | |
| 108 *parameters = der::Input(); | |
| 109 if (algorithm_identifier_parser.HasMore() && | |
| 110 !algorithm_identifier_parser.ReadRawTLV(parameters)) { | |
| 111 return false; | |
| 112 } | |
| 113 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
| |
| 114 } | |
| 115 | |
| 116 // Returns true if the entirety of the input is a NULL value, or is empty. | |
| 117 WARN_UNUSED_RESULT bool IsNullOrEmpty(const der::Input& input) { | |
| 118 if (input.Length() == 0) | |
| 119 return true; | |
| 120 | |
| 121 der::Parser parser(input); | |
| 122 der::Input null_value; | |
| 123 if (!parser.ReadTag(der::kNull, &null_value)) | |
| 124 return false; | |
| 125 | |
| 126 // NULL values are TLV encoded; the value is expected to be empty. | |
| 127 if (null_value.Length() != 0) | |
| 128 return false; | |
| 129 | |
| 130 return !parser.HasMore(); | |
| 131 } | |
| 132 | |
| 133 // Parses parameters for RSA PKCS#1 v1.5 from |parameters_parser| (ensure there | |
| 134 // are none), and assigns the resulting algorithm identifier to |*out|. | |
| 135 // | |
| 136 // Returns true on success. | |
| 137 // | |
| 138 // Note that the parameter parsing used is more permissive than the specs with | |
| 139 // regards to sha-1WithRSAEncryption - it accepts both NULL and empty | |
| 140 // parameters. | |
| 141 // | |
| 142 // Relevant specs: | |
| 143 // | |
| 144 // RFC 4055 section 5 (in reference to sha256WithRSAEncryption et al): | |
| 145 // When any of these four object identifiers appears within an | |
| 146 // AlgorithmIdentifier, the parameters MUST be NULL. Implementations | |
| 147 // MUST accept the parameters being absent as well as present. | |
| 148 // | |
| 149 // RFC 3279 section 2.2.1 (in reference to sha-1WithRSAEncryption): | |
| 150 // When any of these three OIDs appears within the ASN.1 type | |
| 151 // AlgorithmIdentifier, the parameters component of that type SHALL be | |
| 152 // the ASN.1 type NULL. | |
| 153 WARN_UNUSED_RESULT bool ParseRsaPkcs1(DigestAlgorithm digest, | |
| 154 const der::Input& params, | |
| 155 SignatureAlgorithm* out) { | |
| 156 if (!IsNullOrEmpty(params)) | |
| 157 return false; | |
| 158 | |
| 159 out->AssignRsaPkcs1(digest); | |
| 160 return true; | |
| 161 } | |
| 162 | |
| 163 // Parses parameters for ECDSA from |parameters_parser| (ensure there | |
| 164 // are none), and assigns the resulting algorithm identifier to |*out|. | |
| 165 // | |
| 166 // Returns true on success. | |
| 167 // | |
| 168 // Note that the parameter parsing used is more permissive than the specs with | |
| 169 // 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
| |
| 170 // | |
| 171 // Relevant specs: | |
| 172 // | |
| 173 // RFC 5758 section-3.2: | |
| 174 // When the ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with-SHA384, or | |
| 175 // ecdsa-with-SHA512 algorithm identifier appears in the algorithm field | |
| 176 // as an AlgorithmIdentifier, the encoding MUST omit the parameters | |
| 177 // field. That is, the AlgorithmIdentifier SHALL be a SEQUENCE of one | |
| 178 // component, the OID ecdsa-with-SHA224, ecdsa-with-SHA256, ecdsa-with- | |
| 179 // SHA384, or ecdsa-with-SHA512. | |
| 180 // | |
| 181 // RFC 3279 section 2.2.3: | |
| 182 // When the ecdsa-with-SHA1 algorithm identifier appears as the | |
| 183 // algorithm field in an AlgorithmIdentifier, the encoding MUST omit the | |
| 184 // parameters field. That is, the AlgorithmIdentifier SHALL be a | |
| 185 // SEQUENCE of one component: the OBJECT IDENTIFIER ecdsa-with-SHA1. | |
| 186 WARN_UNUSED_RESULT bool ParseEcdsa(DigestAlgorithm digest, | |
| 187 const der::Input& params, | |
| 188 SignatureAlgorithm* out) { | |
| 189 if (!IsNullOrEmpty(params)) | |
| 190 return false; | |
| 191 | |
| 192 out->AssignEcdsa(digest); | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 // From RFC 4055: | |
| 197 // RSASSA-PSS-params ::= SEQUENCE { | |
| 198 // hashAlgorithm [0] HashAlgorithm DEFAULT | |
| 199 // sha1Identifier, | |
| 200 // maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT | |
| 201 // mgf1SHA1Identifier, | |
| 202 // saltLength [2] INTEGER DEFAULT 20, | |
| 203 // trailerField [3] INTEGER DEFAULT 1 } | |
| 204 // | |
| 205 // HashAlgorithm ::= AlgorithmIdentifier | |
| 206 // | |
| 207 // MaskGenAlgorithm ::= AlgorithmIdentifier | |
| 208 WARN_UNUSED_RESULT bool ParseRsaPss(const der::Input& params, | |
| 209 SignatureAlgorithm* out) { | |
| 210 // TODO(eroman): Implement. | |
| 211 return false; | |
| 212 } | |
| 213 | |
| 214 } // namespace | |
| 215 | |
| 216 RsaPssParameters::RsaPssParameters(DigestAlgorithm mgf1_hash, | |
| 217 uint32_t salt_length) | |
| 218 : mgf1_hash_(mgf1_hash), salt_length_(salt_length) { | |
| 219 } | |
| 220 | |
| 221 bool RsaPssParameters::Equals(const SignatureAlgorithmParameters* other) const { | |
| 222 const RsaPssParameters* params = static_cast<const RsaPssParameters*>(other); | |
| 223 return mgf1_hash_ == params->mgf1_hash_ && | |
| 224 salt_length_ == params->salt_length_; | |
| 225 } | |
| 226 | |
| 227 SignatureAlgorithm::SignatureAlgorithm() { | |
| 228 AssignInvalid(); | |
| 229 } | |
| 230 | |
| 231 SignatureAlgorithm::~SignatureAlgorithm() { | |
| 232 } | |
| 233 | |
| 234 bool SignatureAlgorithm::IsValid() const { | |
| 235 return params_; | |
| 236 } | |
| 237 | |
| 238 SignatureAlgorithmId SignatureAlgorithm::algorithm() const { | |
| 239 DCHECK(IsValid()); | |
| 240 return algorithm_; | |
| 241 } | |
| 242 | |
| 243 DigestAlgorithm SignatureAlgorithm::digest() const { | |
| 244 DCHECK(IsValid()); | |
| 245 return digest_; | |
| 246 } | |
| 247 | |
| 248 bool SignatureAlgorithm::ParseDer(const der::Input& algorithm_identifier) { | |
| 249 AssignInvalid(); | |
| 250 | |
| 251 der::Input oid; | |
| 252 der::Input params; | |
| 253 if (!ParseAlgorithmIdentifier(algorithm_identifier, &oid, ¶ms)) | |
| 254 return false; | |
| 255 | |
| 256 // TODO(eroman): Each OID is tested for equality in order, which is not | |
| 257 // particularly efficient. | |
| 258 | |
| 259 if (oid.Equals(der::Input(kOidSha1WithRsaEncryption))) | |
| 260 return ParseRsaPkcs1(DigestAlgorithm::Sha1, params, this); | |
| 261 | |
| 262 if (oid.Equals(der::Input(kOidSha256WithRsaEncryption))) | |
| 263 return ParseRsaPkcs1(DigestAlgorithm::Sha256, params, this); | |
| 264 | |
| 265 if (oid.Equals(der::Input(kOidSha384WithRsaEncryption))) | |
| 266 return ParseRsaPkcs1(DigestAlgorithm::Sha384, params, this); | |
| 267 | |
| 268 if (oid.Equals(der::Input(kOidSha512WithRsaEncryption))) | |
| 269 return ParseRsaPkcs1(DigestAlgorithm::Sha512, params, this); | |
| 270 | |
| 271 if (oid.Equals(der::Input(kOidEcdsaWithSha1))) | |
| 272 return ParseEcdsa(DigestAlgorithm::Sha1, params, this); | |
| 273 | |
| 274 if (oid.Equals(der::Input(kOidEcdsaWithSha256))) | |
| 275 return ParseEcdsa(DigestAlgorithm::Sha256, params, this); | |
| 276 | |
| 277 if (oid.Equals(der::Input(kOidEcdsaWithSha384))) | |
| 278 return ParseEcdsa(DigestAlgorithm::Sha384, params, this); | |
| 279 | |
| 280 if (oid.Equals(der::Input(kOidEcdsaWithSha512))) | |
| 281 return ParseEcdsa(DigestAlgorithm::Sha512, params, this); | |
| 282 | |
| 283 if (oid.Equals(der::Input(kOidRsaSsaPss))) | |
| 284 return ParseRsaPss(params, this); | |
| 285 | |
| 286 return false; // Unsupported OID. | |
| 287 } | |
| 288 | |
| 289 void SignatureAlgorithm::AssignRsaPkcs1(DigestAlgorithm digest) { | |
| 290 algorithm_ = SignatureAlgorithmId::RsaPkcs1; | |
| 291 digest_ = digest; | |
| 292 params_.reset(); | |
| 293 } | |
| 294 | |
| 295 void SignatureAlgorithm::AssignEcdsa(DigestAlgorithm digest) { | |
| 296 algorithm_ = SignatureAlgorithmId::Ecdsa; | |
| 297 digest_ = digest; | |
| 298 params_.reset(); | |
| 299 } | |
| 300 | |
| 301 void SignatureAlgorithm::AssignRsaPss(DigestAlgorithm digest, | |
| 302 DigestAlgorithm mgf1_hash, | |
| 303 uint32_t salt_length) { | |
| 304 algorithm_ = SignatureAlgorithmId::RsaPss; | |
| 305 digest_ = digest; | |
| 306 params_.reset(new RsaPssParameters(mgf1_hash, salt_length)); | |
| 307 } | |
| 308 | |
| 309 bool SignatureAlgorithm::Equals(const SignatureAlgorithm& other) const { | |
| 310 if (algorithm_ != other.algorithm_) | |
| 311 return false; | |
| 312 | |
| 313 if (digest_ != other.digest_) | |
| 314 return false; | |
| 315 | |
| 316 if (!params_ != !other.params_) | |
| 317 return false; | |
| 318 | |
| 319 if (params_ && !params_->Equals(other.params_.get())) | |
| 320 return false; | |
| 321 | |
| 322 return true; | |
| 323 } | |
| 324 | |
| 325 const RsaPssParameters* SignatureAlgorithm::ParamsForRsaPss() const { | |
| 326 if (algorithm_ == SignatureAlgorithmId::RsaPss) | |
| 327 return static_cast<RsaPssParameters*>(params_.get()); | |
| 328 return nullptr; | |
| 329 } | |
| 330 | |
| 331 void SignatureAlgorithm::AssignInvalid() { | |
| 332 algorithm_ = static_cast<SignatureAlgorithmId>(-1); | |
| 333 digest_ = static_cast<DigestAlgorithm>(-1); | |
| 334 params_.reset(); | |
| 335 } | |
| 336 | |
| 337 } // namespace net | |
| OLD | NEW |