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

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

Issue 1209283004: Implement VerifySignedData() for ECDSA, RSA PKCS#1 and RSA PSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@parse_pss
Patch Set: clarify that signature_value is NOT the BIT STRING itself, but the byte contents Created 5 years, 5 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "net/cert/internal/verify_signed_data.h"
6
7 #include "net/cert/internal/signature_algorithm.h"
8
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
11 // conditional file (_openssl.cc) in the build file instead, but that is likely
12 // not worth the effort at this point.
13
14 #if !defined(USE_OPENSSL)
15
16 namespace net {
17
18 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
19 const der::Input& signed_data,
20 const der::Input& signature_value,
21 const der::Input& public_key) {
22 // Not implemented
23 return false;
24 }
25
26 } // namespace net
27
28 #else
29
30 #include <openssl/evp.h>
31 #include <openssl/pkcs12.h>
davidben 2015/07/07 18:03:56 What's this include for?
eroman 2015/07/07 18:34:43 I was apparently relying on it for its transitive
32 #include <openssl/rand.h>
eroman 2015/07/07 18:34:43 This similarly was not needed, and removed.
33
34 #include "crypto/openssl_util.h"
35 #include "crypto/scoped_openssl_types.h"
36 #include "net/der/input.h"
37 #include "net/der/parser.h"
38
39 namespace net {
40
41 namespace {
42
43 // Creates a EVP_PKEY given the der-encoded bytes of the SPKI. This function
44 // does not do any sort of validation of the resultant key. The consumer is
45 // responsible for verifying the key's type and validity of its parameters.
46 WARN_UNUSED_RESULT bool ImportUnverifiedPkeyFromSpki(
47 const der::Input& spki,
48 crypto::ScopedEVP_PKEY* pkey) {
49 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
50
51 const uint8_t* ptr = spki.UnsafeData();
52 pkey->reset(d2i_PUBKEY(nullptr, &ptr, spki.Length()));
davidben 2015/07/07 18:03:56 This needs x509.h. I'd rather we not use x509.h, b
eroman 2015/07/07 18:34:43 Thanks David! So my take-away is: (1) Switch t
davidben 2015/07/07 18:53:21 Oh, good point. I hadn't thought about WebCrypto.
53 if (!pkey->get() || ptr != spki.UnsafeData() + spki.Length())
54 return false;
55
56 return true;
57 }
58
59 // Converts a DigestAlgorithm to an equivalent EVP_MD*.
60 WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) {
61 switch (digest) {
62 case DigestAlgorithm::Sha1:
63 *out = EVP_sha1();
64 break;
65 case DigestAlgorithm::Sha256:
66 *out = EVP_sha256();
67 break;
68 case DigestAlgorithm::Sha384:
69 *out = EVP_sha384();
70 break;
71 case DigestAlgorithm::Sha512:
72 *out = EVP_sha512();
73 break;
74 }
75
76 return *out;
davidben 2015/07/07 18:03:57 I believe MSVC will grump about this and want !!*o
eroman 2015/07/07 18:34:43 Done.
77 }
78
79 // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success.
80 bool ApplyRsaPssOptions(const RsaPssParameters* params, EVP_PKEY_CTX* pctx) {
81 // BoringSSL takes a signed int for the salt length, and interprets
82 // negative values in a special manner. Make sure not to silently underflow.
83 base::CheckedNumeric<int> salt_length_bytes_int(params->salt_length());
84 if (!salt_length_bytes_int.IsValid())
85 return false;
86
87 const EVP_MD* mgf1_hash;
88 if (!GetDigest(params->mgf1_hash(), &mgf1_hash))
89 return false;
90
91 return (1 == EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
92 1 == EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_hash) &&
93 1 == EVP_PKEY_CTX_set_rsa_pss_saltlen(
94 pctx, salt_length_bytes_int.ValueOrDie()));
95 }
96
97 bool RsaVerify(const SignatureAlgorithm& algorithm,
98 const der::Input& signed_data,
99 const der::Input& signature_value,
100 EVP_PKEY* public_key) {
101 // TODO(eroman): Is it necessary to verify that the public key's parameters
102 // are congruent with the signature algorithm, or will BoringSSL already do
103 // the needed checks?
Ryan Sleevi 2015/07/07 14:07:31 David: Look here
davidben 2015/07/07 18:03:56 I don't believe BoringSSL is even passed the signa
eroman 2015/07/07 18:34:43 Thanks! Indeed, seems the checks are in fact quit
104
105 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
106 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
107 EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|.
108
109 const EVP_MD* digest;
110 if (!GetDigest(algorithm.digest(), &digest))
111 return false;
112
113 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, NULL, public_key))
114 return false;
115
116 // Set the RSASSA-PSS specific options.
117 if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss &&
118 !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx)) {
119 return false;
120 }
121
122 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(),
123 signed_data.Length())) {
124 return false;
125 }
126
127 return 1 == EVP_DigestVerifyFinal(ctx.get(), signature_value.UnsafeData(),
128 signature_value.Length());
129 }
130
131 bool EcdsaVerify(const SignatureAlgorithm& algorithm,
132 const der::Input& signed_data,
133 const der::Input& signature_value,
134 EVP_PKEY* public_key) {
135 // TODO(eroman): Is it necessary to verify that the public key's parameters
136 // are congruent with the signature algorithm, or will BoringSSL already do
137 // the needed checks?
Ryan Sleevi 2015/07/07 14:07:31 David: And here
davidben 2015/07/07 18:03:56 Ditto.
138
139 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
140 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
141
142 const EVP_MD* digest;
143 if (!GetDigest(algorithm.digest(), &digest))
144 return false;
145
146 if (!EVP_DigestVerifyInit(ctx.get(), NULL, digest, NULL, public_key) ||
147 !EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(),
148 signed_data.Length())) {
149 return false;
150 }
151
152 return 1 == EVP_DigestVerifyFinal(ctx.get(), signature_value.UnsafeData(),
153 signature_value.Length());
154 }
155
156 } // namespace
157
158 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
159 const der::Input& signed_data,
160 const der::Input& signature_value,
161 const der::Input& public_key_spki) {
162 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
163
164 // The validity checks on the public key are done in the algorithm-specific
165 // verification functions.
166 crypto::ScopedEVP_PKEY public_key;
167 if (!ImportUnverifiedPkeyFromSpki(public_key_spki, &public_key))
168 return false;
169
170 switch (signature_algorithm.algorithm()) {
171 case SignatureAlgorithmId::RsaPkcs1:
172 case SignatureAlgorithmId::RsaPss:
173 return RsaVerify(signature_algorithm, signed_data, signature_value,
174 public_key.get());
175 case SignatureAlgorithmId::Ecdsa:
176 return EcdsaVerify(signature_algorithm, signed_data, signature_value,
177 public_key.get());
178 }
179
180 return false; // Unsupported algorithm.
181 }
182
183 } // namespace net
184
185 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698