Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / nss / rsa_oaep_nss.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 <cryptohi.h>
6 #include <keyhi.h>
7 #include <pk11pub.h>
8 #include <secerr.h>
9 #include <sechash.h>
10
11 #include "base/stl_util.h"
12 #include "content/child/webcrypto/crypto_data.h"
13 #include "content/child/webcrypto/nss/key_nss.h"
14 #include "content/child/webcrypto/nss/rsa_key_nss.h"
15 #include "content/child/webcrypto/nss/util_nss.h"
16 #include "content/child/webcrypto/status.h"
17 #include "content/child/webcrypto/webcrypto_util.h"
18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
19 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
20
21 namespace content {
22
23 namespace webcrypto {
24
25 namespace {
26
27 Status NssSupportsRsaOaep() {
28   if (NssRuntimeSupport::Get()->IsRsaOaepSupported())
29     return Status::Success();
30   return Status::ErrorUnsupported(
31       "NSS version doesn't support RSA-OAEP. Try using version 3.16.2 or "
32       "later");
33 }
34
35 CK_MECHANISM_TYPE WebCryptoHashToMGFMechanism(
36     const blink::WebCryptoAlgorithm& algorithm) {
37   switch (algorithm.id()) {
38     case blink::WebCryptoAlgorithmIdSha1:
39       return CKG_MGF1_SHA1;
40     case blink::WebCryptoAlgorithmIdSha256:
41       return CKG_MGF1_SHA256;
42     case blink::WebCryptoAlgorithmIdSha384:
43       return CKG_MGF1_SHA384;
44     case blink::WebCryptoAlgorithmIdSha512:
45       return CKG_MGF1_SHA512;
46     default:
47       return CKM_INVALID_MECHANISM;
48   }
49 }
50
51 CK_MECHANISM_TYPE WebCryptoHashToDigestMechanism(
52     const blink::WebCryptoAlgorithm& algorithm) {
53   switch (algorithm.id()) {
54     case blink::WebCryptoAlgorithmIdSha1:
55       return CKM_SHA_1;
56     case blink::WebCryptoAlgorithmIdSha256:
57       return CKM_SHA256;
58     case blink::WebCryptoAlgorithmIdSha384:
59       return CKM_SHA384;
60     case blink::WebCryptoAlgorithmIdSha512:
61       return CKM_SHA512;
62     default:
63       // Not a supported algorithm.
64       return CKM_INVALID_MECHANISM;
65   }
66 }
67
68 bool InitializeRsaOaepParams(const blink::WebCryptoAlgorithm& hash,
69                              const CryptoData& label,
70                              CK_RSA_PKCS_OAEP_PARAMS* oaep_params) {
71   oaep_params->source = CKZ_DATA_SPECIFIED;
72   oaep_params->pSourceData = const_cast<unsigned char*>(label.bytes());
73   oaep_params->ulSourceDataLen = label.byte_length();
74   oaep_params->mgf = WebCryptoHashToMGFMechanism(hash);
75   oaep_params->hashAlg = WebCryptoHashToDigestMechanism(hash);
76
77   if (oaep_params->mgf == CKM_INVALID_MECHANISM ||
78       oaep_params->hashAlg == CKM_INVALID_MECHANISM) {
79     return false;
80   }
81
82   return true;
83 }
84
85 Status EncryptRsaOaep(SECKEYPublicKey* key,
86                       const blink::WebCryptoAlgorithm& hash,
87                       const CryptoData& label,
88                       const CryptoData& data,
89                       std::vector<uint8_t>* buffer) {
90   CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
91   if (!InitializeRsaOaepParams(hash, label, &oaep_params))
92     return Status::ErrorUnsupported();
93
94   SECItem param;
95   param.type = siBuffer;
96   param.data = reinterpret_cast<unsigned char*>(&oaep_params);
97   param.len = sizeof(oaep_params);
98
99   buffer->resize(SECKEY_PublicKeyStrength(key));
100   unsigned char* buffer_data = vector_as_array(buffer);
101   unsigned int output_len;
102   if (NssRuntimeSupport::Get()->pk11_pub_encrypt_func()(key,
103                                                         CKM_RSA_PKCS_OAEP,
104                                                         &param,
105                                                         buffer_data,
106                                                         &output_len,
107                                                         buffer->size(),
108                                                         data.bytes(),
109                                                         data.byte_length(),
110                                                         NULL) != SECSuccess) {
111     return Status::OperationError();
112   }
113
114   CHECK_LE(output_len, buffer->size());
115   buffer->resize(output_len);
116   return Status::Success();
117 }
118
119 Status DecryptRsaOaep(SECKEYPrivateKey* key,
120                       const blink::WebCryptoAlgorithm& hash,
121                       const CryptoData& label,
122                       const CryptoData& data,
123                       std::vector<uint8_t>* buffer) {
124   Status status = NssSupportsRsaOaep();
125   if (status.IsError())
126     return status;
127
128   CK_RSA_PKCS_OAEP_PARAMS oaep_params = {0};
129   if (!InitializeRsaOaepParams(hash, label, &oaep_params))
130     return Status::ErrorUnsupported();
131
132   SECItem param;
133   param.type = siBuffer;
134   param.data = reinterpret_cast<unsigned char*>(&oaep_params);
135   param.len = sizeof(oaep_params);
136
137   const int modulus_length_bytes = PK11_GetPrivateModulusLen(key);
138   if (modulus_length_bytes <= 0)
139     return Status::ErrorUnexpected();
140
141   buffer->resize(modulus_length_bytes);
142
143   unsigned char* buffer_data = vector_as_array(buffer);
144   unsigned int output_len;
145   if (NssRuntimeSupport::Get()->pk11_priv_decrypt_func()(key,
146                                                          CKM_RSA_PKCS_OAEP,
147                                                          &param,
148                                                          buffer_data,
149                                                          &output_len,
150                                                          buffer->size(),
151                                                          data.bytes(),
152                                                          data.byte_length()) !=
153       SECSuccess) {
154     return Status::OperationError();
155   }
156
157   CHECK_LE(output_len, buffer->size());
158   buffer->resize(output_len);
159   return Status::Success();
160 }
161
162 class RsaOaepImplementation : public RsaHashedAlgorithm {
163  public:
164   RsaOaepImplementation()
165       : RsaHashedAlgorithm(
166             CKF_ENCRYPT | CKF_DECRYPT | CKF_WRAP | CKF_UNWRAP,
167             blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
168             blink::WebCryptoKeyUsageDecrypt |
169                 blink::WebCryptoKeyUsageUnwrapKey) {}
170
171   Status GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
172                      bool extractable,
173                      blink::WebCryptoKeyUsageMask usages,
174                      GenerateKeyResult* result) const override {
175     Status status = NssSupportsRsaOaep();
176     if (status.IsError())
177       return status;
178     return RsaHashedAlgorithm::GenerateKey(
179         algorithm, extractable, usages, result);
180   }
181
182   Status VerifyKeyUsagesBeforeImportKey(
183       blink::WebCryptoKeyFormat format,
184       blink::WebCryptoKeyUsageMask usages) const override {
185     Status status = NssSupportsRsaOaep();
186     if (status.IsError())
187       return status;
188     return RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(format, usages);
189   }
190
191   const char* GetJwkAlgorithm(
192       const blink::WebCryptoAlgorithmId hash) const override {
193     switch (hash) {
194       case blink::WebCryptoAlgorithmIdSha1:
195         return "RSA-OAEP";
196       case blink::WebCryptoAlgorithmIdSha256:
197         return "RSA-OAEP-256";
198       case blink::WebCryptoAlgorithmIdSha384:
199         return "RSA-OAEP-384";
200       case blink::WebCryptoAlgorithmIdSha512:
201         return "RSA-OAEP-512";
202       default:
203         return NULL;
204     }
205   }
206
207   Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
208                  const blink::WebCryptoKey& key,
209                  const CryptoData& data,
210                  std::vector<uint8_t>* buffer) const override {
211     if (key.type() != blink::WebCryptoKeyTypePublic)
212       return Status::ErrorUnexpectedKeyType();
213
214     return EncryptRsaOaep(
215         PublicKeyNss::Cast(key)->key(),
216         key.algorithm().rsaHashedParams()->hash(),
217         CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
218         data,
219         buffer);
220   }
221
222   Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
223                  const blink::WebCryptoKey& key,
224                  const CryptoData& data,
225                  std::vector<uint8_t>* buffer) const override {
226     if (key.type() != blink::WebCryptoKeyTypePrivate)
227       return Status::ErrorUnexpectedKeyType();
228
229     return DecryptRsaOaep(
230         PrivateKeyNss::Cast(key)->key(),
231         key.algorithm().rsaHashedParams()->hash(),
232         CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
233         data,
234         buffer);
235   }
236 };
237
238 }  // namespace
239
240 AlgorithmImplementation* CreatePlatformRsaOaepImplementation() {
241   return new RsaOaepImplementation;
242 }
243
244 }  // namespace webcrypto
245
246 }  // namespace content