Roll src/third_party/WebKit f36d5e0:68b67cd (svn 193299:193303)
[chromium-blink-merge.git] / content / child / webcrypto / openssl / util_openssl.cc
blobb03c632068e750e7a77cd94d5325382b8fe5964c
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>
9 #include <openssl/rand.h>
11 #include "base/stl_util.h"
12 #include "content/child/webcrypto/crypto_data.h"
13 #include "content/child/webcrypto/generate_key_result.h"
14 #include "content/child/webcrypto/openssl/key_openssl.h"
15 #include "content/child/webcrypto/platform_crypto.h"
16 #include "content/child/webcrypto/status.h"
17 #include "content/child/webcrypto/webcrypto_util.h"
18 #include "crypto/openssl_util.h"
20 namespace content {
22 namespace webcrypto {
24 namespace {
26 // Exports an EVP_PKEY public key to the SPKI format.
27 Status ExportPKeySpki(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
28 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
29 crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
31 // TODO(eroman): Use the OID specified by webcrypto spec.
32 // http://crbug.com/373545
33 if (!i2d_PUBKEY_bio(bio.get(), key))
34 return Status::ErrorUnexpected();
36 char* data = NULL;
37 long len = BIO_get_mem_data(bio.get(), &data);
38 if (!data || len < 0)
39 return Status::ErrorUnexpected();
41 buffer->assign(data, data + len);
42 return Status::Success();
45 // Exports an EVP_PKEY private key to the PKCS8 format.
46 Status ExportPKeyPkcs8(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
47 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
48 crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
50 // TODO(eroman): Use the OID specified by webcrypto spec.
51 // http://crbug.com/373545
52 if (!i2d_PKCS8PrivateKeyInfo_bio(bio.get(), key))
53 return Status::ErrorUnexpected();
55 char* data = NULL;
56 long len = BIO_get_mem_data(bio.get(), &data);
57 if (!data || len < 0)
58 return Status::ErrorUnexpected();
60 buffer->assign(data, data + len);
61 return Status::Success();
64 } // namespace
66 void PlatformInit() {
67 crypto::EnsureOpenSSLInit();
70 const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
71 switch (id) {
72 case blink::WebCryptoAlgorithmIdSha1:
73 return EVP_sha1();
74 case blink::WebCryptoAlgorithmIdSha256:
75 return EVP_sha256();
76 case blink::WebCryptoAlgorithmIdSha384:
77 return EVP_sha384();
78 case blink::WebCryptoAlgorithmIdSha512:
79 return EVP_sha512();
80 default:
81 return NULL;
85 Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
86 const std::vector<uint8_t>& raw_key,
87 const CryptoData& data,
88 unsigned int tag_length_bytes,
89 const CryptoData& iv,
90 const CryptoData& additional_data,
91 const EVP_AEAD* aead_alg,
92 std::vector<uint8_t>* buffer) {
93 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
94 EVP_AEAD_CTX ctx;
96 if (!aead_alg)
97 return Status::ErrorUnexpected();
99 if (!EVP_AEAD_CTX_init(&ctx, aead_alg, vector_as_array(&raw_key),
100 raw_key.size(), tag_length_bytes, NULL)) {
101 return Status::OperationError();
104 crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup> ctx_cleanup(&ctx);
106 size_t len;
107 int ok;
109 if (mode == DECRYPT) {
110 if (data.byte_length() < tag_length_bytes)
111 return Status::ErrorDataTooSmall();
113 buffer->resize(data.byte_length() - tag_length_bytes);
115 ok = EVP_AEAD_CTX_open(&ctx, vector_as_array(buffer), &len, buffer->size(),
116 iv.bytes(), iv.byte_length(), data.bytes(),
117 data.byte_length(), additional_data.bytes(),
118 additional_data.byte_length());
119 } else {
120 // No need to check for unsigned integer overflow here (seal fails if
121 // the output buffer is too small).
122 buffer->resize(data.byte_length() + EVP_AEAD_max_overhead(aead_alg));
124 ok = EVP_AEAD_CTX_seal(&ctx, vector_as_array(buffer), &len, buffer->size(),
125 iv.bytes(), iv.byte_length(), data.bytes(),
126 data.byte_length(), additional_data.bytes(),
127 additional_data.byte_length());
130 if (!ok)
131 return Status::OperationError();
132 buffer->resize(len);
133 return Status::Success();
136 Status GenerateWebCryptoSecretKey(const blink::WebCryptoKeyAlgorithm& algorithm,
137 bool extractable,
138 blink::WebCryptoKeyUsageMask usages,
139 unsigned int keylen_bits,
140 GenerateKeyResult* result) {
141 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
143 unsigned int keylen_bytes = NumBitsToBytes(keylen_bits);
144 std::vector<unsigned char> random_bytes(keylen_bytes, 0);
146 if (keylen_bytes > 0) {
147 if (!(RAND_bytes(&random_bytes[0], keylen_bytes)))
148 return Status::OperationError();
149 TruncateToBitLength(keylen_bits, &random_bytes);
152 result->AssignSecretKey(blink::WebCryptoKey::create(
153 new SymKeyOpenSsl(CryptoData(random_bytes)),
154 blink::WebCryptoKeyTypeSecret, extractable, algorithm, usages));
156 return Status::Success();
159 Status CreateWebCryptoSecretKey(const CryptoData& key_data,
160 const blink::WebCryptoKeyAlgorithm& algorithm,
161 bool extractable,
162 blink::WebCryptoKeyUsageMask usages,
163 blink::WebCryptoKey* key) {
164 *key = blink::WebCryptoKey::create(new SymKeyOpenSsl(key_data),
165 blink::WebCryptoKeyTypeSecret, extractable,
166 algorithm, usages);
167 return Status::Success();
170 Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
171 const blink::WebCryptoKeyAlgorithm& algorithm,
172 bool extractable,
173 blink::WebCryptoKeyUsageMask usages,
174 blink::WebCryptoKey* key) {
175 // Serialize the key at creation time so that if structured cloning is
176 // requested it can be done synchronously from the Blink thread.
177 std::vector<uint8_t> spki_data;
178 Status status = ExportPKeySpki(public_key.get(), &spki_data);
179 if (status.IsError())
180 return status;
182 *key = blink::WebCryptoKey::create(
183 new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
184 blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
185 return Status::Success();
188 Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
189 const blink::WebCryptoKeyAlgorithm& algorithm,
190 bool extractable,
191 blink::WebCryptoKeyUsageMask usages,
192 blink::WebCryptoKey* key) {
193 // Serialize the key at creation time so that if structured cloning is
194 // requested it can be done synchronously from the Blink thread.
195 std::vector<uint8_t> pkcs8_data;
196 Status status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
197 if (status.IsError())
198 return status;
200 *key = blink::WebCryptoKey::create(
201 new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
202 blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
203 return Status::Success();
206 Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
207 int expected_pkey_id,
208 crypto::ScopedEVP_PKEY* pkey) {
209 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
211 const uint8_t* ptr = key_data.bytes();
212 pkey->reset(d2i_PUBKEY(nullptr, &ptr, key_data.byte_length()));
213 if (!pkey->get() || ptr != key_data.bytes() + key_data.byte_length())
214 return Status::DataError();
216 if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
217 return Status::DataError(); // Data did not define expected key type.
219 return Status::Success();
222 Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
223 int expected_pkey_id,
224 crypto::ScopedEVP_PKEY* pkey) {
225 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
227 const uint8_t* ptr = key_data.bytes();
228 crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8inf(
229 d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, key_data.byte_length()));
230 if (!p8inf.get() || ptr != key_data.bytes() + key_data.byte_length())
231 return Status::DataError();
233 pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
234 if (!pkey->get())
235 return Status::DataError();
237 if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
238 return Status::DataError(); // Data did not define expected key type.
240 return Status::Success();
243 BIGNUM* CreateBIGNUM(const std::string& n) {
244 return BN_bin2bn(reinterpret_cast<const uint8_t*>(n.data()), n.size(), NULL);
247 std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n) {
248 std::vector<uint8_t> v(BN_num_bytes(n));
249 BN_bn2bin(n, vector_as_array(&v));
250 return v;
253 } // namespace webcrypto
255 } // namespace content