Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / openssl / util_openssl.cc
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.
4
5 #include "content/child/webcrypto/openssl/util_openssl.h"
6
7 #include <openssl/evp.h>
8 #include <openssl/pkcs12.h>
9
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"
16
17 namespace content {
18
19 namespace webcrypto {
20
21 namespace {
22
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()));
27
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();
32
33   char* data = NULL;
34   long len = BIO_get_mem_data(bio.get(), &data);
35   if (!data || len < 0)
36     return Status::ErrorUnexpected();
37
38   buffer->assign(data, data + len);
39   return Status::Success();
40 }
41
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()));
46
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();
51
52   char* data = NULL;
53   long len = BIO_get_mem_data(bio.get(), &data);
54   if (!data || len < 0)
55     return Status::ErrorUnexpected();
56
57   buffer->assign(data, data + len);
58   return Status::Success();
59 }
60
61 }  // namespace
62
63 void PlatformInit() {
64   crypto::EnsureOpenSSLInit();
65 }
66
67 const EVP_MD* GetDigest(blink::WebCryptoAlgorithmId id) {
68   switch (id) {
69     case blink::WebCryptoAlgorithmIdSha1:
70       return EVP_sha1();
71     case blink::WebCryptoAlgorithmIdSha256:
72       return EVP_sha256();
73     case blink::WebCryptoAlgorithmIdSha384:
74       return EVP_sha384();
75     case blink::WebCryptoAlgorithmIdSha512:
76       return EVP_sha512();
77     default:
78       return NULL;
79   }
80 }
81
82 Status AeadEncryptDecrypt(EncryptOrDecrypt mode,
83                           const std::vector<uint8_t>& raw_key,
84                           const CryptoData& data,
85                           unsigned int tag_length_bytes,
86                           const CryptoData& iv,
87                           const CryptoData& additional_data,
88                           const EVP_AEAD* aead_alg,
89                           std::vector<uint8_t>* buffer) {
90   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
91   EVP_AEAD_CTX ctx;
92
93   if (!aead_alg)
94     return Status::ErrorUnexpected();
95
96   if (!EVP_AEAD_CTX_init(&ctx,
97                          aead_alg,
98                          vector_as_array(&raw_key),
99                          raw_key.size(),
100                          tag_length_bytes,
101                          NULL)) {
102     return Status::OperationError();
103   }
104
105   crypto::ScopedOpenSSL<EVP_AEAD_CTX, EVP_AEAD_CTX_cleanup>::Type ctx_cleanup(
106       &ctx);
107
108   size_t len;
109   int ok;
110
111   if (mode == DECRYPT) {
112     if (data.byte_length() < tag_length_bytes)
113       return Status::ErrorDataTooSmall();
114
115     buffer->resize(data.byte_length() - tag_length_bytes);
116
117     ok = EVP_AEAD_CTX_open(&ctx,
118                            vector_as_array(buffer),
119                            &len,
120                            buffer->size(),
121                            iv.bytes(),
122                            iv.byte_length(),
123                            data.bytes(),
124                            data.byte_length(),
125                            additional_data.bytes(),
126                            additional_data.byte_length());
127   } else {
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));
131
132     ok = EVP_AEAD_CTX_seal(&ctx,
133                            vector_as_array(buffer),
134                            &len,
135                            buffer->size(),
136                            iv.bytes(),
137                            iv.byte_length(),
138                            data.bytes(),
139                            data.byte_length(),
140                            additional_data.bytes(),
141                            additional_data.byte_length());
142   }
143
144   if (!ok)
145     return Status::OperationError();
146   buffer->resize(len);
147   return Status::Success();
148 }
149
150 Status CreateWebCryptoPublicKey(crypto::ScopedEVP_PKEY public_key,
151                                 const blink::WebCryptoKeyAlgorithm& algorithm,
152                                 bool extractable,
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())
160     return status;
161
162   *key = blink::WebCryptoKey::create(
163       new AsymKeyOpenSsl(public_key.Pass(), CryptoData(spki_data)),
164       blink::WebCryptoKeyTypePublic, extractable, algorithm, usages);
165   return Status::Success();
166 }
167
168 Status CreateWebCryptoPrivateKey(crypto::ScopedEVP_PKEY private_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> pkcs8_data;
176   Status status = ExportPKeyPkcs8(private_key.get(), &pkcs8_data);
177   if (status.IsError())
178     return status;
179
180   *key = blink::WebCryptoKey::create(
181       new AsymKeyOpenSsl(private_key.Pass(), CryptoData(pkcs8_data)),
182       blink::WebCryptoKeyTypePrivate, extractable, algorithm, usages);
183   return Status::Success();
184 }
185
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();
191
192   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
193
194   crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
195                                         key_data.byte_length()));
196   if (!bio.get())
197     return Status::ErrorUnexpected();
198
199   pkey->reset(d2i_PUBKEY_bio(bio.get(), NULL));
200   if (!pkey->get())
201     return Status::DataError();
202
203   if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
204     return Status::DataError();  // Data did not define expected key type.
205
206   return Status::Success();
207 }
208
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();
214
215   crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
216
217   crypto::ScopedBIO bio(BIO_new_mem_buf(const_cast<uint8_t*>(key_data.bytes()),
218                                         key_data.byte_length()));
219   if (!bio.get())
220     return Status::ErrorUnexpected();
221
222   crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
223       p8inf(d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
224   if (!p8inf.get())
225     return Status::DataError();
226
227   pkey->reset(EVP_PKCS82PKEY(p8inf.get()));
228   if (!pkey->get())
229     return Status::DataError();
230
231   if (EVP_PKEY_id(pkey->get()) != expected_pkey_id)
232     return Status::DataError();  // Data did not define expected key type.
233
234   return Status::Success();
235 }
236
237 BIGNUM* CreateBIGNUM(const std::string& n) {
238   return BN_bin2bn(reinterpret_cast<const uint8_t*>(n.data()), n.size(), NULL);
239 }
240
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));
244   return v;
245 }
246
247 }  // namespace webcrypto
248
249 }  // namespace content