| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/internal/verify_signed_data.h" | 5 #include "net/cert/internal/verify_signed_data.h" |
| 6 | 6 |
| 7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "net/der/parse_values.h" | 8 #include "net/der/parse_values.h" |
| 9 | 9 |
| 10 // TODO(eroman): There is no intention to implement this for non-OpenSSL. Remove | 10 // TODO(eroman): There is no intention to implement this for non-OpenSSL. Remove |
| 11 // this branch once the migration is complete. This could have been done as a | 11 // this branch once the migration is complete. This could have been done as a |
| 12 // conditional file (_openssl.cc) in the build file instead, but that is likely | 12 // conditional file (_openssl.cc) in the build file instead, but that is likely |
| 13 // not worth the effort at this point. | 13 // not worth the effort at this point. |
| 14 | 14 |
| 15 #if !defined(USE_OPENSSL) | 15 #if !defined(USE_OPENSSL) |
| 16 | 16 |
| 17 namespace net { | 17 namespace net { |
| 18 | 18 |
| 19 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, | 19 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, |
| 20 const der::Input& signed_data, | 20 const der::Input& signed_data, |
| 21 const der::BitString& signature_value, | 21 const der::BitString& signature_value, |
| 22 const der::Input& public_key) { | 22 const der::Input& public_key, |
| 23 const SignaturePolicy* policy) { |
| 23 NOTIMPLEMENTED(); | 24 NOTIMPLEMENTED(); |
| 24 return false; | 25 return false; |
| 25 } | 26 } |
| 26 | 27 |
| 27 } // namespace net | 28 } // namespace net |
| 28 | 29 |
| 29 #else | 30 #else |
| 30 | 31 |
| 31 #include <openssl/digest.h> | 32 #include <openssl/digest.h> |
| 32 #include <openssl/ec.h> | 33 #include <openssl/ec.h> |
| 33 #include <openssl/ec_key.h> | 34 #include <openssl/ec_key.h> |
| 34 #include <openssl/evp.h> | 35 #include <openssl/evp.h> |
| 35 #include <openssl/rsa.h> | 36 #include <openssl/rsa.h> |
| 36 #include <openssl/x509.h> | 37 #include <openssl/x509.h> |
| 37 | 38 |
| 38 #include "base/compiler_specific.h" | 39 #include "base/compiler_specific.h" |
| 39 #include "crypto/openssl_util.h" | 40 #include "crypto/openssl_util.h" |
| 40 #include "crypto/scoped_openssl_types.h" | 41 #include "crypto/scoped_openssl_types.h" |
| 41 #include "net/cert/internal/signature_algorithm.h" | 42 #include "net/cert/internal/signature_algorithm.h" |
| 43 #include "net/cert/internal/signature_policy.h" |
| 42 #include "net/der/input.h" | 44 #include "net/der/input.h" |
| 43 #include "net/der/parser.h" | 45 #include "net/der/parser.h" |
| 44 | 46 |
| 45 namespace net { | 47 namespace net { |
| 46 | 48 |
| 47 namespace { | 49 namespace { |
| 48 | 50 |
| 49 // Converts a DigestAlgorithm to an equivalent EVP_MD*. | 51 // Converts a DigestAlgorithm to an equivalent EVP_MD*. |
| 50 WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) { | 52 WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) { |
| 51 *out = nullptr; | 53 *out = nullptr; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 154 // COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value | 156 // COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value |
| 155 // of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent, | 157 // of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent, |
| 156 // RFC 3279 says they must be NULL: | 158 // RFC 3279 says they must be NULL: |
| 157 // | 159 // |
| 158 // The rsaEncryption OID is intended to be used in the algorithm field | 160 // The rsaEncryption OID is intended to be used in the algorithm field |
| 159 // of a value of type AlgorithmIdentifier. The parameters field MUST | 161 // of a value of type AlgorithmIdentifier. The parameters field MUST |
| 160 // have ASN.1 type NULL for this algorithm identifier. | 162 // have ASN.1 type NULL for this algorithm identifier. |
| 161 // | 163 // |
| 162 // Following RFC 3279 in this case. | 164 // Following RFC 3279 in this case. |
| 163 WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki, | 165 WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki, |
| 164 crypto::ScopedEVP_PKEY* pkey) { | 166 crypto::ScopedEVP_PKEY* pkey, |
| 165 return ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey); | 167 const SignaturePolicy* policy) { |
| 168 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey)) |
| 169 return false; |
| 170 |
| 171 // Extract the modulus length from the key. |
| 172 crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey->get())); |
| 173 if (!rsa) |
| 174 return false; |
| 175 unsigned int modulus_length_bits = BN_num_bits(rsa->n); |
| 176 |
| 177 return policy->IsAcceptableModulusLengthForRsa(modulus_length_bits); |
| 166 } | 178 } |
| 167 | 179 |
| 168 // Does signature verification using either RSA or ECDSA. | 180 // Does signature verification using either RSA or ECDSA. |
| 169 WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm, | 181 WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm, |
| 170 const der::Input& signed_data, | 182 const der::Input& signed_data, |
| 171 const der::BitString& signature_value, | 183 const der::BitString& signature_value, |
| 172 EVP_PKEY* public_key) { | 184 EVP_PKEY* public_key) { |
| 173 DCHECK(algorithm.algorithm() == SignatureAlgorithmId::RsaPkcs1 || | 185 DCHECK(algorithm.algorithm() == SignatureAlgorithmId::RsaPkcs1 || |
| 174 algorithm.algorithm() == SignatureAlgorithmId::RsaPss || | 186 algorithm.algorithm() == SignatureAlgorithmId::RsaPss || |
| 175 algorithm.algorithm() == SignatureAlgorithmId::Ecdsa); | 187 algorithm.algorithm() == SignatureAlgorithmId::Ecdsa); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 201 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(), | 213 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(), |
| 202 signed_data.Length())) { | 214 signed_data.Length())) { |
| 203 return false; | 215 return false; |
| 204 } | 216 } |
| 205 | 217 |
| 206 return 1 == EVP_DigestVerifyFinal(ctx.get(), | 218 return 1 == EVP_DigestVerifyFinal(ctx.get(), |
| 207 signature_value_bytes.UnsafeData(), | 219 signature_value_bytes.UnsafeData(), |
| 208 signature_value_bytes.Length()); | 220 signature_value_bytes.Length()); |
| 209 } | 221 } |
| 210 | 222 |
| 211 // Returns true if the given curve is allowed for ECDSA. The input is a | |
| 212 // BoringSSL NID. | |
| 213 // | |
| 214 // TODO(eroman): Extract policy decisions such as allowed curves, hashes, RSA | |
| 215 // modulus size, to somewhere more central. | |
| 216 WARN_UNUSED_RESULT bool IsAllowedCurveName(int curve_nid) { | |
| 217 switch (curve_nid) { | |
| 218 case NID_X9_62_prime256v1: | |
| 219 case NID_secp384r1: | |
| 220 case NID_secp521r1: | |
| 221 return true; | |
| 222 } | |
| 223 return false; | |
| 224 } | |
| 225 | |
| 226 // Parses an EC public key from SPKI to an EVP_PKEY. | 223 // Parses an EC public key from SPKI to an EVP_PKEY. |
| 227 // | 224 // |
| 228 // Returns true on success. | 225 // Returns true on success. |
| 229 // | 226 // |
| 230 // RFC 5912 describes all the ECDSA signature algorithms as requiring a public | 227 // RFC 5912 describes all the ECDSA signature algorithms as requiring a public |
| 231 // key of type "pk-ec": | 228 // key of type "pk-ec": |
| 232 // | 229 // |
| 233 // pk-ec PUBLIC-KEY ::= { | 230 // pk-ec PUBLIC-KEY ::= { |
| 234 // IDENTIFIER id-ecPublicKey | 231 // IDENTIFIER id-ecPublicKey |
| 235 // KEY ECPoint | 232 // KEY ECPoint |
| (...skipping 25 matching lines...) Expand all Loading... |
| 261 // | 258 // |
| 262 // NamedCurve CURVE ::= { | 259 // NamedCurve CURVE ::= { |
| 263 // { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } | | 260 // { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } | |
| 264 // { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } | | 261 // { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } | |
| 265 // { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } | | 262 // { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } | |
| 266 // { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } | | 263 // { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } | |
| 267 // { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 }, | 264 // { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 }, |
| 268 // ... -- Extensible | 265 // ... -- Extensible |
| 269 // } | 266 // } |
| 270 WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki, | 267 WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki, |
| 271 crypto::ScopedEVP_PKEY* pkey) { | 268 crypto::ScopedEVP_PKEY* pkey, |
| 269 const SignaturePolicy* policy) { |
| 272 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey)) | 270 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey)) |
| 273 return false; | 271 return false; |
| 274 | 272 |
| 275 // Enforce policy on allowed curves in case ImportPkeyFromSpki() were to | 273 // Extract the curve name. |
| 276 // recognize and allow use of a weak curve. | |
| 277 crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey->get())); | 274 crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey->get())); |
| 278 if (!ec.get()) | 275 if (!ec.get()) |
| 279 return false; // Unexpected. | 276 return false; // Unexpected. |
| 277 int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get())); |
| 280 | 278 |
| 281 int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get())); | 279 return policy->IsAcceptableCurveForEcdsa(curve_nid); |
| 282 return IsAllowedCurveName(curve_nid); | |
| 283 } | 280 } |
| 284 | 281 |
| 285 } // namespace | 282 } // namespace |
| 286 | 283 |
| 287 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, | 284 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, |
| 288 const der::Input& signed_data, | 285 const der::Input& signed_data, |
| 289 const der::BitString& signature_value, | 286 const der::BitString& signature_value, |
| 290 const der::Input& public_key_spki) { | 287 const der::Input& public_key_spki, |
| 288 const SignaturePolicy* policy) { |
| 289 if (!policy->IsAcceptableSignatureAlgorithm(signature_algorithm)) |
| 290 return false; |
| 291 |
| 291 crypto::ScopedEVP_PKEY public_key; | 292 crypto::ScopedEVP_PKEY public_key; |
| 292 | 293 |
| 293 // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm. | 294 // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm. |
| 294 switch (signature_algorithm.algorithm()) { | 295 switch (signature_algorithm.algorithm()) { |
| 295 case SignatureAlgorithmId::RsaPkcs1: | 296 case SignatureAlgorithmId::RsaPkcs1: |
| 296 case SignatureAlgorithmId::RsaPss: | 297 case SignatureAlgorithmId::RsaPss: |
| 297 if (!ParseRsaKeyFromSpki(public_key_spki, &public_key)) | 298 if (!ParseRsaKeyFromSpki(public_key_spki, &public_key, policy)) |
| 298 return false; | 299 return false; |
| 299 break; | 300 break; |
| 300 case SignatureAlgorithmId::Ecdsa: | 301 case SignatureAlgorithmId::Ecdsa: |
| 301 if (!ParseEcKeyFromSpki(public_key_spki, &public_key)) | 302 if (!ParseEcKeyFromSpki(public_key_spki, &public_key, policy)) |
| 302 return false; | 303 return false; |
| 303 break; | 304 break; |
| 304 } | 305 } |
| 305 | 306 |
| 306 return DoVerify(signature_algorithm, signed_data, signature_value, | 307 return DoVerify(signature_algorithm, signed_data, signature_value, |
| 307 public_key.get()); | 308 public_key.get()); |
| 308 } | 309 } |
| 309 | 310 |
| 310 } // namespace net | 311 } // namespace net |
| 311 | 312 |
| 312 #endif | 313 #endif |
| OLD | NEW |