[WebCrypto] Crypto operations should copy their parameters before hoping to another...
[WebKit-https.git] / Source / WebCore / crypto / algorithms / CryptoAlgorithmRSASSA_PKCS1_v1_5.cpp
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(SUBTLE_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 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
103 void 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
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(SUBTLE_CRYPTO)