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

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: Address Ryan's comments 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 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
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
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
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
OLDNEW
« no previous file with comments | « net/cert/internal/verify_signed_data.h ('k') | net/cert/internal/verify_signed_data_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698