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

Side by Side Diff: net/cert/internal/verify_signed_data.cc

Issue 1259313002: Add some policy controls for VerifySignedData(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@add_python
Patch Set: Created 5 years, 4 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 unified diff | Download patch
OLDNEW
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 VerificationPolicy* 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/verification_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,
52 const VerificationPolicy* policy,
53 const EVP_MD** out) {
50 *out = nullptr; 54 *out = nullptr;
51 55
56 if (!policy->IsAcceptableDigestAlgorithm(digest))
57 return false;
58
52 switch (digest) { 59 switch (digest) {
53 case DigestAlgorithm::Sha1: 60 case DigestAlgorithm::Sha1:
54 *out = EVP_sha1(); 61 *out = EVP_sha1();
55 break; 62 break;
56 case DigestAlgorithm::Sha256: 63 case DigestAlgorithm::Sha256:
57 *out = EVP_sha256(); 64 *out = EVP_sha256();
58 break; 65 break;
59 case DigestAlgorithm::Sha384: 66 case DigestAlgorithm::Sha384:
60 *out = EVP_sha384(); 67 *out = EVP_sha384();
61 break; 68 break;
62 case DigestAlgorithm::Sha512: 69 case DigestAlgorithm::Sha512:
63 *out = EVP_sha512(); 70 *out = EVP_sha512();
64 break; 71 break;
65 } 72 }
66 73
67 return *out != nullptr; 74 return *out != nullptr;
68 } 75 }
69 76
70 // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success. 77 // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success.
71 WARN_UNUSED_RESULT bool ApplyRsaPssOptions(const RsaPssParameters* params, 78 WARN_UNUSED_RESULT bool ApplyRsaPssOptions(const RsaPssParameters* params,
72 EVP_PKEY_CTX* pctx) { 79 EVP_PKEY_CTX* pctx,
80 const VerificationPolicy* policy) {
73 // BoringSSL takes a signed int for the salt length, and interprets 81 // BoringSSL takes a signed int for the salt length, and interprets
74 // negative values in a special manner. Make sure not to silently underflow. 82 // negative values in a special manner. Make sure not to silently underflow.
75 base::CheckedNumeric<int> salt_length_bytes_int(params->salt_length()); 83 base::CheckedNumeric<int> salt_length_bytes_int(params->salt_length());
76 if (!salt_length_bytes_int.IsValid()) 84 if (!salt_length_bytes_int.IsValid())
77 return false; 85 return false;
78 86
79 const EVP_MD* mgf1_hash; 87 const EVP_MD* mgf1_hash;
80 if (!GetDigest(params->mgf1_hash(), &mgf1_hash)) 88 if (!GetDigest(params->mgf1_hash(), policy, &mgf1_hash))
81 return false; 89 return false;
82 90
83 return EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) && 91 return EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
84 EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_hash) && 92 EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_hash) &&
85 EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, 93 EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
86 salt_length_bytes_int.ValueOrDie()); 94 salt_length_bytes_int.ValueOrDie());
87 } 95 }
88 96
89 // TODO(eroman): This function is not strict enough. It accepts BER, other RSA 97 // TODO(eroman): This function is not strict enough. It accepts BER, other RSA
90 // OIDs, and does not check id-rsaEncryption parameters. 98 // OIDs, and does not check id-rsaEncryption parameters.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 // COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value 161 // 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, 162 // of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent,
155 // RFC 3279 says they must be NULL: 163 // RFC 3279 says they must be NULL:
156 // 164 //
157 // The rsaEncryption OID is intended to be used in the algorithm field 165 // The rsaEncryption OID is intended to be used in the algorithm field
158 // of a value of type AlgorithmIdentifier. The parameters field MUST 166 // of a value of type AlgorithmIdentifier. The parameters field MUST
159 // have ASN.1 type NULL for this algorithm identifier. 167 // have ASN.1 type NULL for this algorithm identifier.
160 // 168 //
161 // Following RFC 3279 in this case. 169 // Following RFC 3279 in this case.
162 WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki, 170 WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki,
163 crypto::ScopedEVP_PKEY* pkey) { 171 crypto::ScopedEVP_PKEY* pkey,
164 return ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey); 172 const VerificationPolicy* policy) {
173 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey))
174 return false;
175
176 // Extract the modulus length from the key.
177 crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey->get()));
178 if (!rsa.get())
179 return false;
180 unsigned int modulus_length_bits = BN_num_bits(rsa.get()->n);
181
182 return policy->IsAcceptableModulusLengthForRsa(modulus_length_bits);
165 } 183 }
166 184
167 // Does signature verification using either RSA or ECDSA. 185 // Does signature verification using either RSA or ECDSA.
168 // 186 //
169 // Note that the |signature_value| input is expected to be a byte string (and 187 // Note that the |signature_value| input is expected to be a byte string (and
170 // not a DER-encoded BIT STRING) 188 // not a DER-encoded BIT STRING)
171 WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm, 189 WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm,
172 const der::Input& signed_data, 190 const der::Input& signed_data,
173 const der::Input& signature_value, 191 const der::Input& signature_value,
174 EVP_PKEY* public_key) { 192 EVP_PKEY* public_key,
193 const VerificationPolicy* policy) {
175 DCHECK(algorithm.algorithm() == SignatureAlgorithmId::RsaPkcs1 || 194 DCHECK(algorithm.algorithm() == SignatureAlgorithmId::RsaPkcs1 ||
176 algorithm.algorithm() == SignatureAlgorithmId::RsaPss || 195 algorithm.algorithm() == SignatureAlgorithmId::RsaPss ||
177 algorithm.algorithm() == SignatureAlgorithmId::Ecdsa); 196 algorithm.algorithm() == SignatureAlgorithmId::Ecdsa);
178 197
179 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 198 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
180 199
181 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); 200 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
182 EVP_PKEY_CTX* pctx = nullptr; // Owned by |ctx|. 201 EVP_PKEY_CTX* pctx = nullptr; // Owned by |ctx|.
183 202
184 const EVP_MD* digest; 203 const EVP_MD* digest;
185 if (!GetDigest(algorithm.digest(), &digest)) 204 if (!GetDigest(algorithm.digest(), policy, &digest))
186 return false; 205 return false;
187 206
188 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, nullptr, public_key)) 207 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, nullptr, public_key))
189 return false; 208 return false;
190 209
191 // Set the RSASSA-PSS specific options. 210 // Set the RSASSA-PSS specific options.
192 if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss && 211 if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss &&
193 !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx)) { 212 !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx, policy)) {
194 return false; 213 return false;
195 } 214 }
196 215
197 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(), 216 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(),
198 signed_data.Length())) { 217 signed_data.Length())) {
199 return false; 218 return false;
200 } 219 }
201 220
202 return 1 == EVP_DigestVerifyFinal(ctx.get(), signature_value.UnsafeData(), 221 return 1 == EVP_DigestVerifyFinal(ctx.get(), signature_value.UnsafeData(),
203 signature_value.Length()); 222 signature_value.Length());
204 } 223 }
205 224
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. 225 // Parses an EC public key from SPKI to an EVP_PKEY.
222 // 226 //
223 // Returns true on success. 227 // Returns true on success.
224 // 228 //
225 // RFC 5912 describes all the ECDSA signature algorithms as requiring a public 229 // RFC 5912 describes all the ECDSA signature algorithms as requiring a public
226 // key of type "pk-ec": 230 // key of type "pk-ec":
227 // 231 //
228 // pk-ec PUBLIC-KEY ::= { 232 // pk-ec PUBLIC-KEY ::= {
229 // IDENTIFIER id-ecPublicKey 233 // IDENTIFIER id-ecPublicKey
230 // KEY ECPoint 234 // KEY ECPoint
(...skipping 25 matching lines...) Expand all
256 // 260 //
257 // NamedCurve CURVE ::= { 261 // NamedCurve CURVE ::= {
258 // { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } | 262 // { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } |
259 // { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } | 263 // { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } |
260 // { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } | 264 // { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } |
261 // { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } | 265 // { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } |
262 // { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 }, 266 // { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 },
263 // ... -- Extensible 267 // ... -- Extensible
264 // } 268 // }
265 WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki, 269 WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki,
266 crypto::ScopedEVP_PKEY* pkey) { 270 crypto::ScopedEVP_PKEY* pkey,
271 const VerificationPolicy* policy) {
267 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey)) 272 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey))
268 return false; 273 return false;
269 274
270 // Enforce policy on allowed curves in case ImportPkeyFromSpki() were to 275 // 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())); 276 crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey->get()));
273 if (!ec.get()) 277 if (!ec.get())
274 return false; // Unexpected. 278 return false; // Unexpected.
279 int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
275 280
276 int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get())); 281 return policy->IsAcceptableCurveForEcdsa(curve_nid);
277 return IsAllowedCurveName(curve_nid);
278 } 282 }
279 283
280 } // namespace 284 } // namespace
281 285
282 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, 286 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
283 const der::Input& signed_data, 287 const der::Input& signed_data,
284 const der::Input& signature_value_bit_string, 288 const der::Input& signature_value_bit_string,
285 const der::Input& public_key_spki) { 289 const der::Input& public_key_spki,
290 const VerificationPolicy* policy) {
291 // Optimization: Check the digest before parsing the SPKI. This isn't
292 // strictly necessary as it will also get checked by GetDigest().
293 if (!policy->IsAcceptableDigestAlgorithm(signature_algorithm.digest()))
294 return false;
295
286 crypto::ScopedEVP_PKEY public_key; 296 crypto::ScopedEVP_PKEY public_key;
287 297
288 // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm. 298 // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm.
289 switch (signature_algorithm.algorithm()) { 299 switch (signature_algorithm.algorithm()) {
290 case SignatureAlgorithmId::RsaPkcs1: 300 case SignatureAlgorithmId::RsaPkcs1:
291 case SignatureAlgorithmId::RsaPss: 301 case SignatureAlgorithmId::RsaPss:
292 if (!ParseRsaKeyFromSpki(public_key_spki, &public_key)) 302 if (!ParseRsaKeyFromSpki(public_key_spki, &public_key, policy))
293 return false; 303 return false;
294 break; 304 break;
295 case SignatureAlgorithmId::Ecdsa: 305 case SignatureAlgorithmId::Ecdsa:
296 if (!ParseEcKeyFromSpki(public_key_spki, &public_key)) 306 if (!ParseEcKeyFromSpki(public_key_spki, &public_key, policy))
297 return false; 307 return false;
298 break; 308 break;
299 } 309 }
300 310
301 // Extract the bytes of the signature_value. Assume that the BIT STRING has 311 // 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 312 // 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. 313 // case for all of the currently supported algorithms.
304 der::Input signature_value; 314 der::Input signature_value;
305 der::Parser parser(signature_value_bit_string); 315 der::Parser parser(signature_value_bit_string);
306 if (!parser.ReadBitStringNoUnusedBits(&signature_value)) 316 if (!parser.ReadBitStringNoUnusedBits(&signature_value))
307 return false; 317 return false;
308 // By definition signature_value_bit_string must be a single BIT STRING. 318 // By definition signature_value_bit_string must be a single BIT STRING.
309 if (parser.HasMore()) 319 if (parser.HasMore())
310 return false; 320 return false;
311 321
312 return DoVerify(signature_algorithm, signed_data, signature_value, 322 return DoVerify(signature_algorithm, signed_data, signature_value,
313 public_key.get()); 323 public_key.get(), policy);
314 } 324 }
315 325
316 } // namespace net 326 } // namespace net
317 327
318 #endif 328 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698