1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CryptoAlgorithmRSASSA_PKCS1_v1_5.h"
28
29#if ENABLE(WEB_CRYPTO)
30
31#include "CryptoAlgorithmRsaHashedImportParams.h"
32#include "CryptoAlgorithmRsaHashedKeyGenParams.h"
33#include "CryptoKeyPair.h"
34#include "CryptoKeyRSA.h"
35#include <wtf/Variant.h>
36
37namespace WebCore {
38
39namespace CryptoAlgorithmRSASSA_PKCS1_v1_5Internal {
40static const char* const ALG1 = "RS1";
41static const char* const ALG224 = "RS224";
42static const char* const ALG256 = "RS256";
43static const char* const ALG384 = "RS384";
44static const char* const ALG512 = "RS512";
45}
46
47Ref<CryptoAlgorithm> CryptoAlgorithmRSASSA_PKCS1_v1_5::create()
48{
49 return adoptRef(*new CryptoAlgorithmRSASSA_PKCS1_v1_5);
50}
51
52CryptoAlgorithmIdentifier CryptoAlgorithmRSASSA_PKCS1_v1_5::identifier() const
53{
54 return s_identifier;
55}
56
57void CryptoAlgorithmRSASSA_PKCS1_v1_5::sign(const CryptoAlgorithmParameters&, Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
58{
59 if (key->type() != CryptoKeyType::Private) {
60 exceptionCallback(InvalidAccessError);
61 return;
62 }
63
64 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
65 [key = WTFMove(key), data = WTFMove(data)] {
66 return platformSign(downcast<CryptoKeyRSA>(key.get()), data);
67 });
68}
69
70void CryptoAlgorithmRSASSA_PKCS1_v1_5::verify(const CryptoAlgorithmParameters&, Ref<CryptoKey>&& key, Vector<uint8_t>&& signature, Vector<uint8_t>&& data, BoolCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
71{
72 if (key->type() != CryptoKeyType::Public) {
73 exceptionCallback(InvalidAccessError);
74 return;
75 }
76
77 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
78 [key = WTFMove(key), signature = WTFMove(signature), data = WTFMove(data)] {
79 return platformVerify(downcast<CryptoKeyRSA>(key.get()), signature, data);
80 });
81}
82
83void CryptoAlgorithmRSASSA_PKCS1_v1_5::generateKey(const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context)
84{
85 const auto& rsaParameters = downcast<CryptoAlgorithmRsaHashedKeyGenParams>(parameters);
86
87 if (usages & (CryptoKeyUsageDecrypt | CryptoKeyUsageEncrypt | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey)) {
88 exceptionCallback(SyntaxError);
89 return;
90 }
91
92 auto keyPairCallback = [capturedCallback = WTFMove(callback)](CryptoKeyPair&& pair) {
93 pair.publicKey->setUsagesBitmap(pair.publicKey->usagesBitmap() & CryptoKeyUsageVerify);
94 pair.privateKey->setUsagesBitmap(pair.privateKey->usagesBitmap() & CryptoKeyUsageSign);
95 capturedCallback(WTFMove(pair));
96 };
97 auto failureCallback = [capturedCallback = WTFMove(exceptionCallback)]() {
98 capturedCallback(OperationError);
99 };
100 CryptoKeyRSA::generatePair(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5, rsaParameters.hashIdentifier, true, rsaParameters.modulusLength, rsaParameters.publicExponentVector(), extractable, usages, WTFMove(keyPairCallback), WTFMove(failureCallback), &context);
101}
102
103void CryptoAlgorithmRSASSA_PKCS1_v1_5::importKey(CryptoKeyFormat format, KeyData&& data, const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback)
104{
105 using namespace CryptoAlgorithmRSASSA_PKCS1_v1_5Internal;
106
107 const auto& rsaParameters = downcast<CryptoAlgorithmRsaHashedImportParams>(parameters);
108
109 RefPtr<CryptoKeyRSA> result;
110 switch (format) {
111 case CryptoKeyFormat::Jwk: {
112 JsonWebKey key = WTFMove(WTF::get<JsonWebKey>(data));
113
114 if (usages && ((!key.d.isNull() && (usages ^ CryptoKeyUsageSign)) || (key.d.isNull() && (usages ^ CryptoKeyUsageVerify)))) {
115 exceptionCallback(SyntaxError);
116 return;
117 }
118 if (usages && !key.use.isNull() && key.use != "sig") {
119 exceptionCallback(DataError);
120 return;
121 }
122
123 bool isMatched = false;
124 switch (rsaParameters.hashIdentifier) {
125 case CryptoAlgorithmIdentifier::SHA_1:
126 isMatched = key.alg.isNull() || key.alg == ALG1;
127 break;
128 case CryptoAlgorithmIdentifier::SHA_224:
129 isMatched = key.alg.isNull() || key.alg == ALG224;
130 break;
131 case CryptoAlgorithmIdentifier::SHA_256:
132 isMatched = key.alg.isNull() || key.alg == ALG256;
133 break;
134 case CryptoAlgorithmIdentifier::SHA_384:
135 isMatched = key.alg.isNull() || key.alg == ALG384;
136 break;
137 case CryptoAlgorithmIdentifier::SHA_512:
138 isMatched = key.alg.isNull() || key.alg == ALG512;
139 break;
140 default:
141 break;
142 }
143 if (!isMatched) {
144 exceptionCallback(DataError);
145 return;
146 }
147
148 result = CryptoKeyRSA::importJwk(rsaParameters.identifier, rsaParameters.hashIdentifier, WTFMove(key), extractable, usages);
149 break;
150 }
151 case CryptoKeyFormat::Spki: {
152 if (usages && (usages ^ CryptoKeyUsageVerify)) {
153 exceptionCallback(SyntaxError);
154 return;
155 }
156 // FIXME: <webkit.org/b/165436>
157 result = CryptoKeyRSA::importSpki(rsaParameters.identifier, rsaParameters.hashIdentifier, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
158 break;
159 }
160 case CryptoKeyFormat::Pkcs8: {
161 if (usages && (usages ^ CryptoKeyUsageSign)) {
162 exceptionCallback(SyntaxError);
163 return;
164 }
165 // FIXME: <webkit.org/b/165436>
166 result = CryptoKeyRSA::importPkcs8(parameters.identifier, rsaParameters.hashIdentifier, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
167 break;
168 }
169 default:
170 exceptionCallback(NotSupportedError);
171 return;
172 }
173 if (!result) {
174 exceptionCallback(DataError);
175 return;
176 }
177
178 callback(*result);
179}
180
181void CryptoAlgorithmRSASSA_PKCS1_v1_5::exportKey(CryptoKeyFormat format, Ref<CryptoKey>&& key, KeyDataCallback&& callback, ExceptionCallback&& exceptionCallback)
182{
183 using namespace CryptoAlgorithmRSASSA_PKCS1_v1_5Internal;
184 const auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
185
186 if (!rsaKey.keySizeInBits()) {
187 exceptionCallback(OperationError);
188 return;
189 }
190
191 KeyData result;
192 switch (format) {
193 case CryptoKeyFormat::Jwk: {
194 JsonWebKey jwk = rsaKey.exportJwk();
195 switch (rsaKey.hashAlgorithmIdentifier()) {
196 case CryptoAlgorithmIdentifier::SHA_1:
197 jwk.alg = String(ALG1);
198 break;
199 case CryptoAlgorithmIdentifier::SHA_224:
200 jwk.alg = String(ALG224);
201 break;
202 case CryptoAlgorithmIdentifier::SHA_256:
203 jwk.alg = String(ALG256);
204 break;
205 case CryptoAlgorithmIdentifier::SHA_384:
206 jwk.alg = String(ALG384);
207 break;
208 case CryptoAlgorithmIdentifier::SHA_512:
209 jwk.alg = String(ALG512);
210 break;
211 default:
212 ASSERT_NOT_REACHED();
213 }
214 result = WTFMove(jwk);
215 break;
216 }
217 case CryptoKeyFormat::Spki: {
218 auto spki = rsaKey.exportSpki();
219 if (spki.hasException()) {
220 exceptionCallback(spki.releaseException().code());
221 return;
222 }
223 result = spki.releaseReturnValue();
224 break;
225 }
226 case CryptoKeyFormat::Pkcs8: {
227 auto pkcs8 = rsaKey.exportPkcs8();
228 if (pkcs8.hasException()) {
229 exceptionCallback(pkcs8.releaseException().code());
230 return;
231 }
232 result = pkcs8.releaseReturnValue();
233 break;
234 }
235 default:
236 exceptionCallback(NotSupportedError);
237 return;
238 }
239
240 callback(format, WTFMove(result));
241}
242
243}
244
245#endif // ENABLE(WEB_CRYPTO)
246