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 | |
37 | namespace WebCore { |
38 | |
39 | namespace CryptoAlgorithmRSASSA_PKCS1_v1_5Internal { |
40 | static const char* const ALG1 = "RS1" ; |
41 | static const char* const ALG224 = "RS224" ; |
42 | static const char* const ALG256 = "RS256" ; |
43 | static const char* const ALG384 = "RS384" ; |
44 | static const char* const ALG512 = "RS512" ; |
45 | } |
46 | |
47 | Ref<CryptoAlgorithm> CryptoAlgorithmRSASSA_PKCS1_v1_5::create() |
48 | { |
49 | return adoptRef(*new CryptoAlgorithmRSASSA_PKCS1_v1_5); |
50 | } |
51 | |
52 | CryptoAlgorithmIdentifier CryptoAlgorithmRSASSA_PKCS1_v1_5::identifier() const |
53 | { |
54 | return s_identifier; |
55 | } |
56 | |
57 | void 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 | |
70 | void 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 | |
83 | void CryptoAlgorithmRSASSA_PKCS1_v1_5::generateKey(const CryptoAlgorithmParameters& parameters, bool , 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 | |
103 | void CryptoAlgorithmRSASSA_PKCS1_v1_5::importKey(CryptoKeyFormat format, KeyData&& data, const CryptoAlgorithmParameters& parameters, bool , 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 | |
181 | void 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 | |