Source/WebCore/ChangeLog

112017-04-26 Zan Dobersek <zdobersek@igalia.com>
22
 3 [GCrypt] RSAES-PKCS1-v1_5 support
 4 https://bugs.webkit.org/show_bug.cgi?id=171219
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 Add RSAES-PKCS1-v1_5 support for configurations that use libgcrypt.
 9
 10 The encryption operation embeds the plain-text data into a data s-expression,
 11 specifying PKCS#1 as the padding method of choice. That's passed to the
 12 gcry_pk_encrypt() call together with the specified key. The returned enc-val
 13 expression contains the 'a' MPI from which the data is extracted and returned.
 14
 15 The decryption operation goes in reverse -- the cipher-text data is embedded
 16 into an enc-val s-expression that again also specifies PKCS#1 as the padding
 17 method. The s-expression is passed to gcry_pk_decrypt() together with the
 18 specified key. The returned data s-expression contains the decrypted text
 19 inside the 'value' parameter, so the data is extracted from that and returned
 20 to the caller.
 21
 22 No new tests -- the revelant tests are passing and are unskipped, apart from
 23 the ones using PKCS#8 and SPKI formats.
 24
 25 * crypto/gcrypt/CryptoAlgorithmRSAES_PKCS1_v1_5GCrypt.cpp:
 26 (WebCore::mpiData):
 27 (WebCore::gcryptEncrypt):
 28 (WebCore::gcryptDecrypt):
 29 (WebCore::CryptoAlgorithmRSAES_PKCS1_v1_5::platformEncrypt):
 30 (WebCore::CryptoAlgorithmRSAES_PKCS1_v1_5::platformDecrypt):
 31
 322017-04-26 Zan Dobersek <zdobersek@igalia.com>
 33
334 [GCrypt] CryptoKeyRSA: implement create(), keySizeInBits(), buildAlgorithm(), exportData()
435 https://bugs.webkit.org/show_bug.cgi?id=171213
536

Source/WebCore/crypto/gcrypt/CryptoAlgorithmRSAES_PKCS1_v1_5GCrypt.cpp

3131#include "CryptoKeyRSA.h"
3232#include "ExceptionCode.h"
3333#include "NotImplemented.h"
 34#include "ScriptExecutionContext.h"
 35#include <pal/crypto/gcrypt/Handle.h>
 36#include <pal/crypto/gcrypt/Utilities.h>
