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
NssSupportsRsaOaep()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
WebCryptoHashToMGFMechanism(const blink::WebCryptoAlgorithm & algorithm)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
WebCryptoHashToDigestMechanism(const blink::WebCryptoAlgorithm & algorithm)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
InitializeRsaOaepParams(const blink::WebCryptoAlgorithm & hash,const CryptoData & label,CK_RSA_PKCS_OAEP_PARAMS * oaep_params)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
EncryptRsaOaep(SECKEYPublicKey * key,const blink::WebCryptoAlgorithm & hash,const CryptoData & label,const CryptoData & data,std::vector<uint8_t> * buffer)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 ¶m,
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
DecryptRsaOaep(SECKEYPrivateKey * key,const blink::WebCryptoAlgorithm & hash,const CryptoData & label,const CryptoData & data,std::vector<uint8_t> * buffer)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 ¶m,
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:
RsaOaepImplementation()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
VerifyKeyUsagesBeforeGenerateKeyPair(blink::WebCryptoKeyUsageMask combined_usage_mask,blink::WebCryptoKeyUsageMask * public_usage_mask,blink::WebCryptoKeyUsageMask * private_usage_mask) const171 virtual Status VerifyKeyUsagesBeforeGenerateKeyPair(
172 blink::WebCryptoKeyUsageMask combined_usage_mask,
173 blink::WebCryptoKeyUsageMask* public_usage_mask,
174 blink::WebCryptoKeyUsageMask* private_usage_mask) const OVERRIDE {
175 Status status = NssSupportsRsaOaep();
176 if (status.IsError())
177 return status;
178 return RsaHashedAlgorithm::VerifyKeyUsagesBeforeGenerateKeyPair(
179 combined_usage_mask, public_usage_mask, private_usage_mask);
180 }
181
VerifyKeyUsagesBeforeImportKey(blink::WebCryptoKeyFormat format,blink::WebCryptoKeyUsageMask usage_mask) const182 virtual Status VerifyKeyUsagesBeforeImportKey(
183 blink::WebCryptoKeyFormat format,
184 blink::WebCryptoKeyUsageMask usage_mask) const OVERRIDE {
185 Status status = NssSupportsRsaOaep();
186 if (status.IsError())
187 return status;
188 return RsaHashedAlgorithm::VerifyKeyUsagesBeforeImportKey(format,
189 usage_mask);
190 }
191
GetJwkAlgorithm(const blink::WebCryptoAlgorithmId hash) const192 virtual const char* GetJwkAlgorithm(
193 const blink::WebCryptoAlgorithmId hash) const OVERRIDE {
194 switch (hash) {
195 case blink::WebCryptoAlgorithmIdSha1:
196 return "RSA-OAEP";
197 case blink::WebCryptoAlgorithmIdSha256:
198 return "RSA-OAEP-256";
199 case blink::WebCryptoAlgorithmIdSha384:
200 return "RSA-OAEP-384";
201 case blink::WebCryptoAlgorithmIdSha512:
202 return "RSA-OAEP-512";
203 default:
204 return NULL;
205 }
206 }
207
Encrypt(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & data,std::vector<uint8_t> * buffer) const208 virtual Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
209 const blink::WebCryptoKey& key,
210 const CryptoData& data,
211 std::vector<uint8_t>* buffer) const OVERRIDE {
212 if (key.type() != blink::WebCryptoKeyTypePublic)
213 return Status::ErrorUnexpectedKeyType();
214
215 return EncryptRsaOaep(
216 PublicKeyNss::Cast(key)->key(),
217 key.algorithm().rsaHashedParams()->hash(),
218 CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
219 data,
220 buffer);
221 }
222
Decrypt(const blink::WebCryptoAlgorithm & algorithm,const blink::WebCryptoKey & key,const CryptoData & data,std::vector<uint8_t> * buffer) const223 virtual Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
224 const blink::WebCryptoKey& key,
225 const CryptoData& data,
226 std::vector<uint8_t>* buffer) const OVERRIDE {
227 if (key.type() != blink::WebCryptoKeyTypePrivate)
228 return Status::ErrorUnexpectedKeyType();
229
230 return DecryptRsaOaep(
231 PrivateKeyNss::Cast(key)->key(),
232 key.algorithm().rsaHashedParams()->hash(),
233 CryptoData(algorithm.rsaOaepParams()->optionalLabel()),
234 data,
235 buffer);
236 }
237 };
238
239 } // namespace
240
CreatePlatformRsaOaepImplementation()241 AlgorithmImplementation* CreatePlatformRsaOaepImplementation() {
242 return new RsaOaepImplementation;
243 }
244
245 } // namespace webcrypto
246
247 } // namespace content
248