Vectorize website settings icons in omnibox
[chromium-blink-merge.git] / components / webcrypto / openssl / util_openssl.cc
blobb6ada7007e3fc208c748fc2ec1de093f55496704
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 "components/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 "components/webcrypto/crypto_data.h"
13 #include "components/webcrypto/generate_key_result.h"
14 #include "components/webcrypto/openssl/key_openssl.h"
15 #include "components/webcrypto/platform_crypto.h"
16 #include "components/webcrypto/status.h"
17 #include "components/webcrypto/webcrypto_util.h"
18 #include "crypto/openssl_util.h"
20 namespace webcrypto {
22 namespace {
24 // Exports an EVP_PKEY public key to the SPKI format.
25 Status ExportPKeySpki(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
26 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
27 crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
29 // TODO(eroman): Use the OID specified by webcrypto spec.
30 // http://crbug.com/373545
31 if (!i2d_PUBKEY_bio(bio.get(), key))
32 return Status::ErrorUnexpected();
34 char* data = NULL;
35 long len = BIO_get_mem_data(bio.get(), &data);
36 if (!data || len < 0)
37 return Status::ErrorUnexpected();
39 buffer->assign(data, data + len);
40 return Status::Success();
43 // Exports an EVP_PKEY private key to the PKCS8 format.
44 Status ExportPKeyPkcs8(EVP_PKEY* key, std::vector<uint8_t>* buffer) {
45 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
46 crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
48 // TODO(eroman): Use the OID specified by webcrypto spec.
49 // http://crbug.com/373545
50 if (!i2d_PKCS8PrivateKeyInfo_bio(bio.get(), key))
51 return Status::ErrorUnexpected();
53 char* data = NULL;
54 long len = BIO_get_mem_data(bio.get(), &data);
55 if (!data || len < 0)
56 return Status::ErrorUnexpected();
58 buffer->assign(data, data + len);
59 return Status::Success();
62 } // namespace
64 void PlatformInit() {
65 crypto::EnsureOpenSSLInit();
68 const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
69 switch (id) {
70 case blink::WebCryptoAlgorithmIdSha1:
71 return EVP_sha1();
72 case blink::WebCryptoAlgorithmIdSha256:
73 return EVP_sha256();
74 case blink::WebCryptoAlgorithmIdSha384:
75 return EVP_sha384();
76 case blink::WebCryptoAlgorithmIdSha512:
77 return EVP_sha512();
78 default:
79 return NULL;
83 Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
84 const std::vector<uint8_t>& raw_key,
85 const CryptoData& data,
86 unsigned int tag_length_bytes,
87 const CryptoData& iv,
88 const CryptoData& additional_data,
89 const EVP_AEAD* aead_alg,
90 std::vector<uint8_t>* buffer) {
91 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
92 EVP_AEAD_CTX ctx;
94 if (!aead_alg)
95 return Status::ErrorUnexpected();
97 if (!EVP_AEAD_CTX_init(&ctx, aead_alg, vector_as_array(&raw_key),
98 raw_key.size(), tag_length_bytes, NULL)) {
99 return Status::OperationError();
102 crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup> ctx_cleanup(&ctx);
104 size_t len;
105 int ok;
107 if (mode == DECRYPT) {
108 if (data.byte_length() < tag_length_bytes)
109 return Status::ErrorDataTooSmall();
111 buffer->resize(data.byte_length() - tag_length_bytes);
113 ok = EVP_AEAD_CTX_open(&ctx, vector_as_array(buffer), &len, buffer->size(),
114 iv.bytes(), iv.byte_length(), data.bytes(),
115 data.byte_length(), additional_data.bytes(),
116 additional_data.byte_length());
117 } else {
118 // No need to check for unsigned integer overflow here (seal fails if
119 // the output buffer is too small).
120 buffer->resize(data.byte_length() + EVP_AEAD_max_overhead(aead_alg));
122 ok = EVP_AEAD_CTX_seal(&ctx, vector_as_array(buffer), &len, buffer->size(),
123 iv.bytes(), iv.byte_length(), data.bytes(),
124 data.byte_length(), additional_data.bytes(),
125 additional_data.byte_length());
128 if (!ok)
129 return Status::OperationError();
130 buffer->resize(len);
131 return Status::Success();
134 Status GenerateWebCryptoSecretKey(const blink::WebCryptoKeyAlgorithm& algorithm,
135 bool extractable,
136 blink::WebCryptoKeyUsageMask usages,
137 unsigned int keylen_bits,
138 GenerateKeyResult* result) {
139 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
141 unsigned int keylen_bytes = NumBitsToBytes(keylen_bits);
142 std::vector<unsigned char> random_bytes(keylen_bytes, 0);
144 if (keylen_bytes > 0) {
145 if (!(RAND_bytes(&random_bytes[0], keylen_bytes)))
146 return Status::OperationError();
147 TruncateToBitLength(keylen_bits, &random_bytes);
150 result->AssignSecretKey(blink::WebCryptoKey::create(
151 new SymKeyOpenSsl(CryptoData(random_bytes)),
152 blink::WebCryptoKeyTypeSecret, extractable, algorithm, usages));
154 return Status::Success();
157 Status CreateWebCryptoSecretKey(const CryptoData& key_data,
158 const blink::WebCryptoKeyAlgorithm& algorithm,
159 bool extractable,
160 blink::WebCryptoKeyUsageMask usages,
161 blink::WebCryptoKey* key) {
162 *key = blink::WebCryptoKey::create(new SymKeyOpenSsl(key_data),
163 blink::WebCryptoKeyTypeSecret, extractable,
164 algorithm, usages);
165 return Status::Success();
168 Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
169 const blink::WebCryptoKeyAlgorithm& algorithm,
170 bool extractable,
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> spki_data;
176 Status status = ExportPKeySpki(public_key.get(), &spki_data);
177 if (status.IsError())
178 return status;
180 *key = blink::WebCryptoKey::create(
181 new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
182 blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
183 return Status::Success();
186 Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key,
187 const blink::WebCryptoKeyAlgorithm& algorithm,
188 bool extractable,
189 blink::WebCryptoKeyUsageMask usages,
190 blink::WebCryptoKey* key) {
191 // Serialize the key at creation time so that if structured cloning is
192 // requested it can be done synchronously from the Blink thread.
193 std::vector<uint8_t> pkcs8_data;
194 Status status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
195 if (status.IsError())
196 return status;
198 *key = blink::WebCryptoKey::create(
199 new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
200 blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
201 return Status::Success();
204 Status ImportUnverifiedPkeyFromSpki(const CryptoData& key_data,
205 int expected_pkey_id,
206 crypto::ScopedEVP_PKEY* pkey) {
207 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
209 const uint8_t* ptr = key_data.bytes();
210 pkey->reset(d2i_PUBKEY(nullptr, &ptr, key_data.byte_length()));
211 if (!pkey->get() || ptr != key_data.bytes() + key_data.byte_length())
212 return Status::DataError();
214 if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
215 return Status::DataError(); // Data did not define expected key type.
217 return Status::Success();
220 Status ImportUnverifiedPkeyFromPkcs8(const CryptoData& key_data,
221 int expected_pkey_id,
222 crypto::ScopedEVP_PKEY* pkey) {
223 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
225 const uint8_t* ptr = key_data.bytes();
226 crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8inf(
227 d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, key_data.byte_length()));
228 if (!p8inf.get() || ptr != key_data.bytes() + key_data.byte_length())
229 return Status::DataError();
231 pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
232 if (!pkey->get())
233 return Status::DataError();
235 if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
236 return Status::DataError(); // Data did not define expected key type.
238 return Status::Success();
241 BIGNUM* CreateBIGNUM(const std::string& n) {
242 return BN_bin2bn(reinterpret_cast<const uint8_t*>(n.data()), n.size(), NULL);
245 std::vector<uint8_t> BIGNUMToVector(const BIGNUM* n) {
246 std::vector<uint8_t> v(BN_num_bytes(n));
247 BN_bn2bin(n, vector_as_array(&v));
248 return v;
251 } // namespace webcrypto