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