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
3 // found in the LICENSE file.
5 #include "content/child/webcrypto/openssl/util_openssl.h"
7 #include <openssl/evp.h>
8 #include <openssl/pkcs12.h>
10 #include "base/stl_util.h"
11 #include "content/child/webcrypto/crypto_data.h"
12 #include "content/child/webcrypto/openssl/key_openssl.h"
13 #include "content/child/webcrypto/platform_crypto.h"
14 #include "content/child/webcrypto/status.h"
15 #include "crypto/openssl_util.h"
23 // Exports an EVP_PKEY public key to the SPKI format.
24 Status ExportPKeySpki(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
25 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
26 crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
28 // TODO(eroman): Use the OID specified by webcrypto spec.
29 // http://crbug.com/373545
30 if (!i2d_PUBKEY_bio(bio.get(), key))
31 return Status::ErrorUnexpected();
34 long len = BIO_get_mem_data(bio.get(), &data);
36 return Status::ErrorUnexpected();
38 buffer->assign(data, data + len);
39 return Status::Success();
42 // Exports an EVP_PKEY private key to the PKCS8 format.
43 Status ExportPKeyPkcs8(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
44 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
45 crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
47 // TODO(eroman): Use the OID specified by webcrypto spec.
48 // http://crbug.com/373545
49 if (!i2d_PKCS8PrivateKeyInfo_bio(bio.get(), key))
50 return Status::ErrorUnexpected();
53 long len = BIO_get_mem_data(bio.get(), &data);
55 return Status::ErrorUnexpected();
57 buffer->assign(data, data + len);
58 return Status::Success();
64 crypto::EnsureOpenSSLInit();
67 const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
69 case blink::WebCryptoAlgorithmIdSha1:
71 case blink::WebCryptoAlgorithmIdSha256:
73 case blink::WebCryptoAlgorithmIdSha384:
75 case blink::WebCryptoAlgorithmIdSha512:
82 Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
83 const std::vector<uint8_t>& raw_key,
84 const CryptoData& data,
85 unsigned int tag_length_bytes,
87 const CryptoData& additional_data,
88 const EVP_AEAD* aead_alg,
89 std::vector<uint8_t>* buffer) {
90 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
94 return Status::ErrorUnexpected();
96 if (!EVP_AEAD_CTX_init(&ctx,
98 vector_as_array(&raw_key),
102 return Status::OperationError();
105 crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup>::Type ctx_cleanup(
111 if (mode == DECRYPT) {
112 if (data.byte_length() < tag_length_bytes)
113 return Status::ErrorDataTooSmall();
115 buffer->resize(data.byte_length() - tag_length_bytes);
117 ok = EVP_AEAD_CTX_open(&ctx,
118 vector_as_array(buffer),
125 additional_data.bytes(),
126 additional_data.byte_length());
128 // No need to check for unsigned integer overflow here (seal fails if
129 // the output buffer is too small).
130 buffer->resize(data.byte_length() + EVP_AEAD_max_overhead(aead_alg));
132 ok = EVP_AEAD_CTX_seal(&ctx,
133 vector_as_array(buffer),
140 additional_data.bytes(),
141 additional_data.byte_length());
145 return Status::OperationError();
147 return Status::Success();
150 Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
151 const blink::WebCryptoKeyAlgorithm& algorithm,
153 blink::WebCryptoKeyUsageMask usages,
154 blink::WebCryptoKey* key) {
155 // Serialize the key at creation time so that if structured cloning is
156 // requested it can be done synchronously from the Blink thread.
157 std::vector<uint8_t> spki_data;
158 Status status = ExportPKeySpki(public_key.get(), &spki_data);
159 if (status.IsError())
162 *key = blink::WebCryptoKey::create(
163 new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
164 blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
165 return Status::Success();
168 Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
169 const blink::WebCryptoKeyAlgorithm& algorithm,
171 blink::WebCryptoKeyUsageMask usages,
172 blink::WebCryptoKey* key) {
173 // Serialize the key at creation time so that if structured cloning is
174 // requested it can be done synchronously from the Blink thread.
175 std::vector<uint8_t> pkcs8_data;
176 Status status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
177 if (status.IsError())
180 *key = blink::WebCryptoKey::create(
181 new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
182 blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
183 return Status::Success();
186 Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
187 int expected_pkey_id,
188 crypto::ScopedEVP_PKEY* pkey) {
189 if (!key_data.byte_length())
190 return Status::ErrorImportEmptyKeyData();
192 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
194 crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
195 key_data.byte_length()));
197 return Status::ErrorUnexpected();
199 pkey->reset(d2i_PUBKEY_bio(bio.get(), NULL));
201 return Status::DataError();
203 if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
204 return Status::DataError(); // Data did not define expected key type.
206 return Status::Success();
209 Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
210 int expected_pkey_id,
211 crypto::ScopedEVP_PKEY* pkey) {
212 if (!key_data.byte_length())
213 return Status::ErrorImportEmptyKeyData();
215 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
217 crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
218 key_data.byte_length()));
220 return Status::ErrorUnexpected();
222 crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
223 p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
225 return Status::DataError();
227 pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
229 return Status::DataError();
231 if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
232 return Status::DataError(); // Data did not define expected key type.
234 return Status::Success();
237 BIGNUM* CreateBIGNUM(const std::string& n) {
238 return BN_bin2bn(reinterpret_cast<const uint8_t*>(n.data()), n.size(), NULL);
241 std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n) {
242 std::vector<uint8_t> v(BN_num_bytes(n));
243 BN_bn2bin(n, vector_as_array(&v));
247 } // namespace webcrypto
249 } // namespace content