[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / WebCore / crypto / algorithms / CryptoAlgorithmHMAC.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 "CryptoAlgorithmHMAC.h"
28
29 #if ENABLE(SUBTLE_CRYPTO)
30
31 #include "CryptoAlgorithmHmacKeyParams.h"
32 #include "CryptoAlgorithmHmacKeyParamsDeprecated.h"
33 #include "CryptoAlgorithmHmacParamsDeprecated.h"
34 #include "CryptoKeyDataOctetSequence.h"
35 #include "CryptoKeyHMAC.h"
36 #include "ExceptionCode.h"
37
38 namespace WebCore {
39
40 static const char* const ALG1 = "HS1";
41 static const char* const ALG224 = "HS224";
42 static const char* const ALG256 = "HS256";
43 static const char* const ALG384 = "HS384";
44 static const char* const ALG512 = "HS512";
45
46 static inline bool usagesAreInvalidForCryptoAlgorithmHMAC(CryptoKeyUsageBitmap usages)
47 {
48     return usages & (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey);
49 }
50
51 Ref<CryptoAlgorithm> CryptoAlgorithmHMAC::create()
52 {
53     return adoptRef(*new CryptoAlgorithmHMAC);
54 }
55
56 CryptoAlgorithmIdentifier CryptoAlgorithmHMAC::identifier() const
57 {
58     return s_identifier;
59 }
60
61 bool CryptoAlgorithmHMAC::keyAlgorithmMatches(const CryptoAlgorithmHmacParamsDeprecated& parameters, const CryptoKey& key) const
62 {
63     if (key.algorithmIdentifier() != s_identifier)
64         return false;
65
66     if (downcast<CryptoKeyHMAC>(key).hashAlgorithmIdentifier() != parameters.hash)
67         return false;
68
69     return true;
70 }
71
72 void CryptoAlgorithmHMAC::generateKey(const std::unique_ptr<CryptoAlgorithmParameters>&& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext&)
73 {
74     ASSERT(parameters);
75     const auto& hmacParameters = downcast<CryptoAlgorithmHmacKeyParams>(*parameters);
76
77     if (usagesAreInvalidForCryptoAlgorithmHMAC(usages)) {
78         exceptionCallback(SYNTAX_ERR);
79         return;
80     }
81
82     if (hmacParameters.length && !hmacParameters.length.value()) {
83         exceptionCallback(OperationError);
84         return;
85     }
86
87     auto result = CryptoKeyHMAC::generate(hmacParameters.length.value_or(0), hmacParameters.hashIdentifier, extractable, usages);
88     if (!result) {
89         exceptionCallback(OperationError);
90         return;
91     }
92
93     callback(result.get(), nullptr);
94 }
95
96 void CryptoAlgorithmHMAC::importKey(SubtleCrypto::KeyFormat format, KeyData&& data, const std::unique_ptr<CryptoAlgorithmParameters>&& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback)
97 {
98     ASSERT(parameters);
99     const auto& hmacParameters = downcast<CryptoAlgorithmHmacKeyParams>(*parameters);
100
101     if (usagesAreInvalidForCryptoAlgorithmHMAC(usages)) {
102         exceptionCallback(SYNTAX_ERR);
103         return;
104     }
105
106     RefPtr<CryptoKeyHMAC> result;
107     switch (format) {
108     case SubtleCrypto::KeyFormat::Raw:
109         result = CryptoKeyHMAC::importRaw(hmacParameters.length.value_or(0), hmacParameters.hashIdentifier, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
110         break;
111     case SubtleCrypto::KeyFormat::Jwk: {
112         auto checkAlgCallback = [](CryptoAlgorithmIdentifier hash, const std::optional<String>& alg) -> bool {
113             switch (hash) {
114             case CryptoAlgorithmIdentifier::SHA_1:
115                 return !alg || alg.value() == ALG1;
116             case CryptoAlgorithmIdentifier::SHA_224:
117                 return !alg || alg.value() == ALG224;
118             case CryptoAlgorithmIdentifier::SHA_256:
119                 return !alg || alg.value() == ALG256;
120             case CryptoAlgorithmIdentifier::SHA_384:
121                 return !alg || alg.value() == ALG384;
122             case CryptoAlgorithmIdentifier::SHA_512:
123                 return !alg || alg.value() == ALG512;
124             default:
125                 return false;
126             }
127             return false;
128         };
129         result = CryptoKeyHMAC::importJwk(hmacParameters.length.value_or(0), hmacParameters.hashIdentifier, WTFMove(WTF::get<JsonWebKey>(data)), extractable, usages, WTFMove(checkAlgCallback));
130         break;
131     }
132     default:
133         exceptionCallback(NOT_SUPPORTED_ERR);
134         return;
135     }
136     if (!result) {
137         exceptionCallback(DataError);
138         return;
139     }
140
141     callback(*result);
142 }
143
144 void CryptoAlgorithmHMAC::exportKey(SubtleCrypto::KeyFormat format, Ref<CryptoKey>&& key, KeyDataCallback&& callback, ExceptionCallback&& exceptionCallback)
145 {
146     const auto& hmacKey = downcast<CryptoKeyHMAC>(key.get());
147
148     if (hmacKey.key().isEmpty()) {
149         exceptionCallback(OperationError);
150         return;
151     }
152
153     KeyData result;
154     switch (format) {
155     case SubtleCrypto::KeyFormat::Raw:
156         result = Vector<uint8_t>(hmacKey.key());
157         break;
158     case SubtleCrypto::KeyFormat::Jwk: {
159         JsonWebKey jwk = hmacKey.exportJwk();
160         switch (hmacKey.hashAlgorithmIdentifier()) {
161         case CryptoAlgorithmIdentifier::SHA_1:
162             jwk.alg = String(ALG1);
163             break;
164         case CryptoAlgorithmIdentifier::SHA_224:
165             jwk.alg = String(ALG224);
166             break;
167         case CryptoAlgorithmIdentifier::SHA_256:
168             jwk.alg = String(ALG256);
169             break;
170         case CryptoAlgorithmIdentifier::SHA_384:
171             jwk.alg = String(ALG384);
172             break;
173         case CryptoAlgorithmIdentifier::SHA_512:
174             jwk.alg = String(ALG512);
175             break;
176         default:
177             ASSERT_NOT_REACHED();
178         }
179         result = WTFMove(jwk);
180         break;
181     }
182     default:
183         exceptionCallback(NOT_SUPPORTED_ERR);
184         return;
185     }
186
187     callback(format, WTFMove(result));
188 }
189
190 ExceptionOr<void> CryptoAlgorithmHMAC::sign(const CryptoAlgorithmParametersDeprecated& parameters, const CryptoKey& key, const CryptoOperationData& data, VectorCallback&& callback, VoidCallback&& failureCallback)
191 {
192     auto& hmacParameters = downcast<CryptoAlgorithmHmacParamsDeprecated>(parameters);
193     if (!keyAlgorithmMatches(hmacParameters, key))
194         return Exception { NOT_SUPPORTED_ERR };
195     return platformSign(hmacParameters, downcast<CryptoKeyHMAC>(key), data, WTFMove(callback), WTFMove(failureCallback));
196 }
197
198 ExceptionOr<void> CryptoAlgorithmHMAC::verify(const CryptoAlgorithmParametersDeprecated& parameters, const CryptoKey& key, const CryptoOperationData& expectedSignature, const CryptoOperationData& data, BoolCallback&& callback, VoidCallback&& failureCallback)
199 {
200     auto& hmacParameters = downcast<CryptoAlgorithmHmacParamsDeprecated>(parameters);
201     if (!keyAlgorithmMatches(hmacParameters, key))
202         return Exception { NOT_SUPPORTED_ERR };
203     return platformVerify(hmacParameters, downcast<CryptoKeyHMAC>(key), expectedSignature, data, WTFMove(callback), WTFMove(failureCallback));
204 }
205
206 ExceptionOr<void> CryptoAlgorithmHMAC::generateKey(const CryptoAlgorithmParametersDeprecated& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, VoidCallback&& failureCallback, ScriptExecutionContext&)
207 {
208     auto& hmacParameters = downcast<CryptoAlgorithmHmacKeyParamsDeprecated>(parameters);
209     auto result = CryptoKeyHMAC::generate(hmacParameters.hasLength ? hmacParameters.length : 0, hmacParameters.hash, extractable, usages);
210     if (!result) {
211         failureCallback();
212         return { };
213     }
214     callback(result.get(), nullptr);
215     return { };
216 }
217
218 ExceptionOr<void> CryptoAlgorithmHMAC::importKey(const CryptoAlgorithmParametersDeprecated& parameters, const CryptoKeyData& keyData, bool extractable, CryptoKeyUsageBitmap usage, KeyCallback&& callback, VoidCallback&&)
219 {
220     if (!is<CryptoKeyDataOctetSequence>(keyData))
221         return Exception { NOT_SUPPORTED_ERR };
222     callback(CryptoKeyHMAC::create(downcast<CryptoKeyDataOctetSequence>(keyData).octetSequence(), downcast<CryptoAlgorithmHmacParamsDeprecated>(parameters).hash, extractable, usage));
223     return { };
224 }
225
226 }
227
228 #endif // ENABLE(SUBTLE_CRYPTO)