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/algorithms/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/algorithm_implementations.h"
13 #include "components/webcrypto/crypto_data.h"
14 #include "components/webcrypto/generate_key_result.h"
15 #include "components/webcrypto/key.h"
16 #include "components/webcrypto/status.h"
17 #include "components/webcrypto/webcrypto_util.h"
18 #include "crypto/openssl_util.h"
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();
35 long len
= BIO_get_mem_data(bio
.get(), &data
);
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();
54 long len
= BIO_get_mem_data(bio
.get(), &data
);
56 return Status::ErrorUnexpected();
58 buffer
->assign(data
, data
+ len
);
59 return Status::Success();
64 const EVP_MD
* GetDigest(blink::WebCryptoAlgorithmId id
) {
66 case blink::WebCryptoAlgorithmIdSha1
:
68 case blink::WebCryptoAlgorithmIdSha256
:
70 case blink::WebCryptoAlgorithmIdSha384
:
72 case blink::WebCryptoAlgorithmIdSha512
:
79 Status
AeadEncryptDecrypt(EncryptOrDecrypt mode
,
80 const std::vector
<uint8_t>& raw_key
,
81 const CryptoData
& data
,
82 unsigned int tag_length_bytes
,
84 const CryptoData
& additional_data
,
85 const EVP_AEAD
* aead_alg
,
86 std::vector
<uint8_t>* buffer
) {
87 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
91 return Status::ErrorUnexpected();
93 if (!EVP_AEAD_CTX_init(&ctx
, aead_alg
, vector_as_array(&raw_key
),
94 raw_key
.size(), tag_length_bytes
, NULL
)) {
95 return Status::OperationError();
98 crypto::ScopedOpenSSL
<EVP_AEAD_CTX
, EVP_AEAD_CTX_cleanup
> ctx_cleanup(&ctx
);
103 if (mode
== DECRYPT
) {
104 if (data
.byte_length() < tag_length_bytes
)
105 return Status::ErrorDataTooSmall();
107 buffer
->resize(data
.byte_length() - tag_length_bytes
);
109 ok
= EVP_AEAD_CTX_open(&ctx
, vector_as_array(buffer
), &len
, buffer
->size(),
110 iv
.bytes(), iv
.byte_length(), data
.bytes(),
111 data
.byte_length(), additional_data
.bytes(),
112 additional_data
.byte_length());
114 // No need to check for unsigned integer overflow here (seal fails if
115 // the output buffer is too small).
116 buffer
->resize(data
.byte_length() + EVP_AEAD_max_overhead(aead_alg
));
118 ok
= EVP_AEAD_CTX_seal(&ctx
, vector_as_array(buffer
), &len
, buffer
->size(),
119 iv
.bytes(), iv
.byte_length(), data
.bytes(),
120 data
.byte_length(), additional_data
.bytes(),
121 additional_data
.byte_length());
125 return Status::OperationError();
127 return Status::Success();
130 Status
CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key
,
131 const blink::WebCryptoKeyAlgorithm
& algorithm
,
133 blink::WebCryptoKeyUsageMask usages
,
134 blink::WebCryptoKey
* key
) {
135 // Serialize the key at creation time so that if structured cloning is
136 // requested it can be done synchronously from the Blink thread.
137 std::vector
<uint8_t> spki_data
;
138 Status status
= ExportPKeySpki(public_key
.get(), &spki_data
);
139 if (status
.IsError())
142 *key
= blink::WebCryptoKey::create(
143 CreateAsymmetricKeyHandle(public_key
.Pass(), spki_data
),
144 blink::WebCryptoKeyTypePublic
, extractable
, algorithm
, usages
);
145 return Status::Success();
148 Status
CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_key
,
149 const blink::WebCryptoKeyAlgorithm
& algorithm
,
151 blink::WebCryptoKeyUsageMask usages
,
152 blink::WebCryptoKey
* key
) {
153 // Serialize the key at creation time so that if structured cloning is
154 // requested it can be done synchronously from the Blink thread.
155 std::vector
<uint8_t> pkcs8_data
;
156 Status status
= ExportPKeyPkcs8(private_key
.get(), &pkcs8_data
);
157 if (status
.IsError())
160 *key
= blink::WebCryptoKey::create(
161 CreateAsymmetricKeyHandle(private_key
.Pass(), pkcs8_data
),
162 blink::WebCryptoKeyTypePrivate
, extractable
, algorithm
, usages
);
163 return Status::Success();
166 Status
ImportUnverifiedPkeyFromSpki(const CryptoData
& key_data
,
167 int expected_pkey_id
,
168 crypto::ScopedEVP_PKEY
* pkey
) {
169 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
171 const uint8_t* ptr
= key_data
.bytes();
172 pkey
->reset(d2i_PUBKEY(nullptr, &ptr
, key_data
.byte_length()));
173 if (!pkey
->get() || ptr
!= key_data
.bytes() + key_data
.byte_length())
174 return Status::DataError();
176 if (EVP_PKEY_id(pkey
->get()) != expected_pkey_id
)
177 return Status::DataError(); // Data did not define expected key type.
179 return Status::Success();
182 Status
ImportUnverifiedPkeyFromPkcs8(const CryptoData
& key_data
,
183 int expected_pkey_id
,
184 crypto::ScopedEVP_PKEY
* pkey
) {
185 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
187 const uint8_t* ptr
= key_data
.bytes();
188 crypto::ScopedOpenSSL
<PKCS8_PRIV_KEY_INFO
, PKCS8_PRIV_KEY_INFO_free
> p8inf(
189 d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr
, key_data
.byte_length()));
190 if (!p8inf
.get() || ptr
!= key_data
.bytes() + key_data
.byte_length())
191 return Status::DataError();
193 pkey
->reset(EVP_PKCS82PKEY(p8inf
.get()));
195 return Status::DataError();
197 if (EVP_PKEY_id(pkey
->get()) != expected_pkey_id
)
198 return Status::DataError(); // Data did not define expected key type.
200 return Status::Success();
203 BIGNUM
* CreateBIGNUM(const std::string
& n
) {
204 return BN_bin2bn(reinterpret_cast<const uint8_t*>(n
.data()), n
.size(), NULL
);
207 std::vector
<uint8_t> BIGNUMToVector(const BIGNUM
* n
) {
208 std::vector
<uint8_t> v(BN_num_bytes(n
));
209 BN_bn2bin(n
, vector_as_array(&v
));
213 } // namespace webcrypto