2 * Copyright (C) 2014 Igalia S.L. All rights reserved.
3 * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
28 #include "CryptoAlgorithmRSASSA_PKCS1_v1_5.h"
30 #if ENABLE(SUBTLE_CRYPTO)
32 #include "CryptoAlgorithmRsaSsaParamsDeprecated.h"
33 #include "CryptoKeyRSA.h"
34 #include "ExceptionCode.h"
35 #include "GCryptUtilities.h"
36 #include "NotImplemented.h"
37 #include "ScriptExecutionContext.h"
41 static std::optional<Vector<uint8_t>> gcryptSign(gcry_sexp_t keySexp, const Vector<uint8_t>& data, CryptoAlgorithmIdentifier hashAlgorithmIdentifier)
43 // Perform digest operation with the specified algorithm on the given data.
44 Vector<uint8_t> dataHash;
46 auto digestAlgorithm = hashCryptoDigestAlgorithm(hashAlgorithmIdentifier);
50 auto digest = PAL::CryptoDigest::create(*digestAlgorithm);
54 digest->addBytes(data.data(), data.size());
55 dataHash = digest->computeHash();
58 // Construct the data s-expression that contains PKCS#1-padded hashed data.
59 PAL::GCrypt::Handle<gcry_sexp_t> dataSexp;
61 auto shaAlgorithm = hashAlgorithmName(hashAlgorithmIdentifier);
65 gcry_error_t error = gcry_sexp_build(&dataSexp, nullptr, "(data(flags pkcs1)(hash %s %b))",
66 *shaAlgorithm, dataHash.size(), dataHash.data());
67 if (error != GPG_ERR_NO_ERROR) {
68 PAL::GCrypt::logError(error);
73 // Perform the PK signing, retrieving a sig-val s-expression of the following form:
77 PAL::GCrypt::Handle<gcry_sexp_t> signatureSexp;
78 gcry_error_t error = gcry_pk_sign(&signatureSexp, dataSexp, keySexp);
79 if (error != GPG_ERR_NO_ERROR) {
80 PAL::GCrypt::logError(error);
84 // Return MPI data of the embedded s integer.
85 PAL::GCrypt::Handle<gcry_sexp_t> sSexp(gcry_sexp_find_token(signatureSexp, "s", 0));
89 return mpiData(sSexp);
92 static std::optional<bool> gcryptVerify(gcry_sexp_t keySexp, const Vector<uint8_t>& signature, const Vector<uint8_t>& data, CryptoAlgorithmIdentifier hashAlgorithmIdentifier)
94 // Perform digest operation with the specified algorithm on the given data.
95 Vector<uint8_t> dataHash;
97 auto digestAlgorithm = hashCryptoDigestAlgorithm(hashAlgorithmIdentifier);
101 auto digest = PAL::CryptoDigest::create(*digestAlgorithm);
105 digest->addBytes(data.data(), data.size());
106 dataHash = digest->computeHash();
109 // Construct the sig-val s-expression that contains the signature data.
110 PAL::GCrypt::Handle<gcry_sexp_t> signatureSexp;
111 gcry_error_t error = gcry_sexp_build(&signatureSexp, nullptr, "(sig-val(rsa(s %b)))",
112 signature.size(), signature.data());
113 if (error != GPG_ERR_NO_ERROR) {
114 PAL::GCrypt::logError(error);
118 // Construct the data s-expression that contains PKCS#1-padded hashed data.
119 PAL::GCrypt::Handle<gcry_sexp_t> dataSexp;
121 auto shaAlgorithm = hashAlgorithmName(hashAlgorithmIdentifier);
125 error = gcry_sexp_build(&dataSexp, nullptr, "(data(flags pkcs1)(hash %s %b))",
126 *shaAlgorithm, dataHash.size(), dataHash.data());
127 if (error != GPG_ERR_NO_ERROR) {
128 PAL::GCrypt::logError(error);
133 // Perform the PK verification. We report success if there's no error returned, or
134 // a failure in any other case. OperationError should not be returned at this point.
135 error = gcry_pk_verify(signatureSexp, dataSexp, keySexp);
136 return { error == GPG_ERR_NO_ERROR };
139 void CryptoAlgorithmRSASSA_PKCS1_v1_5::platformSign(Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
143 [key = WTFMove(key), data = WTFMove(data), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
144 auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
146 auto output = gcryptSign(rsaKey.platformKey(), data, rsaKey.hashAlgorithmIdentifier());
148 // We should only dereference callbacks after being back to the Document/Worker threads.
150 [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
151 exceptionCallback(OperationError);
157 // We should only dereference callbacks after being back to the Document/Worker threads.
159 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
166 void CryptoAlgorithmRSASSA_PKCS1_v1_5::platformVerify(Ref<CryptoKey>&& key, Vector<uint8_t>&& signature, Vector<uint8_t>&& data, BoolCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
170 [key = WTFMove(key), signature = WTFMove(signature), data = WTFMove(data), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
171 auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
173 auto output = gcryptVerify(rsaKey.platformKey(), signature, data, rsaKey.hashAlgorithmIdentifier());
175 // We should only dereference callbacks after being back to the Document/Worker threads.
177 [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
178 exceptionCallback(OperationError);
184 // We should only dereference callbacks after being back to the Document/Worker threads.
186 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
193 ExceptionOr<void> CryptoAlgorithmRSASSA_PKCS1_v1_5::platformSign(const CryptoAlgorithmRsaSsaParamsDeprecated&, const CryptoKeyRSA&, const CryptoOperationData&, VectorCallback&&, VoidCallback&&)
196 return Exception { NOT_SUPPORTED_ERR };
199 ExceptionOr<void> CryptoAlgorithmRSASSA_PKCS1_v1_5::platformVerify(const CryptoAlgorithmRsaSsaParamsDeprecated&, const CryptoKeyRSA&, const CryptoOperationData&, const CryptoOperationData&, BoolCallback&&, VoidCallback&&)
202 return Exception { NOT_SUPPORTED_ERR };
205 } // namespace WebCore
207 #endif // ENABLE(SUBTLE_CRYPTO)