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 |