3437
3538namespace WebCore {
3639
37 void CryptoAlgorithmRSAES_PKCS1_v1_5::platformEncrypt(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&, ScriptExecutionContext&, WorkQueue&)
 40static std::optional<Vector<uint8_t>> mpiData(gcry_sexp_t paramSexp)
3841{
39  notImplemented();
 42 // Retrieve the MPI value stored in the s-expression: (name mpi-data)
 43 PAL::GCrypt::Handle<gcry_mpi_t> paramMPI(gcry_sexp_nth_mpi(paramSexp, 1, GCRYMPI_FMT_USG));
 44 if (!paramMPI)
 45 return std::nullopt;
 46
 47 // Query the data length first to properly prepare the buffer.
 48 size_t dataLength = 0;
 49 gcry_error_t error = gcry_mpi_print(GCRYMPI_FMT_USG, nullptr, 0, &dataLength, paramMPI);
 50 if (error != GPG_ERR_NO_ERROR) {
 51 PAL::GCrypt::logError(error);
 52 return std::nullopt;
 53 }
 54
 55 // Finally, copy the MPI data into a properly-sized buffer.
 56 Vector<uint8_t> output(dataLength);
 57 error = gcry_mpi_print(GCRYMPI_FMT_USG, output.data(), output.size(), nullptr, paramMPI);
 58 if (error != GPG_ERR_NO_ERROR) {
 59 PAL::GCrypt::logError(error);
 60 return std::nullopt;
 61 }
 62
 63 return output;
4064}
4165
42 void CryptoAlgorithmRSAES_PKCS1_v1_5::platformDecrypt(Ref<CryptoKey>&&, Vector<uint8_t>&&, VectorCallback&&, ExceptionCallback&&, ScriptExecutionContext&, WorkQueue&)
 66static std::optional<Vector<uint8_t>> gcryptEncrypt(gcry_sexp_t keySexp, Vector<uint8_t>&& plainText)
4367{
44  notImplemented();
 68 // Embed the plain-text data in a data s-expression using PKCS#1 padding.
 69 PAL::GCrypt::Handle<gcry_sexp_t> dataSexp;
 70 gcry_error_t error = gcry_sexp_build(&dataSexp, nullptr, "(data(flags pkcs1)(value %b))",
 71 plainText.size(), plainText.data());
 72 if (error != GPG_ERR_NO_ERROR) {
 73 PAL::GCrypt::logError(error);
 74 return std::nullopt;
 75 }
 76
 77 // Encrypt data with the provided key. The returned s-expression is of this form:
 78 // (enc-val
 79 // (rsa
 80 // (a a-mpi)))
 81 PAL::GCrypt::Handle<gcry_sexp_t> cipherSexp;
 82 error = gcry_pk_encrypt(&cipherSexp, dataSexp, keySexp);
 83 if (error != GPG_ERR_NO_ERROR) {
 84 PAL::GCrypt::logError(error);
 85 return std::nullopt;
 86 }
 87
 88 // Return MPI data of the embedded a integer.
 89 PAL::GCrypt::Handle<gcry_sexp_t> aSexp(gcry_sexp_find_token(cipherSexp, "a", 0));
 90 if (!aSexp)
 91 return std::nullopt;
 92
 93 return mpiData(aSexp);
 94}
 95
 96static std::optional<Vector<uint8_t>> gcryptDecrypt(gcry_sexp_t keySexp, Vector<uint8_t>&& cipherText)
 97{
 98 // Embed the cipher-text data in an enc-val s-expression using PKCS#1 padding.
 99 PAL::GCrypt::Handle<gcry_sexp_t> encValSexp;
 100 gcry_error_t error = gcry_sexp_build(&encValSexp, nullptr, "(enc-val(flags pkcs1)(rsa(a %b)))",
 101 cipherText.size(), cipherText.data());
 102 if (error != GPG_ERR_NO_ERROR) {
 103 PAL::GCrypt::logError(error);
 104 return std::nullopt;
 105 }
 106
 107 // Decrypt data with the provided key. The returned s-expression is of this form:
 108 // (data
 109 // (flags pkcs1)
 110 // (value block))
 111 PAL::GCrypt::Handle<gcry_sexp_t> plainSexp;
 112 error = gcry_pk_decrypt(&plainSexp, encValSexp, keySexp);
 113 if (error != GPG_ERR_NO_ERROR) {
 114 PAL::GCrypt::logError(error);
 115 return std::nullopt;
 116 }
 117
 118 // Return MPI data of the embedded value integer.
 119 PAL::GCrypt::Handle<gcry_sexp_t> valueSexp(gcry_sexp_find_token(plainSexp, "value", 0));
 120 if (!valueSexp)
 121 return std::nullopt;
 122
 123 return mpiData(valueSexp);
 124}
 125
 126void CryptoAlgorithmRSAES_PKCS1_v1_5::platformEncrypt(Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
 127{
 128 context.ref();
 129 workQueue.dispatch(
 130 [key = WTFMove(key), plainText = WTFMove(plainText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
 131 auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
 132
 133 auto output = gcryptEncrypt(rsaKey.platformKey(), WTFMove(plainText));
 134 if (!output) {
 135 // We should only dereference callbacks after being back to the Document/Worker threads.
 136 context.postTask(
 137 [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
 138 exceptionCallback(OperationError);
 139 context.deref();
 140 });
 141 return;
 142 }
 143
 144 // We should only dereference callbacks after being back to the Document/Worker threads.
 145 context.postTask(
 146 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) mutable {
 147 callback(WTFMove(output));
 148 context.deref();
 149 });
 150 });
 151}
 152
 153void CryptoAlgorithmRSAES_PKCS1_v1_5::platformDecrypt(Ref<CryptoKey>&& key, Vector<uint8_t>&& cipherText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
 154{
 155 context.ref();
 156 workQueue.dispatch(
 157 [key = WTFMove(key), cipherText = WTFMove(cipherText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
 158 auto& rsaKey = downcast<CryptoKeyRSA>(key.get());
 159
 160 auto output = gcryptDecrypt(rsaKey.platformKey(), WTFMove(cipherText));
 161 if (!output) {
 162 // We should only dereference callbacks after being back to the Document/Worker threads.
 163 context.postTask(
 164 [callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
 165 exceptionCallback(OperationError);
 166 context.deref();
 167 });
 168 return;
 169 }
 170
 171 // We should only dereference callbacks after being back to the Document/Worker threads.
 172 context.postTask(
 173 [output = WTFMove(*output), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) mutable {
 174 callback(WTFMove(output));
 175 context.deref();
 176 });
 177 });
45178}
46179
47180ExceptionOr<void> CryptoAlgorithmRSAES_PKCS1_v1_5::platformEncrypt(const CryptoKeyRSA&, const CryptoOperationData&, VectorCallback&&, VoidCallback&&)

LayoutTests/ChangeLog

 12017-04-26 Zan Dobersek <zdobersek@igalia.com>
 2
 3 [GCrypt] RSAES-PKCS1-v1_5 support
 4 https://bugs.webkit.org/show_bug.cgi?id=171219
 5
 6 Reviewed by NOBODY (OOPS!).
 7
 8 * platform/gtk/TestExpectations: Enable the RSAES-PKCS1-v1_5 layout tests that we pass.
 9
1102017-04-25 Joseph Pecoraro <pecoraro@apple.com>
211
312 [mac-wk1 Debug] LayoutTest http/tests/inspector/network/resource-sizes-network.html is a flaky failure

LayoutTests/platform/gtk/TestExpectations

@@crypto/subtle/hmac-import-raw-key-customized-length.html [ Pass ]
764764crypto/subtle/hmac-import-raw-key-export-jwk-key.html [ Pass ]
765765crypto/subtle/hmac-import-raw-key-export-raw-key.html [ Pass ]
766766crypto/subtle/hmac-import-raw-key.html [ Pass ]
 767crypto/subtle/rsaes-pkcs1-v1_5-generate-export-key-jwk.html [ Pass ]
 768crypto/subtle/rsaes-pkcs1-v1_5-generate-key-encrypt-decrypt.html [ Pass ]
 769crypto/subtle/rsaes-pkcs1-v1_5-generate-key-extractable.html [ Pass ]
 770crypto/subtle/rsaes-pkcs1-v1_5-generate-key.html [ Pass ]
 771crypto/subtle/rsaes-pkcs1-v1_5-import-jwk-private-key.html [ Pass ]
 772crypto/subtle/rsaes-pkcs1-v1_5-import-jwk-public-key-empty-usages.html [ Pass ]
 773crypto/subtle/rsaes-pkcs1-v1_5-import-jwk-public-key.html [ Pass ]
 774crypto/subtle/rsaes-pkcs1-v1_5-import-jwk-public-key-leading-zero.html [ Pass ]
 775crypto/subtle/rsaes-pkcs1-v1_5-import-jwk-public-key-minimum.html [ Pass ]
 776crypto/subtle/rsaes-pkcs1-v1_5-import-jwk-public-key-non-extractable.html [ Pass ]
 777crypto/subtle/rsaes-pkcs1-v1_5-import-key-decrypt.html [ Pass ]
 778crypto/subtle/rsaes-pkcs1-v1_5-import-key-encrypt.html [ Pass ]
767779webkit.org/b/133319 crypto/webkitSubtle/sha-1.html [ Pass ]
768780webkit.org/b/133319 crypto/webkitSubtle/sha-224.html [ Pass ]
769781webkit.org/b/133319 crypto/webkitSubtle/sha-256.html [ Pass ]