OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |