1 | /* |
2 | * Copyright (C) 2017 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 "CryptoAlgorithmECDSA.h" |
28 | |
29 | #if ENABLE(WEB_CRYPTO) |
30 | |
31 | #include "CryptoAlgorithmEcKeyParams.h" |
32 | #include "CryptoAlgorithmEcdsaParams.h" |
33 | #include "CryptoKeyEC.h" |
34 | #include <JavaScriptCore/JSCJSValueInlines.h> |
35 | #include <wtf/CrossThreadCopier.h> |
36 | |
37 | namespace WebCore { |
38 | |
39 | namespace CryptoAlgorithmECDSAInternal { |
40 | static const char* const ALG256 = "ES256" ; |
41 | static const char* const ALG384 = "ES384" ; |
42 | static const char* const ALG512 = "ES512" ; |
43 | static const char* const P256 = "P-256" ; |
44 | static const char* const P384 = "P-384" ; |
45 | static const char* const P521 = "P-521" ; |
46 | } |
47 | |
48 | Ref<CryptoAlgorithm> CryptoAlgorithmECDSA::create() |
49 | { |
50 | return adoptRef(*new CryptoAlgorithmECDSA); |
51 | } |
52 | |
53 | CryptoAlgorithmIdentifier CryptoAlgorithmECDSA::identifier() const |
54 | { |
55 | return s_identifier; |
56 | } |
57 | |
58 | void CryptoAlgorithmECDSA::sign(const CryptoAlgorithmParameters& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue) |
59 | { |
60 | if (key->type() != CryptoKeyType::Private) { |
61 | exceptionCallback(InvalidAccessError); |
62 | return; |
63 | } |
64 | |
65 | dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback), |
66 | [parameters = crossThreadCopy(downcast<CryptoAlgorithmEcdsaParams>(parameters)), key = WTFMove(key), data = WTFMove(data)] { |
67 | return platformSign(parameters, downcast<CryptoKeyEC>(key.get()), data); |
68 | }); |
69 | } |
70 | |
71 | void CryptoAlgorithmECDSA::verify(const CryptoAlgorithmParameters& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& signature, Vector<uint8_t>&& data, BoolCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue) |
72 | { |
73 | if (key->type() != CryptoKeyType::Public) { |
74 | exceptionCallback(InvalidAccessError); |
75 | return; |
76 | } |
77 | |
78 | dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback), |
79 | [parameters = crossThreadCopy(downcast<CryptoAlgorithmEcdsaParams>(parameters)), key = WTFMove(key), signature = WTFMove(signature), data = WTFMove(data)] { |
80 | return platformVerify(parameters, downcast<CryptoKeyEC>(key.get()), signature, data); |
81 | }); |
82 | } |
83 | |
84 | void CryptoAlgorithmECDSA::generateKey(const CryptoAlgorithmParameters& parameters, bool , CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext&) |
85 | { |
86 | const auto& ecParameters = downcast<CryptoAlgorithmEcKeyParams>(parameters); |
87 | |
88 | if (usages & (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey)) { |
89 | exceptionCallback(SyntaxError); |
90 | return; |
91 | } |
92 | |
93 | auto result = CryptoKeyEC::generatePair(CryptoAlgorithmIdentifier::ECDSA, ecParameters.namedCurve, extractable, usages); |
94 | if (result.hasException()) { |
95 | exceptionCallback(result.releaseException().code()); |
96 | return; |
97 | } |
98 | |
99 | auto pair = result.releaseReturnValue(); |
100 | pair.publicKey->setUsagesBitmap(pair.publicKey->usagesBitmap() & CryptoKeyUsageVerify); |
101 | pair.privateKey->setUsagesBitmap(pair.privateKey->usagesBitmap() & CryptoKeyUsageSign); |
102 | callback(WTFMove(pair)); |
103 | } |
104 | |
105 | void CryptoAlgorithmECDSA::importKey(CryptoKeyFormat format, KeyData&& data, const CryptoAlgorithmParameters& parameters, bool , CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback) |
106 | { |
107 | using namespace CryptoAlgorithmECDSAInternal; |
108 | const auto& ecParameters = downcast<CryptoAlgorithmEcKeyParams>(parameters); |
109 | |
110 | RefPtr<CryptoKeyEC> result; |
111 | switch (format) { |
112 | case CryptoKeyFormat::Jwk: { |
113 | JsonWebKey key = WTFMove(WTF::get<JsonWebKey>(data)); |
114 | |
115 | if (usages && ((!key.d.isNull() && (usages ^ CryptoKeyUsageSign)) || (key.d.isNull() && (usages ^ CryptoKeyUsageVerify)))) { |
116 | exceptionCallback(SyntaxError); |
117 | return; |
118 | } |
119 | if (usages && !key.use.isNull() && key.use != "sig" ) { |
120 | exceptionCallback(DataError); |
121 | return; |
122 | } |
123 | |
124 | bool isMatched = false; |
125 | if (key.crv == P256) |
126 | isMatched = key.alg.isNull() || key.alg == ALG256; |
127 | if (key.crv == P384) |
128 | isMatched = key.alg.isNull() || key.alg == ALG384; |
129 | if (key.crv == P521) |
130 | isMatched = key.alg.isNull() || key.alg == ALG512; |
131 | if (!isMatched) { |
132 | exceptionCallback(DataError); |
133 | return; |
134 | } |
135 | |
136 | result = CryptoKeyEC::importJwk(ecParameters.identifier, ecParameters.namedCurve, WTFMove(key), extractable, usages); |
137 | break; |
138 | } |
139 | case CryptoKeyFormat::Raw: |
140 | if (usages && (usages ^ CryptoKeyUsageVerify)) { |
141 | exceptionCallback(SyntaxError); |
142 | return; |
143 | } |
144 | result = CryptoKeyEC::importRaw(ecParameters.identifier, ecParameters.namedCurve, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages); |
145 | break; |
146 | case CryptoKeyFormat::Spki: |
147 | if (usages && (usages ^ CryptoKeyUsageVerify)) { |
148 | exceptionCallback(SyntaxError); |
149 | return; |
150 | } |
151 | result = CryptoKeyEC::importSpki(ecParameters.identifier, ecParameters.namedCurve, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages); |
152 | break; |
153 | case CryptoKeyFormat::Pkcs8: |
154 | if (usages && (usages ^ CryptoKeyUsageSign)) { |
155 | exceptionCallback(SyntaxError); |
156 | return; |
157 | } |
158 | result = CryptoKeyEC::importPkcs8(ecParameters.identifier, ecParameters.namedCurve, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages); |
159 | break; |
160 | } |
161 | if (!result) { |
162 | exceptionCallback(DataError); |
163 | return; |
164 | } |
165 | |
166 | callback(*result); |
167 | } |
168 | |
169 | void CryptoAlgorithmECDSA::exportKey(CryptoKeyFormat format, Ref<CryptoKey>&& key, KeyDataCallback&& callback, ExceptionCallback&& exceptionCallback) |
170 | { |
171 | const auto& ecKey = downcast<CryptoKeyEC>(key.get()); |
172 | |
173 | if (!ecKey.keySizeInBits()) { |
174 | exceptionCallback(OperationError); |
175 | return; |
176 | } |
177 | |
178 | KeyData result; |
179 | switch (format) { |
180 | case CryptoKeyFormat::Jwk: { |
181 | auto jwk = ecKey.exportJwk(); |
182 | if (jwk.hasException()) { |
183 | exceptionCallback(jwk.releaseException().code()); |
184 | return; |
185 | } |
186 | result = jwk.releaseReturnValue(); |
187 | break; |
188 | } |
189 | case CryptoKeyFormat::Raw: { |
190 | auto raw = ecKey.exportRaw(); |
191 | if (raw.hasException()) { |
192 | exceptionCallback(raw.releaseException().code()); |
193 | return; |
194 | } |
195 | result = raw.releaseReturnValue(); |
196 | break; |
197 | } |
198 | case CryptoKeyFormat::Spki: { |
199 | auto spki = ecKey.exportSpki(); |
200 | if (spki.hasException()) { |
201 | exceptionCallback(spki.releaseException().code()); |
202 | return; |
203 | } |
204 | result = spki.releaseReturnValue(); |
205 | break; |
206 | } |
207 | case CryptoKeyFormat::Pkcs8: { |
208 | auto pkcs8 = ecKey.exportPkcs8(); |
209 | if (pkcs8.hasException()) { |
210 | exceptionCallback(pkcs8.releaseException().code()); |
211 | return; |
212 | } |
213 | result = pkcs8.releaseReturnValue(); |
214 | break; |
215 | } |
216 | } |
217 | |
218 | callback(format, WTFMove(result)); |
219 | } |
220 | |
221 | } // namespace WebCore |
222 | |
223 | #endif // ENABLE(WEB_CRYPTO) |
224 | |