• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/algorithm_dispatch.h"
6 
7 #include "base/logging.h"
8 #include "content/child/webcrypto/algorithm_implementation.h"
9 #include "content/child/webcrypto/algorithm_registry.h"
10 #include "content/child/webcrypto/crypto_data.h"
11 #include "content/child/webcrypto/platform_crypto.h"
12 #include "content/child/webcrypto/status.h"
13 #include "content/child/webcrypto/webcrypto_util.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
15 
16 namespace content {
17 
18 namespace webcrypto {
19 
20 namespace {
21 
DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & data,std::vector<uint8_t> * buffer)22 Status DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm& algorithm,
23                                 const blink::WebCryptoKey& key,
24                                 const CryptoData& data,
25                                 std::vector<uint8_t>* buffer) {
26   if (algorithm.id() != key.algorithm().id())
27     return Status::ErrorUnexpected();
28 
29   const AlgorithmImplementation* impl = NULL;
30   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
31   if (status.IsError())
32     return status;
33 
34   return impl->Decrypt(algorithm, key, data, buffer);
35 }
36 
EncryptDontCheckUsage(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & data,std::vector<uint8_t> * buffer)37 Status EncryptDontCheckUsage(const blink::WebCryptoAlgorithm& algorithm,
38                              const blink::WebCryptoKey& key,
39                              const CryptoData& data,
40                              std::vector<uint8_t>* buffer) {
41   if (algorithm.id() != key.algorithm().id())
42     return Status::ErrorUnexpected();
43 
44   const AlgorithmImplementation* impl = NULL;
45   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
46   if (status.IsError())
47     return status;
48 
49   return impl->Encrypt(algorithm, key, data, buffer);
50 }
51 
ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,const blink::WebCryptoKey & key,std::vector<uint8_t> * buffer)52 Status ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format,
53                                         const blink::WebCryptoKey& key,
54                                         std::vector<uint8_t>* buffer) {
55   const AlgorithmImplementation* impl = NULL;
56   Status status = GetAlgorithmImplementation(key.algorithm().id(), &impl);
57   if (status.IsError())
58     return status;
59 
60   switch (format) {
61     case blink::WebCryptoKeyFormatRaw:
62       return impl->ExportKeyRaw(key, buffer);
63     case blink::WebCryptoKeyFormatSpki:
64       return impl->ExportKeySpki(key, buffer);
65     case blink::WebCryptoKeyFormatPkcs8:
66       return impl->ExportKeyPkcs8(key, buffer);
67     case blink::WebCryptoKeyFormatJwk:
68       return impl->ExportKeyJwk(key, buffer);
69     default:
70       return Status::ErrorUnsupported();
71   }
72 }
73 
74 }  // namespace
75 
Encrypt(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & data,std::vector<uint8_t> * buffer)76 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
77                const blink::WebCryptoKey& key,
78                const CryptoData& data,
79                std::vector<uint8_t>* buffer) {
80   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
81     return Status::ErrorUnexpected();
82   return EncryptDontCheckUsage(algorithm, key, data, buffer);
83 }
84 
Decrypt(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & data,std::vector<uint8_t> * buffer)85 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
86                const blink::WebCryptoKey& key,
87                const CryptoData& data,
88                std::vector<uint8_t>* buffer) {
89   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
90     return Status::ErrorUnexpected();
91   return DecryptDontCheckKeyUsage(algorithm, key, data, buffer);
92 }
93 
Digest(const blink::WebCryptoAlgorithm & algorithm,const CryptoData & data,std::vector<uint8_t> * buffer)94 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
95               const CryptoData& data,
96               std::vector<uint8_t>* buffer) {
97   const AlgorithmImplementation* impl = NULL;
98   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
99   if (status.IsError())
100     return status;
101 
102   return impl->Digest(algorithm, data, buffer);
103 }
104 
GenerateSecretKey(const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask usage_mask,blink::WebCryptoKey * key)105 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
106                          bool extractable,
107                          blink::WebCryptoKeyUsageMask usage_mask,
108                          blink::WebCryptoKey* key) {
109   const AlgorithmImplementation* impl = NULL;
110   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
111   if (status.IsError())
112     return status;
113 
114   status = impl->VerifyKeyUsagesBeforeGenerateKey(usage_mask);
115   if (status.IsError())
116     return status;
117 
118   return impl->GenerateSecretKey(algorithm, extractable, usage_mask, key);
119 }
120 
GenerateKeyPair(const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask combined_usage_mask,blink::WebCryptoKey * public_key,blink::WebCryptoKey * private_key)121 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
122                        bool extractable,
123                        blink::WebCryptoKeyUsageMask combined_usage_mask,
124                        blink::WebCryptoKey* public_key,
125                        blink::WebCryptoKey* private_key) {
126   const AlgorithmImplementation* impl = NULL;
127   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
128   if (status.IsError())
129     return status;
130 
131   blink::WebCryptoKeyUsageMask public_usage_mask;
132   blink::WebCryptoKeyUsageMask private_usage_mask;
133   status = impl->VerifyKeyUsagesBeforeGenerateKeyPair(
134       combined_usage_mask, &public_usage_mask, &private_usage_mask);
135   if (status.IsError())
136     return status;
137 
138   return impl->GenerateKeyPair(algorithm,
139                                extractable,
140                                public_usage_mask,
141                                private_usage_mask,
142                                public_key,
143                                private_key);
144 }
145 
146 // Note that this function may be called from the target Blink thread.
ImportKey(blink::WebCryptoKeyFormat format,const CryptoData & key_data,const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask usage_mask,blink::WebCryptoKey * key)147 Status ImportKey(blink::WebCryptoKeyFormat format,
148                  const CryptoData& key_data,
149                  const blink::WebCryptoAlgorithm& algorithm,
150                  bool extractable,
151                  blink::WebCryptoKeyUsageMask usage_mask,
152                  blink::WebCryptoKey* key) {
153   const AlgorithmImplementation* impl = NULL;
154   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
155   if (status.IsError())
156     return status;
157 
158   status = impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask);
159   if (status.IsError())
160     return status;
161 
162   switch (format) {
163     case blink::WebCryptoKeyFormatRaw:
164       return impl->ImportKeyRaw(
165           key_data, algorithm, extractable, usage_mask, key);
166     case blink::WebCryptoKeyFormatSpki:
167       return impl->ImportKeySpki(
168           key_data, algorithm, extractable, usage_mask, key);
169     case blink::WebCryptoKeyFormatPkcs8:
170       return impl->ImportKeyPkcs8(
171           key_data, algorithm, extractable, usage_mask, key);
172     case blink::WebCryptoKeyFormatJwk:
173       return impl->ImportKeyJwk(
174           key_data, algorithm, extractable, usage_mask, key);
175     default:
176       return Status::ErrorUnsupported();
177   }
178 }
179 
ExportKey(blink::WebCryptoKeyFormat format,const blink::WebCryptoKey & key,std::vector<uint8_t> * buffer)180 Status ExportKey(blink::WebCryptoKeyFormat format,
181                  const blink::WebCryptoKey& key,
182                  std::vector<uint8_t>* buffer) {
183   if (!key.extractable())
184     return Status::ErrorKeyNotExtractable();
185   return ExportKeyDontCheckExtractability(format, key, buffer);
186 }
187 
Sign(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & data,std::vector<uint8_t> * buffer)188 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
189             const blink::WebCryptoKey& key,
190             const CryptoData& data,
191             std::vector<uint8_t>* buffer) {
192   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
193     return Status::ErrorUnexpected();
194   if (algorithm.id() != key.algorithm().id())
195     return Status::ErrorUnexpected();
196 
197   const AlgorithmImplementation* impl = NULL;
198   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
199   if (status.IsError())
200     return status;
201 
202   return impl->Sign(algorithm, key, data, buffer);
203 }
204 
Verify(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & signature,const CryptoData & data,bool * signature_match)205 Status Verify(const blink::WebCryptoAlgorithm& algorithm,
206               const blink::WebCryptoKey& key,
207               const CryptoData& signature,
208               const CryptoData& data,
209               bool* signature_match) {
210   if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
211     return Status::ErrorUnexpected();
212   if (algorithm.id() != key.algorithm().id())
213     return Status::ErrorUnexpected();
214 
215   const AlgorithmImplementation* impl = NULL;
216   Status status = GetAlgorithmImplementation(algorithm.id(), &impl);
217   if (status.IsError())
218     return status;
219 
220   return impl->Verify(algorithm, key, signature, data, signature_match);
221 }
222 
WrapKey(blink::WebCryptoKeyFormat format,const blink::WebCryptoKey & key_to_wrap,const blink::WebCryptoKey & wrapping_key,const blink::WebCryptoAlgorithm & wrapping_algorithm,std::vector<uint8_t> * buffer)223 Status WrapKey(blink::WebCryptoKeyFormat format,
224                const blink::WebCryptoKey& key_to_wrap,
225                const blink::WebCryptoKey& wrapping_key,
226                const blink::WebCryptoAlgorithm& wrapping_algorithm,
227                std::vector<uint8_t>* buffer) {
228   if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageWrapKey))
229     return Status::ErrorUnexpected();
230 
231   std::vector<uint8_t> exported_data;
232   Status status = ExportKey(format, key_to_wrap, &exported_data);
233   if (status.IsError())
234     return status;
235   return EncryptDontCheckUsage(
236       wrapping_algorithm, wrapping_key, CryptoData(exported_data), buffer);
237 }
238 
UnwrapKey(blink::WebCryptoKeyFormat format,const CryptoData & wrapped_key_data,const blink::WebCryptoKey & wrapping_key,const blink::WebCryptoAlgorithm & wrapping_algorithm,const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask usage_mask,blink::WebCryptoKey * key)239 Status UnwrapKey(blink::WebCryptoKeyFormat format,
240                  const CryptoData& wrapped_key_data,
241                  const blink::WebCryptoKey& wrapping_key,
242                  const blink::WebCryptoAlgorithm& wrapping_algorithm,
243                  const blink::WebCryptoAlgorithm& algorithm,
244                  bool extractable,
245                  blink::WebCryptoKeyUsageMask usage_mask,
246                  blink::WebCryptoKey* key) {
247   if (!KeyUsageAllows(wrapping_key, blink::WebCryptoKeyUsageUnwrapKey))
248     return Status::ErrorUnexpected();
249   if (wrapping_algorithm.id() != wrapping_key.algorithm().id())
250     return Status::ErrorUnexpected();
251 
252   // Fail fast if the import is doomed to fail.
253   const AlgorithmImplementation* import_impl = NULL;
254   Status status = GetAlgorithmImplementation(algorithm.id(), &import_impl);
255   if (status.IsError())
256     return status;
257 
258   status = import_impl->VerifyKeyUsagesBeforeImportKey(format, usage_mask);
259   if (status.IsError())
260     return status;
261 
262   std::vector<uint8_t> buffer;
263   status = DecryptDontCheckKeyUsage(
264       wrapping_algorithm, wrapping_key, wrapped_key_data, &buffer);
265   if (status.IsError())
266     return status;
267 
268   // NOTE that returning the details of ImportKey() failures may leak
269   // information about the plaintext of the encrypted key (for instance the JWK
270   // key_ops). As long as the ImportKey error messages don't describe actual
271   // key bytes however this should be OK. For more discussion see
272   // http://crubg.com/372040
273   return ImportKey(
274       format, CryptoData(buffer), algorithm, extractable, usage_mask, key);
275 }
276 
CreateDigestor(blink::WebCryptoAlgorithmId algorithm)277 scoped_ptr<blink::WebCryptoDigestor> CreateDigestor(
278     blink::WebCryptoAlgorithmId algorithm) {
279   PlatformInit();
280   return CreatePlatformDigestor(algorithm);
281 }
282 
283 }  // namespace webcrypto
284 
285 }  // namespace content
286