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 "CryptoAlgorithmRSAES_PKCS1_v1_5.h"
28
29#if ENABLE(WEB_CRYPTO)
30
31#include "CryptoAlgorithmRsaKeyGenParams.h"
32#include "CryptoKeyPair.h"
33#include "CryptoKeyRSA.h"
34#include <wtf/Variant.h>
35
36namespace WebCore {
37
38static const char* const ALG = "RSA1_5";
39
40Ref<CryptoAlgorithm> CryptoAlgorithmRSAES_PKCS1_v1_5::create()
41{
42 return adoptRef(*new CryptoAlgorithmRSAES_PKCS1_v1_5);
43}
44
45CryptoAlgorithmIdentifier CryptoAlgorithmRSAES_PKCS1_v1_5::identifier() const
46{
47 return s_identifier;
48}
49
50void CryptoAlgorithmRSAES_PKCS1_v1_5::encrypt(const CryptoAlgorithmParameters&, Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
51{
52 if (key->type() != CryptoKeyType::Public) {
53 exceptionCallback(InvalidAccessError);
54 return;
55 }
56
57 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
58 [key = WTFMove(key), plainText = WTFMove(plainText)] {
59 return platformEncrypt(downcast<CryptoKeyRSA>(key.get()), plainText);
60 });
61}
62
63void CryptoAlgorithmRSAES_PKCS1_v1_5::decrypt(const CryptoAlgorithmParameters&, Ref<CryptoKey>&& key, Vector<uint8_t>&& cipherText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
64{
65 if (key->type() != CryptoKeyType::Private) {
66 exceptionCallback(InvalidAccessError);
67 return;
68 }
69
70 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
71 [key = WTFMove(key), cipherText = WTFMove(cipherText)] {
72 return platformDecrypt(downcast<CryptoKeyRSA>(key.get()), cipherText);
73 });
74}
75
76void CryptoAlgorithmRSAES_PKCS1_v1_5::generateKey(const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context)
77{
78 const auto& rsaParameters = downcast<CryptoAlgorithmRsaKeyGenParams>(parameters);
79
80 if (usages & (CryptoKeyUsageSign | CryptoKeyUsageVerify | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey)) {
81 exceptionCallback(SyntaxError);
82 return;
83 }
84
85 auto keyPairCallback = [capturedCallback = WTFMove(callback)](CryptoKeyPair&& pair) {
86 pair.publicKey->setUsagesBitmap(pair.publicKey->usagesBitmap() & CryptoKeyUsageEncrypt);
87 pair.privateKey->setUsagesBitmap(pair.privateKey->usagesBitmap() & CryptoKeyUsageDecrypt);
88 capturedCallback(WTFMove(pair));
89 };
90 auto failureCallback = [capturedCallback = WTFMove(exceptionCallback)]() {
91 capturedCallback(OperationError);
92 };
93 // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect.
94 CryptoKeyRSA::generatePair(CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5, CryptoAlgorithmIdentifier::SHA_1, false, rsaParameters.modulusLength, rsaParameters.publicExponentVector(), extractable, usages, WTFMove(keyPairCallback), WTFMove(failureCallback), &context);
95}
96
97void CryptoAlgorithmRSAES_PKCS1_v1_5::importKey(CryptoKeyFormat format, KeyData&& data, const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback)
98{
99 RefPtr<CryptoKeyRSA> result;
100 switch (format) {
101 case CryptoKeyFormat::Jwk: {
102 JsonWebKey key = WTFMove(WTF::get<JsonWebKey>(data));
103 if (usages && ((!key.d.isNull() && (usages ^ CryptoKeyUsageDecrypt)) || (key.d.isNull() && (usages ^ CryptoKeyUsageEncrypt)))) {
104 exceptionCallback(SyntaxError);
105 return;
106 }
107 if (usages && !key.use.isNull() && key.use != "enc") {
108 exceptionCallback(DataError);
109 return;
110 }
111 if (!key.alg.isNull() && key.alg != ALG) {
112 exceptionCallback(DataError);
113 return;
114 }
115 result = CryptoKeyRSA::importJwk(parameters.identifier, WTF::nullopt, WTFMove(key), extractable, usages);
116 break;
117 }
118 case CryptoKeyFormat::Spki: {
119 if (usages && (usages ^ CryptoKeyUsageEncrypt)) {
120 exceptionCallback(SyntaxError);
121 return;
122 }
123 result = CryptoKeyRSA::importSpki(parameters.identifier, WTF::nullopt, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
124 break;
125 }
126 case CryptoKeyFormat::Pkcs8: {
127 if (usages && (usages ^ CryptoKeyUsageDecrypt)) {
128 exceptionCallback(SyntaxError);
129 return;
130 }
131 result = CryptoKeyRSA::importPkcs8(parameters.identifier, WTF::nullopt, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
132 break;
133 }
134 default:
135 exceptionCallback(NotSupportedError);
136 return;
137 }
138 if (!result) {
139 exceptionCallback(DataError);
140 return;
141 }
142
143 callback(*result);
144}
145
146void CryptoAlgorithmRSAES_PKCS1_v1_5::exportKey(CryptoKeyFormat format, Ref<CryptoKey>&& key, KeyDataCallback&& callback, ExceptionCallback&& exceptionCallback)
147{
148 const auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
149
150 if (!rsaKey.keySizeInBits()) {
151 exceptionCallback(OperationError);
152 return;
153 }
154
155 KeyData result;
156 switch (format) {
157 case CryptoKeyFormat::Jwk: {
158 JsonWebKey jwk = rsaKey.exportJwk();
159 jwk.alg = String(ALG);
160 result = WTFMove(jwk);
161 break;
162 }
163 case CryptoKeyFormat::Spki: {
164 auto spki = rsaKey.exportSpki();
165 if (spki.hasException()) {
166 exceptionCallback(spki.releaseException().code());
167 return;
168 }
169 result = spki.releaseReturnValue();
170 break;
171 }
172 case CryptoKeyFormat::Pkcs8: {
173 auto pkcs8 = rsaKey.exportPkcs8();
174 if (pkcs8.hasException()) {
175 exceptionCallback(pkcs8.releaseException().code());
176 return;
177 }
178 result = pkcs8.releaseReturnValue();
179 break;
180 }
181 default:
182 exceptionCallback(NotSupportedError);
183 return;
184 }
185
186 callback(format, WTFMove(result));
187}
188
189}
190
191#endif // ENABLE(WEB_CRYPTO)
192