[GCrypt] Gather SUBTLE_CRYPTO utility functions in a single header
[WebKit-https.git] / Source / WebCore / crypto / gcrypt / CryptoAlgorithmRSA_OAEPGCrypt.cpp
1 /*
2  * Copyright (C) 2014 Igalia S.L. 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 "CryptoAlgorithmRSA_OAEP.h"
28
29 #if ENABLE(SUBTLE_CRYPTO)
30
31 #include "CryptoAlgorithmRsaOaepParams.h"
32 #include "CryptoKeyRSA.h"
33 #include "ExceptionCode.h"
34 #include "GCryptUtilities.h"
35 #include "NotImplemented.h"
36 #include "ScriptExecutionContext.h"
37
38 namespace WebCore {
39
40 static std::optional<Vector<uint8_t>> gcryptEncrypt(CryptoAlgorithmIdentifier hashAlgorithmIdentifier, gcry_sexp_t keySexp, const Vector<uint8_t>& labelVector, const Vector<uint8_t>& plainText)
41 {
42     // Embed the plain-text data in a data s-expression using OAEP padding.
43     // Empty label data is properly handled by gcry_sexp_build().
44     PAL::GCrypt::Handle<gcry_sexp_t> dataSexp;
45     {
46         auto shaAlgorithm = hashAlgorithmName(hashAlgorithmIdentifier);
47         if (!shaAlgorithm)
48             return std::nullopt;
49
50         gcry_error_t error = gcry_sexp_build(&dataSexp, nullptr, "(data(flags oaep)(hash-algo %s)(label %b)(value %b))",
51             *shaAlgorithm, labelVector.size(), labelVector.data(), plainText.size(), plainText.data());
52         if (error != GPG_ERR_NO_ERROR) {
53             PAL::GCrypt::logError(error);
54             return std::nullopt;
55         }
56     }
57
58     // Encrypt data with the provided key. The returned s-expression is of this form:
59     // (enc-val
60     //   (flags oaep)
61     //   (rsa
62     //     (a a-mpi)))
63     PAL::GCrypt::Handle<gcry_sexp_t> cipherSexp;
64     gcry_error_t error = gcry_pk_encrypt(&cipherSexp, dataSexp, keySexp);
65     if (error != GPG_ERR_NO_ERROR) {
66         PAL::GCrypt::logError(error);
67         return std::nullopt;
68     }
69
70     // Return MPI data of the embedded a integer.
71     PAL::GCrypt::Handle<gcry_sexp_t> aSexp(gcry_sexp_find_token(cipherSexp, "a", 0));
72     if (!aSexp)
73         return std::nullopt;
74
75     return mpiData(aSexp);
76 }
77
78 static std::optional<Vector<uint8_t>> gcryptDecrypt(CryptoAlgorithmIdentifier hashAlgorithmIdentifier, gcry_sexp_t keySexp, const Vector<uint8_t>& labelVector, const Vector<uint8_t>& cipherText)
79 {
80     // Embed the cipher-text data in an enc-val s-expression using OAEP padding.
81     // Empty label data is properly handled by gcry_sexp_build().
82     PAL::GCrypt::Handle<gcry_sexp_t> encValSexp;
83     {
84         auto shaAlgorithm = hashAlgorithmName(hashAlgorithmIdentifier);
85         if (!shaAlgorithm)
86             return std::nullopt;
87
88         gcry_error_t error = gcry_sexp_build(&encValSexp, nullptr, "(enc-val(flags oaep)(hash-algo %s)(label %b)(rsa(a %b)))",
89             *shaAlgorithm, labelVector.size(), labelVector.data(), cipherText.size(), cipherText.data());
90         if (error != GPG_ERR_NO_ERROR) {
91             PAL::GCrypt::logError(error);
92             return std::nullopt;
93         }
94     }
95
96     // Decrypt data with the provided key. The returned s-expression is of this form:
97     // (data
98     //   (flags oaep)
99     //   (value block))
100     PAL::GCrypt::Handle<gcry_sexp_t> plainSexp;
101     gcry_error_t error = gcry_pk_decrypt(&plainSexp, encValSexp, keySexp);
102     if (error != GPG_ERR_NO_ERROR) {
103         PAL::GCrypt::logError(error);
104         return std::nullopt;
105     }
106
107     // Return MPI data of the embedded value integer.
108     PAL::GCrypt::Handle<gcry_sexp_t> valueSexp(gcry_sexp_find_token(plainSexp, "value", 0));
109     if (!valueSexp)
110         return std::nullopt;
111
112     return mpiData(valueSexp);
113 }
114
115 void CryptoAlgorithmRSA_OAEP::platformEncrypt(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
116 {
117     context.ref();
118     workQueue.dispatch(
119         [parameters = WTFMove(parameters), key = WTFMove(key), plainText = WTFMove(plainText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
120             auto& rsaParameters = downcast<CryptoAlgorithmRsaOaepParams>(*parameters);
121             auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
122
123             auto output = gcryptEncrypt(rsaKey.hashAlgorithmIdentifier(), rsaKey.platformKey(), rsaParameters.labelVector(), plainText);
124             if (!output) {
125                 // We should only dereference callbacks after being back to the Document/Worker threads.
126                 context.postTask(
127                     [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
128                         exceptionCallback(OperationError);
129                         context.deref();
130                     });
131                 return;
132             }
133
134             // We should only dereference callbacks after being back to the Document/Worker threads.
135             context.postTask(
136                 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
137                     callback(output);
138                     context.deref();
139                 });
140         });
141 }
142
143 void CryptoAlgorithmRSA_OAEP::platformDecrypt(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& cipherText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
144 {
145     context.ref();
146     workQueue.dispatch(
147         [parameters = WTFMove(parameters), key = WTFMove(key), cipherText = WTFMove(cipherText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
148             auto& rsaParameters = downcast<CryptoAlgorithmRsaOaepParams>(*parameters);
149             auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
150
151             auto output = gcryptDecrypt(rsaKey.hashAlgorithmIdentifier(), rsaKey.platformKey(), rsaParameters.labelVector(), cipherText);
152             if (!output) {
153                 // We should only dereference callbacks after being back to the Document/Worker threads.
154                 context.postTask(
155                     [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
156                         exceptionCallback(OperationError);
157                         context.deref();
158                     });
159                 return;
160             }
161
162             // We should only dereference callbacks after being back to the Document/Worker threads.
163             context.postTask(
164                 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
165                     callback(output);
166                     context.deref();
167                 });
168         });
169 }
170
171 ExceptionOr<void> CryptoAlgorithmRSA_OAEP::platformEncrypt(const CryptoAlgorithmRsaOaepParamsDeprecated&, const CryptoKeyRSA&, const CryptoOperationData&, VectorCallback&&, VoidCallback&&)
172 {
173     notImplemented();
174     return Exception { NOT_SUPPORTED_ERR };
175 }
176
177 ExceptionOr<void> CryptoAlgorithmRSA_OAEP::platformDecrypt(const CryptoAlgorithmRsaOaepParamsDeprecated&, const CryptoKeyRSA&, const CryptoOperationData&, VectorCallback&&, VoidCallback&&)
178 {
179     notImplemented();
180     return Exception { NOT_SUPPORTED_ERR };
181 }
182
183 } // namespace WebCore
184
185 #endif // ENABLE(SUBTLE_CRYPTO)