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

Side by Side Diff: content/child/webcrypto/openssl/rsa_key_openssl.cc

Issue 401363002: [webcrypto] Add OpenSSL implementation of RSA key generation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase onto master Created 6 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "content/child/webcrypto/openssl/rsa_key_openssl.h" 5 #include "content/child/webcrypto/openssl/rsa_key_openssl.h"
6 6
7 #include <openssl/evp.h> 7 #include <openssl/evp.h>
8 #include <openssl/pkcs12.h> 8 #include <openssl/pkcs12.h>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 return Status::ErrorUnexpected(); 81 return Status::ErrorUnexpected();
82 if (e.size() != BN_bn2bin(rsa.get()->e, &e[0])) 82 if (e.size() != BN_bn2bin(rsa.get()->e, &e[0]))
83 return Status::ErrorUnexpected(); 83 return Status::ErrorUnexpected();
84 84
85 *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed( 85 *key_algorithm = blink::WebCryptoKeyAlgorithm::createRsaHashed(
86 rsa_algorithm, modulus_length_bits, &e[0], e.size(), hash_algorithm); 86 rsa_algorithm, modulus_length_bits, &e[0], e.size(), hash_algorithm);
87 87
88 return Status::Success(); 88 return Status::Success();
89 } 89 }
90 90
91 // Verifies that |key| is consistent with the input algorithm id, and creates a 91 Status CreateWebCryptoPrivateKey(
92 // blink::WebCryptoKeyAlgorithm describing the key. 92 crypto::ScopedEVP_PKEY private_key,
93 // Returns Status::Success() on success and sets |*key_algorithm|. 93 const blink::WebCryptoAlgorithmId rsa_algorithm_id,
94 Status ValidateKeyTypeAndCreateKeyAlgorithm( 94 const blink::WebCryptoAlgorithm& hash,
95 const blink::WebCryptoAlgorithm& algorithm, 95 bool extractable,
96 EVP_PKEY* key, 96 blink::WebCryptoKeyUsageMask usage_mask,
97 blink::WebCryptoKeyAlgorithm* key_algorithm) { 97 blink::WebCryptoKey* key) {
98 // TODO(eroman): Validate the algorithm OID against the webcrypto provided 98 blink::WebCryptoKeyAlgorithm key_algorithm;
99 // hash. http://crbug.com/389400 99 Status status = CreateRsaHashedKeyAlgorithm(
100 if (EVP_PKEY_id(key) != EVP_PKEY_RSA) 100 rsa_algorithm_id, hash.id(), private_key.get(), &key_algorithm);
101 return Status::DataError(); // Data did not define an RSA key. 101 if (status.IsError())
102 return CreateRsaHashedKeyAlgorithm(algorithm.id(), 102 return status;
103 GetInnerHashAlgorithm(algorithm).id(), 103
104 key, 104 // Serialize the key at creation time so that if structured cloning is
105 key_algorithm); 105 // requested it can be done synchronously from the Blink thread.
106 std::vector<uint8_t> pkcs8_data;
107 status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
108 if (status.IsError())
109 return status;
110
111 *key = blink::WebCryptoKey::create(
112 new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
113 blink::WebCryptoKeyTypePrivate,
114 extractable,
115 key_algorithm,
116 usage_mask);
117 return Status::Success();
118 }
119
120 Status CreateWebCryptoPublicKey(
121 crypto::ScopedEVP_PKEY public_key,
122 const blink::WebCryptoAlgorithmId rsa_algorithm_id,
123 const blink::WebCryptoAlgorithm& hash,
124 bool extractable,
125 blink::WebCryptoKeyUsageMask usage_mask,
126 blink::WebCryptoKey* key) {
127 blink::WebCryptoKeyAlgorithm key_algorithm;
128 Status status = CreateRsaHashedKeyAlgorithm(
129 rsa_algorithm_id, hash.id(), public_key.get(), &key_algorithm);
130 if (status.IsError())
131 return status;
132
133 // Serialize the key at creation time so that if structured cloning is
134 // requested it can be done synchronously from the Blink thread.
135 std::vector<uint8_t> spki_data;
136 status = ExportPKeySpki(public_key.get(), &spki_data);
137 if (status.IsError())
138 return status;
139
140 *key = blink::WebCryptoKey::create(
141 new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
142 blink::WebCryptoKeyTypePublic,
143 extractable,
144 key_algorithm,
145 usage_mask);
146 return Status::Success();
106 } 147 }
107 148
108 } // namespace 149 } // namespace
109 150
151 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeGenerateKeyPair(
152 blink::WebCryptoKeyUsageMask combined_usage_mask,
153 blink::WebCryptoKeyUsageMask* public_usage_mask,
154 blink::WebCryptoKeyUsageMask* private_usage_mask) const {
155 Status status = CheckKeyCreationUsages(
156 all_public_key_usages_ | all_private_key_usages_, combined_usage_mask);
157 if (status.IsError())
158 return status;
159
160 *public_usage_mask = combined_usage_mask & all_public_key_usages_;
161 *private_usage_mask = combined_usage_mask & all_private_key_usages_;
162
163 return Status::Success();
164 }
165
166 Status RsaHashedAlgorithm::GenerateKeyPair(
167 const blink::WebCryptoAlgorithm& algorithm,
168 bool extractable,
169 blink::WebCryptoKeyUsageMask public_usage_mask,
170 blink::WebCryptoKeyUsageMask private_usage_mask,
171 blink::WebCryptoKey* public_key,
172 blink::WebCryptoKey* private_key) const {
173 const blink::WebCryptoRsaHashedKeyGenParams* params =
174 algorithm.rsaHashedKeyGenParams();
175
176 unsigned int public_exponent = 0;
177 unsigned int modulus_length_bits = 0;
178 Status status =
179 GetRsaKeyGenParameters(params, &public_exponent, &modulus_length_bits);
180 if (status.IsError())
181 return status;
182
183 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
184
185 // Generate an RSA key pair.
186 crypto::ScopedRSA rsa_private_key(RSA_new());
187 crypto::ScopedBIGNUM bn(BN_new());
188 if (!rsa_private_key.get() || !bn.get() ||
189 !BN_set_word(bn.get(), public_exponent)) {
190 return Status::OperationError();
191 }
192
193 if (!RSA_generate_key_ex(
194 rsa_private_key.get(), modulus_length_bits, bn.get(), NULL)) {
195 return Status::OperationError();
196 }
197
198 // Construct an EVP_PKEY for the private key.
199 crypto::ScopedEVP_PKEY private_pkey(EVP_PKEY_new());
200 if (!private_pkey ||
201 !EVP_PKEY_set1_RSA(private_pkey.get(), rsa_private_key.get())) {
202 return Status::OperationError();
203 }
204
205 // Construct an EVP_PKEY for the public key.
206 crypto::ScopedRSA rsa_public_key(RSAPublicKey_dup(rsa_private_key.get()));
207 crypto::ScopedEVP_PKEY public_pkey(EVP_PKEY_new());
208 if (!public_pkey ||
209 !EVP_PKEY_set1_RSA(public_pkey.get(), rsa_public_key.get())) {
210 return Status::OperationError();
211 }
212
213 // Note that extractable is unconditionally set to true. This is because per
214 // the WebCrypto spec generated public keys are always public.
215 status = CreateWebCryptoPublicKey(public_pkey.Pass(),
216 algorithm.id(),
217 params->hash(),
218 true,
219 public_usage_mask,
220 public_key);
221 if (status.IsError())
222 return status;
223
224 return CreateWebCryptoPrivateKey(private_pkey.Pass(),
225 algorithm.id(),
226 params->hash(),
227 extractable,
228 private_usage_mask,
229 private_key);
230 }
231
110 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey( 232 Status RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(
111 blink::WebCryptoKeyFormat format, 233 blink::WebCryptoKeyFormat format,
112 blink::WebCryptoKeyUsageMask usage_mask) const { 234 blink::WebCryptoKeyUsageMask usage_mask) const {
113 switch (format) { 235 switch (format) {
114 case blink::WebCryptoKeyFormatSpki: 236 case blink::WebCryptoKeyFormatSpki:
115 return CheckKeyCreationUsages(all_public_key_usages_, usage_mask); 237 return CheckKeyCreationUsages(all_public_key_usages_, usage_mask);
116 case blink::WebCryptoKeyFormatPkcs8: 238 case blink::WebCryptoKeyFormatPkcs8:
117 return CheckKeyCreationUsages(all_private_key_usages_, usage_mask); 239 return CheckKeyCreationUsages(all_private_key_usages_, usage_mask);
118 default: 240 default:
119 return Status::ErrorUnsupportedImportKeyFormat(); 241 return Status::ErrorUnsupportedImportKeyFormat();
(...skipping 18 matching lines...) Expand all
138 260
139 crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type 261 crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
140 p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL)); 262 p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
141 if (!p8inf.get()) 263 if (!p8inf.get())
142 return Status::DataError(); 264 return Status::DataError();
143 265
144 crypto::ScopedEVP_PKEY private_key(EVP_PKCS82PKEY(p8inf.get())); 266 crypto::ScopedEVP_PKEY private_key(EVP_PKCS82PKEY(p8inf.get()));
145 if (!private_key.get()) 267 if (!private_key.get())
146 return Status::DataError(); 268 return Status::DataError();
147 269
148 blink::WebCryptoKeyAlgorithm key_algorithm; 270 if (EVP_PKEY_id(private_key.get()) != EVP_PKEY_RSA)
149 Status status = ValidateKeyTypeAndCreateKeyAlgorithm( 271 return Status::DataError(); // Data did not define an RSA key.
150 algorithm, private_key.get(), &key_algorithm);
151 if (status.IsError())
152 return status;
153 272
154 // TODO(eroman): This is probably going to be the same as the input. 273 // TODO(eroman): Validate the algorithm OID against the webcrypto provided
155 std::vector<uint8_t> pkcs8_data; 274 // hash. http://crbug.com/389400
156 status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
157 if (status.IsError())
158 return status;
159 275
160 scoped_ptr<AsymKeyOpenSsl> key_handle( 276 return CreateWebCryptoPrivateKey(private_key.Pass(),
161 new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data))); 277 algorithm.id(),
162 278 algorithm.rsaHashedImportParams()->hash(),
163 *key = blink::WebCryptoKey::create(key_handle.release(), 279 extractable,
164 blink::WebCryptoKeyTypePrivate, 280 usage_mask,
165 extractable, 281 key);
166 key_algorithm,
167 usage_mask);
168 return Status::Success();
169 } 282 }
170 283
171 Status RsaHashedAlgorithm::ImportKeySpki( 284 Status RsaHashedAlgorithm::ImportKeySpki(
172 const CryptoData& key_data, 285 const CryptoData& key_data,
173 const blink::WebCryptoAlgorithm& algorithm, 286 const blink::WebCryptoAlgorithm& algorithm,
174 bool extractable, 287 bool extractable,
175 blink::WebCryptoKeyUsageMask usage_mask, 288 blink::WebCryptoKeyUsageMask usage_mask,
176 blink::WebCryptoKey* key) const { 289 blink::WebCryptoKey* key) const {
177 if (!key_data.byte_length()) 290 if (!key_data.byte_length())
178 return Status::ErrorImportEmptyKeyData(); 291 return Status::ErrorImportEmptyKeyData();
179 292
180 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); 293 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
181 294
182 crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()), 295 crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
183 key_data.byte_length())); 296 key_data.byte_length()));
184 if (!bio.get()) 297 if (!bio.get())
185 return Status::ErrorUnexpected(); 298 return Status::ErrorUnexpected();
186 299
187 crypto::ScopedEVP_PKEY public_key(d2i_PUBKEY_bio(bio.get(), NULL)); 300 crypto::ScopedEVP_PKEY public_key(d2i_PUBKEY_bio(bio.get(), NULL));
188 if (!public_key.get()) 301 if (!public_key.get())
189 return Status::DataError(); 302 return Status::DataError();
190 303
191 blink::WebCryptoKeyAlgorithm key_algorithm; 304 if (EVP_PKEY_id(public_key.get()) != EVP_PKEY_RSA)
192 Status status = ValidateKeyTypeAndCreateKeyAlgorithm( 305 return Status::DataError(); // Data did not define an RSA key.
193 algorithm, public_key.get(), &key_algorithm);
194 if (status.IsError())
195 return status;
196 306
197 // TODO(eroman): This is probably going to be the same as the input. 307 // TODO(eroman): Validate the algorithm OID against the webcrypto provided
198 std::vector<uint8_t> spki_data; 308 // hash. http://crbug.com/389400
199 status = ExportPKeySpki(public_key.get(), &spki_data);
200 if (status.IsError())
201 return status;
202 309
203 scoped_ptr<AsymKeyOpenSsl> key_handle( 310 return CreateWebCryptoPublicKey(public_key.Pass(),
204 new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data))); 311 algorithm.id(),
205 312 algorithm.rsaHashedImportParams()->hash(),
206 *key = blink::WebCryptoKey::create(key_handle.release(), 313 extractable,
207 blink::WebCryptoKeyTypePublic, 314 usage_mask,
208 extractable, 315 key);
209 key_algorithm,
210 usage_mask);
211 return Status::Success();
212 } 316 }
213 317
214 Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key, 318 Status RsaHashedAlgorithm::ExportKeyPkcs8(const blink::WebCryptoKey& key,
215 std::vector<uint8_t>* buffer) const { 319 std::vector<uint8_t>* buffer) const {
216 if (key.type() != blink::WebCryptoKeyTypePrivate) 320 if (key.type() != blink::WebCryptoKeyTypePrivate)
217 return Status::ErrorUnexpectedKeyType(); 321 return Status::ErrorUnexpectedKeyType();
218 *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data(); 322 *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
219 return Status::Success(); 323 return Status::Success();
220 } 324 }
221 325
222 Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key, 326 Status RsaHashedAlgorithm::ExportKeySpki(const blink::WebCryptoKey& key,
223 std::vector<uint8_t>* buffer) const { 327 std::vector<uint8_t>* buffer) const {
224 if (key.type() != blink::WebCryptoKeyTypePublic) 328 if (key.type() != blink::WebCryptoKeyTypePublic)
225 return Status::ErrorUnexpectedKeyType(); 329 return Status::ErrorUnexpectedKeyType();
226 *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data(); 330 *buffer = AsymKeyOpenSsl::Cast(key)->serialized_key_data();
227 return Status::Success(); 331 return Status::Success();
228 } 332 }
229 333
230 } // namespace webcrypto 334 } // namespace webcrypto
231 335
232 } // namespace content 336 } // namespace content
OLDNEW
« no previous file with comments | « content/child/webcrypto/openssl/rsa_key_openssl.h ('k') | content/child/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698