Commit a3d6e70d authored by ap@apple.com's avatar ap@apple.com

Add support for WebCrypto RSA-OAEP

https://bugs.webkit.org/show_bug.cgi?id=125084

Reviewed by Sam Weinig.

Source/WebCore: 

Tests: crypto/subtle/rsa-oaep-key-manipulation.html
       crypto/subtle/rsa-oaep-plaintext-length.html
       crypto/subtle/rsa-oaep-wrap-unwrap-aes.html

* WebCore.xcodeproj/project.pbxproj: Added new files.

* bindings/js/JSCryptoAlgorithmDictionary.cpp:
(WebCore::createRsaOaepParams):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForEncrypt):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForDecrypt):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForImportKey):
Added RSA-OAEP parameters.

* bindings/js/JSCryptoKeySerializationJWK.cpp:
(WebCore::JSCryptoKeySerializationJWK::reconcileAlgorithm):
(WebCore::JSCryptoKeySerializationJWK::keySizeIsValid):
(WebCore::JSCryptoKeySerializationJWK::addJWKAlgorithmToJSON):
Support RSA-OAEP in JWK. It is more limited than general WebCrypto, as JWK only
allows SHA-1 as hash.

* crypto/CommonCryptoUtilities.cpp: Added. (WebCore::getCommonCryptoDigestAlgorithm):
* crypto/CommonCryptoUtilities.h: Added.
Extracted some shared code and forward declarations for CommonCrypto.

* crypto/CryptoAlgorithmParameters.h: (WebCore::CryptoAlgorithmParameters::Class):
* crypto/parameters/CryptoAlgorithmRsaOaepParams.h: Added.
Added RsaOaepParams.

* crypto/algorithms/CryptoAlgorithmRSA_OAEP.cpp: Added.
* crypto/algorithms/CryptoAlgorithmRSA_OAEP.h: Added.
* crypto/mac/CryptoAlgorithmRSA_OAEPMac.cpp: Added.

* crypto/mac/CryptoAlgorithmHMACMac.cpp:
(WebCore::getCommonCryptoHMACAlgorithm):
(WebCore::CryptoAlgorithmHMAC::platformSign):
(WebCore::CryptoAlgorithmHMAC::platformVerify):
* crypto/mac/CryptoAlgorithmRSASSA_PKCS1_v1_5Mac.cpp:
* crypto/mac/CryptoKeyMac.cpp:
* crypto/mac/CryptoKeyRSAMac.cpp:
Use CommonCryptoUtilities.

* crypto/mac/CryptoAlgorithmRegistryMac.cpp:
(WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms): Register RSA-OAEP.

LayoutTests: 

* crypto/subtle/rsa-oaep-key-manipulation-expected.txt: Added.
* crypto/subtle/rsa-oaep-key-manipulation.html: Added.
* crypto/subtle/rsa-oaep-plaintext-length-expected.txt: Added.
* crypto/subtle/rsa-oaep-plaintext-length.html: Added.
* crypto/subtle/rsa-oaep-wrap-unwrap-aes-expected.txt: Added.
* crypto/subtle/rsa-oaep-wrap-unwrap-aes.html: Added.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159944 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 0309686b
2013-12-02 Alexey Proskuryakov <ap@apple.com>
Add support for WebCrypto RSA-OAEP
https://bugs.webkit.org/show_bug.cgi?id=125084
Reviewed by Sam Weinig.
* crypto/subtle/rsa-oaep-key-manipulation-expected.txt: Added.
* crypto/subtle/rsa-oaep-key-manipulation.html: Added.
* crypto/subtle/rsa-oaep-plaintext-length-expected.txt: Added.
* crypto/subtle/rsa-oaep-plaintext-length.html: Added.
* crypto/subtle/rsa-oaep-wrap-unwrap-aes-expected.txt: Added.
* crypto/subtle/rsa-oaep-wrap-unwrap-aes.html: Added.
2013-12-01 Filip Pizlo <fpizlo@apple.com>
Stores to local captured variables should be intercepted
......
Test generating, importing and exporting RSA keys for RSA-OAEP. Test that they can't be used with another algorithm.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Generating a key pair...
PASS keyPair.toString() is '[object KeyPair]'
PASS keyPair.publicKey.type is 'public'
PASS keyPair.publicKey.algorithm.name is 'rsa-oaep'
PASS keyPair.publicKey.algorithm.modulusLength is 2048
PASS bytesToHexString(keyPair.publicKey.algorithm.publicExponent) is '010001'
PASS keyPair.publicKey.algorithm.hash is undefined.
PASS keyPair.privateKey.type is 'private'
PASS keyPair.privateKey.algorithm.name is 'rsa-oaep'
PASS keyPair.privateKey.algorithm.modulusLength is 2048
PASS bytesToHexString(keyPair.privateKey.algorithm.publicExponent) is '010001'
PASS keyPair.privateKey.algorithm.hash is undefined.
Testing that the keys can't be used with different algorithms...
PASS crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, keyPair.privateKey, hexStringToUint8Array("00")) threw exception Error: NotSupportedError: DOM Exception 9.
PASS crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, keyPair.publicKey, hexStringToUint8Array("00")) threw exception Error: NotSupportedError: DOM Exception 9.
Trying to export keys to raw...
PASS Promise rejected for exporting public key
PASS Promise rejected for exporting private key
Exporting public key to JWK...
PASS jwkPublicKey.alg is 'RSA-OAEP'
PASS jwkPublicKey.extractable is true
PASS jwkPublicKey.use is 'enc'
PASS jwkPublicKey.kty is 'RSA'
PASS bytesToHexString(Base64URL.parse(jwkPublicKey.e)) is '010001'
Importing it back...
PASS exportedPublicKey.type is 'public'
PASS exportedPublicKey.algorithm.name is 'rsa-oaep'
PASS exportedPublicKey.algorithm.modulusLength is 2048
PASS bytesToHexString(exportedPublicKey.algorithm.publicExponent) is '010001'
PASS exportedPublicKey.algorithm.hash.name is 'sha-1'
PASS exportedPublicKey.extractable is true
PASS exportedPublicKey.usages is ['encrypt','decrypt','wrapKey','unwrapKey']
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
<script src="resources/common.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Test generating, importing and exporting RSA keys for RSA-OAEP. Test that they can't be used with another algorithm.");
jsTestIsAsync = true;
var algorithmKeyGen = {
name: "RSA-OAEP",
// RsaKeyGenParams
modulusLength: 2048,
publicExponent: new Uint8Array([0x01, 0x00, 0x01]), // Equivalent to 65537
};
var extractable = true;
debug("Generating a key pair...");
crypto.subtle.generateKey(algorithmKeyGen, extractable, ["encrypt", "decrypt", "wrapKey", "unwrapKey"]).then(function(result) {
keyPair = result;
shouldBe("keyPair.toString()", "'[object KeyPair]'");
shouldBe("keyPair.publicKey.type", "'public'");
shouldBe("keyPair.publicKey.algorithm.name", "'rsa-oaep'");
shouldBe("keyPair.publicKey.algorithm.modulusLength", "2048");
shouldBe("bytesToHexString(keyPair.publicKey.algorithm.publicExponent)", "'010001'");
shouldBeUndefined("keyPair.publicKey.algorithm.hash");
shouldBe("keyPair.privateKey.type", "'private'");
shouldBe("keyPair.privateKey.algorithm.name", "'rsa-oaep'");
shouldBe("keyPair.privateKey.algorithm.modulusLength", "2048");
shouldBe("bytesToHexString(keyPair.privateKey.algorithm.publicExponent)", "'010001'");
shouldBeUndefined("keyPair.privateKey.algorithm.hash");
debug("\nTesting that the keys can't be used with different algorithms...");
iv = hexStringToUint8Array("000102030405060708090a0b0c0d0e0f");
shouldThrow('crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, keyPair.privateKey, hexStringToUint8Array("00"))');
shouldThrow('crypto.subtle.encrypt({name: "aes-cbc", iv: iv}, keyPair.publicKey, hexStringToUint8Array("00"))');
debug("\nTrying to export keys to raw...");
return crypto.subtle.exportKey('raw', keyPair.publicKey);
}).then(undefined, function(result) {
testPassed("Promise rejected for exporting public key");
return crypto.subtle.exportKey('raw', keyPair.privateKey);
}).then(undefined, function(result) {
testPassed("Promise rejected for exporting private key");
debug("\nExporting public key to JWK...");
return crypto.subtle.exportKey("jwk", keyPair.publicKey);
}).then(function(result) {
jwkPublicKeyArray = result;
jwkPublicKey = JSON.parse(bytesToASCIIString(jwkPublicKeyArray));
shouldBe("jwkPublicKey.alg", "'RSA-OAEP'");
shouldBe("jwkPublicKey.extractable", "true");
shouldBe("jwkPublicKey.use", "'enc'");
shouldBe("jwkPublicKey.kty", "'RSA'");
shouldBe("bytesToHexString(Base64URL.parse(jwkPublicKey.e))", "'010001'");
debug("\nImporting it back...");
return crypto.subtle.importKey("jwk", jwkPublicKeyArray, null, extractable, ["encrypt", "decrypt", "wrapKey", "unwrapKey"]);
}).then(function(result) {
exportedPublicKey = result;
shouldBe("exportedPublicKey.type", "'public'");
shouldBe("exportedPublicKey.algorithm.name", "'rsa-oaep'");
shouldBe("exportedPublicKey.algorithm.modulusLength", "2048");
shouldBe("bytesToHexString(exportedPublicKey.algorithm.publicExponent)", "'010001'");
shouldBe("exportedPublicKey.algorithm.hash.name", "'sha-1'");
shouldBe("exportedPublicKey.extractable", "true");
shouldBe("exportedPublicKey.usages", "['encrypt','decrypt','wrapKey','unwrapKey']");
finishJSTest();
});
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
Test what happens when trying to encrypt a too large plain text with RSA-OAEP.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Importing RSA keys...
Encrypting a 214 byte buffer with RSA-OAEP SHA-1, 2048 bit key...
PASS Succeeded
Encrypting a 215 byte buffer...
PASS Rejected
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
<script src="resources/common.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Test what happens when trying to encrypt a too large plain text with RSA-OAEP.");
jsTestIsAsync = true;
var publicKeyJSON = {
kty: "RSA",
alg: "RSA-OAEP",
n: "rcCUCv7Oc1HVam1DIhCzqknThWawOp8QLk8Ziy2p10ByjQFCajoFiyuAWl-R1WXZaf4xitLRracT9agpzIzc-MbLSHIGgWQGO21lGiImy5ftZ-D8bHAqRz2y15pzD4c4CEou7XSSLDoRnR0QG5MsDhD6s2gV9mwHkrtkCxtMWdBi-77as8wGmlNRldcOSgZDLK8UnCSgA1OguZ989bFyc8tOOEIb0xUSfPSz3LPSCnyYz68aDjmKVeNH-ig857OScyWbGyEy3Biw64qun3juUlNWsJ3zngkOdteYWytx5Qr4XKNs6R-Myyq72KUp02mJDZiiyiglxML_i3-_CeecCw",
e: "AQAB"
};
var privateKeyJSON = {
kty: "RSA",
alg: "RSA-OAEP",
n: "rcCUCv7Oc1HVam1DIhCzqknThWawOp8QLk8Ziy2p10ByjQFCajoFiyuAWl-R1WXZaf4xitLRracT9agpzIzc-MbLSHIGgWQGO21lGiImy5ftZ-D8bHAqRz2y15pzD4c4CEou7XSSLDoRnR0QG5MsDhD6s2gV9mwHkrtkCxtMWdBi-77as8wGmlNRldcOSgZDLK8UnCSgA1OguZ989bFyc8tOOEIb0xUSfPSz3LPSCnyYz68aDjmKVeNH-ig857OScyWbGyEy3Biw64qun3juUlNWsJ3zngkOdteYWytx5Qr4XKNs6R-Myyq72KUp02mJDZiiyiglxML_i3-_CeecCw",
e: "AQAB",
d: "eNLS37aCz7RXSNPD_DtLBJ6j5T8cSxdzRBCjPaI6WcGqJp16lq3UTwuoDLAqlA9oGYm238dsIWpuucP_lQtbWe-7SpxoI6_vmYGf7YVUHv1-DF9qiOmSrMmdxMnVOzYXY8RaT6thPjn_J5cfLV2xI_LwsrMtmpdSyNlgX0zTUhwtuahgAKMEChYjH2EnjHdHw6sY2-wApdcQI7ULE0oo5RzbQZpmuhcN9hiBc0L3hhF0qo50mbl02_65_GQ7DpVkXBxNgRBLzlPabmzzG2oAhfefLgYmSC1opaCkXE6vRWQNWNL45RZNZFYM3uoJghOMqGeocM0BpjdChHrPOlFvSQ",
p: "4miTuAjKMeH5uJ5KB397QUwhbkYEgSbcA2mifmSkvE2018gb55qkBHK1eVryf1_m43LNlc6O_ak6gfzdZIZvS5NCGjPl0q09plUpu8qFOSspBwA67qGH76lFlZLn_d4yglS7wfLru4_5Ys8qLLs-DqVLviwposOnyyWqwM5AXp0",
q: "xHYrzkivtmnz_sGchnWGc0q-pDOkKicptRpv2pMFIIXxnFX5aMeEXIZjVujXtwUy1UlFIN2GZJSvy5KJ79mu_XyNnFHMzedH-A3ee3u8h1UUrZF-vUu1_e4U_x67NN1dedzUSKynN7pFl3OkuShMBWGV-cwzOPdcVAfVuZlxUMc",
dp: "fBzDzYDUBmBQGop7Hn0dvf_T27V6RqpctWo074CQZcFbP2atFVtKSj3viWT3xid2VHzcgiDHdfpM3nEVlEO1wwIonGCSvdjGEOZiiFVOjrZAOVxA8guOjyyFvqbXke06VwPIIVvfKeSU2zuhbP__1tt6F_fxow4Kb2xonGT0GGk",
dq: "jmE2DiIPdhwDgLXAQpIaBqQ81bO3XfVT_LRULAwwwwlPuQV148H04zlh9TJ6Y2GZHYokV1U0eOBpJxfkb7dLYtpJpuiBjRf4yIUEoGlkkI_QlJnFSFr-YjGRdfNHqWBkxlSMZL770R9mIATndGkH7z5x-r9KwBZFC4FCG2hg_zE",
qi: "YCX_pLwbMBA1ThVH0WcwmnytqNcrMCEwTm7ByA2eU6nWbQrULvf7m9_kzfLUcjsnpAVlBQG5JMXMy0Sq4ptwbywsa5-G8KAOOOR2L3v4hC-Eys9ftgFM_3i0o40eeQH4b3haPbntrIeMg8IzlOuVYKf9-2QuKDoWeRdd7NsdxTk"
};
var encryptAlgorithm = {name: "RSA-OAEP", hash: "sha-1"};
var extractable = true;
var nonExtractable = false;
debug("Importing RSA keys...");
crypto.subtle.importKey("jwk", asciiToUint8Array(JSON.stringify(publicKeyJSON)), null, extractable, ["encrypt", "decrypt"]).then(function(result) {
publicKey = result;
return crypto.subtle.importKey("jwk", asciiToUint8Array(JSON.stringify(privateKeyJSON)), null, extractable, ["encrypt", "decrypt"]);
}).then(function(result) {
privateKey = result;
debug("Encrypting a 214 byte buffer with RSA-OAEP SHA-1, 2048 bit key...");
return crypto.subtle.encrypt({name: "RSA-OAEP", hash: "SHA-1"}, publicKey, new Uint8Array(214));
}).then(function(result) {
testPassed("Succeeded");
debug("Encrypting a 215 byte buffer...");
return crypto.subtle.encrypt({name: "RSA-OAEP", hash: "SHA-1"}, publicKey, new Uint8Array(215));
}).then(function(result) {
testFailed("Succeeded");
finishJSTest();
}, function(result) {
testPassed("Rejected");
finishJSTest();
});
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
Test wrapping and unwrapping AES keys with RSA-OAEP.
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
Importing RSA keys...
Importing an AES key...
Wrapping it...
PASS wrappedKey.toString() is '[object ArrayBuffer]'
Unwrapping it...
PASS unwrappedKey.toString() is '[object Key]'
PASS unwrappedKey.type is 'secret'
PASS unwrappedKey.extractable is true
PASS unwrappedKey.algorithm.name is 'aes-cbc'
PASS unwrappedKey.algorithm.length is 256
PASS unwrappedKey.usages is ['encrypt', 'decrypt']
Exporting it...
PASS bytesToHexString(unwrappedKeyData) is bytesToHexString(aesKeyData)
Wrapping the same key as JWK...
PASS wrappedKey.toString() is '[object ArrayBuffer]'
Unwrapping it...
PASS unwrappedKey.toString() is '[object Key]'
PASS unwrappedKey.type is 'secret'
PASS unwrappedKey.extractable is true
PASS unwrappedKey.algorithm.name is 'aes-cbc'
PASS unwrappedKey.algorithm.length is 256
PASS unwrappedKey.usages is ['encrypt', 'decrypt']
Exporting it...
PASS bytesToHexString(unwrappedKeyData) is bytesToHexString(aesKeyData)
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE html>
<html>
<head>
<script src="../../resources/js-test-pre.js"></script>
<script src="resources/common.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
description("Test wrapping and unwrapping AES keys with RSA-OAEP.");
jsTestIsAsync = true;
var publicKeyJSON = {
kty: "RSA",
alg: "RSA-OAEP",
n: "rcCUCv7Oc1HVam1DIhCzqknThWawOp8QLk8Ziy2p10ByjQFCajoFiyuAWl-R1WXZaf4xitLRracT9agpzIzc-MbLSHIGgWQGO21lGiImy5ftZ-D8bHAqRz2y15pzD4c4CEou7XSSLDoRnR0QG5MsDhD6s2gV9mwHkrtkCxtMWdBi-77as8wGmlNRldcOSgZDLK8UnCSgA1OguZ989bFyc8tOOEIb0xUSfPSz3LPSCnyYz68aDjmKVeNH-ig857OScyWbGyEy3Biw64qun3juUlNWsJ3zngkOdteYWytx5Qr4XKNs6R-Myyq72KUp02mJDZiiyiglxML_i3-_CeecCw",
e: "AQAB"
};
var privateKeyJSON = {
kty: "RSA",
alg: "RSA-OAEP",
n: "rcCUCv7Oc1HVam1DIhCzqknThWawOp8QLk8Ziy2p10ByjQFCajoFiyuAWl-R1WXZaf4xitLRracT9agpzIzc-MbLSHIGgWQGO21lGiImy5ftZ-D8bHAqRz2y15pzD4c4CEou7XSSLDoRnR0QG5MsDhD6s2gV9mwHkrtkCxtMWdBi-77as8wGmlNRldcOSgZDLK8UnCSgA1OguZ989bFyc8tOOEIb0xUSfPSz3LPSCnyYz68aDjmKVeNH-ig857OScyWbGyEy3Biw64qun3juUlNWsJ3zngkOdteYWytx5Qr4XKNs6R-Myyq72KUp02mJDZiiyiglxML_i3-_CeecCw",
e: "AQAB",
d: "eNLS37aCz7RXSNPD_DtLBJ6j5T8cSxdzRBCjPaI6WcGqJp16lq3UTwuoDLAqlA9oGYm238dsIWpuucP_lQtbWe-7SpxoI6_vmYGf7YVUHv1-DF9qiOmSrMmdxMnVOzYXY8RaT6thPjn_J5cfLV2xI_LwsrMtmpdSyNlgX0zTUhwtuahgAKMEChYjH2EnjHdHw6sY2-wApdcQI7ULE0oo5RzbQZpmuhcN9hiBc0L3hhF0qo50mbl02_65_GQ7DpVkXBxNgRBLzlPabmzzG2oAhfefLgYmSC1opaCkXE6vRWQNWNL45RZNZFYM3uoJghOMqGeocM0BpjdChHrPOlFvSQ",
p: "4miTuAjKMeH5uJ5KB397QUwhbkYEgSbcA2mifmSkvE2018gb55qkBHK1eVryf1_m43LNlc6O_ak6gfzdZIZvS5NCGjPl0q09plUpu8qFOSspBwA67qGH76lFlZLn_d4yglS7wfLru4_5Ys8qLLs-DqVLviwposOnyyWqwM5AXp0",
q: "xHYrzkivtmnz_sGchnWGc0q-pDOkKicptRpv2pMFIIXxnFX5aMeEXIZjVujXtwUy1UlFIN2GZJSvy5KJ79mu_XyNnFHMzedH-A3ee3u8h1UUrZF-vUu1_e4U_x67NN1dedzUSKynN7pFl3OkuShMBWGV-cwzOPdcVAfVuZlxUMc",
dp: "fBzDzYDUBmBQGop7Hn0dvf_T27V6RqpctWo074CQZcFbP2atFVtKSj3viWT3xid2VHzcgiDHdfpM3nEVlEO1wwIonGCSvdjGEOZiiFVOjrZAOVxA8guOjyyFvqbXke06VwPIIVvfKeSU2zuhbP__1tt6F_fxow4Kb2xonGT0GGk",
dq: "jmE2DiIPdhwDgLXAQpIaBqQ81bO3XfVT_LRULAwwwwlPuQV148H04zlh9TJ6Y2GZHYokV1U0eOBpJxfkb7dLYtpJpuiBjRf4yIUEoGlkkI_QlJnFSFr-YjGRdfNHqWBkxlSMZL770R9mIATndGkH7z5x-r9KwBZFC4FCG2hg_zE",
qi: "YCX_pLwbMBA1ThVH0WcwmnytqNcrMCEwTm7ByA2eU6nWbQrULvf7m9_kzfLUcjsnpAVlBQG5JMXMy0Sq4ptwbywsa5-G8KAOOOR2L3v4hC-Eys9ftgFM_3i0o40eeQH4b3haPbntrIeMg8IzlOuVYKf9-2QuKDoWeRdd7NsdxTk"
};
var wrapAlgorithm = {name: "RSA-OAEP", hash: "sha-1"};
var extractable = true;
var nonExtractable = false;
debug("Importing RSA keys...");
crypto.subtle.importKey("jwk", asciiToUint8Array(JSON.stringify(publicKeyJSON)), null, extractable, ["wrapKey", "unwrapKey"]).then(function(result) {
publicKey = result;
return crypto.subtle.importKey("jwk", asciiToUint8Array(JSON.stringify(privateKeyJSON)), null, extractable, ["wrapKey", "unwrapKey"]);
}).then(function(result) {
privateKey = result;
debug("Importing an AES key...");
aesKeyData = hexStringToUint8Array("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
return crypto.subtle.importKey("raw", aesKeyData, "aes-cbc", extractable, ["encrypt", "decrypt", "wrapKey", "unwrapKey"])
}).then(function(result) {
aesKey = result;
debug("Wrapping it...");
return crypto.subtle.wrapKey("raw", aesKey, publicKey, wrapAlgorithm);
}).then(function(result) {
wrappedKey = result;
shouldBe("wrappedKey.toString()", "'[object ArrayBuffer]'");
debug("Unwrapping it...");
return crypto.subtle.unwrapKey("raw", wrappedKey, privateKey, wrapAlgorithm, "aes-cbc", extractable, ["encrypt", "decrypt"]);
}).then(function(result) {
unwrappedKey = result;
shouldBe("unwrappedKey.toString()", "'[object Key]'");
shouldBe("unwrappedKey.type", "'secret'");
shouldBe("unwrappedKey.extractable", "true");
shouldBe("unwrappedKey.algorithm.name", "'aes-cbc'");
shouldBe("unwrappedKey.algorithm.length", "256");
shouldBe("unwrappedKey.usages", "['encrypt', 'decrypt']");
debug("Exporting it...");
return crypto.subtle.exportKey("raw", unwrappedKey);
}).then(function(result) {
unwrappedKeyData = result;
shouldBe("bytesToHexString(unwrappedKeyData)", "bytesToHexString(aesKeyData)");
debug("\nWrapping the same key as JWK...");
return crypto.subtle.wrapKey("jwk", aesKey, publicKey, wrapAlgorithm);
}).then(function(result) {
wrappedKey = result;
shouldBe("wrappedKey.toString()", "'[object ArrayBuffer]'");
debug("Unwrapping it...");
return crypto.subtle.unwrapKey("jwk", wrappedKey, privateKey, wrapAlgorithm, "aes-cbc", extractable, ["encrypt", "decrypt"]);
}).then(function(result) {
unwrappedKey = result;
shouldBe("unwrappedKey.toString()", "'[object Key]'");
shouldBe("unwrappedKey.type", "'secret'");
shouldBe("unwrappedKey.extractable", "true");
shouldBe("unwrappedKey.algorithm.name", "'aes-cbc'");
shouldBe("unwrappedKey.algorithm.length", "256");
shouldBe("unwrappedKey.usages", "['encrypt', 'decrypt']");
debug("Exporting it...");
return crypto.subtle.exportKey("raw", unwrappedKey);
}).then(function(result) {
unwrappedKeyData = result;
shouldBe("bytesToHexString(unwrappedKeyData)", "bytesToHexString(aesKeyData)");
finishJSTest();
});
</script>
<script src="../../resources/js-test-post.js"></script>
</body>
</html>
2013-12-02 Alexey Proskuryakov <ap@apple.com>
Add support for WebCrypto RSA-OAEP
https://bugs.webkit.org/show_bug.cgi?id=125084
Reviewed by Sam Weinig.
Tests: crypto/subtle/rsa-oaep-key-manipulation.html
crypto/subtle/rsa-oaep-plaintext-length.html
crypto/subtle/rsa-oaep-wrap-unwrap-aes.html
* WebCore.xcodeproj/project.pbxproj: Added new files.
* bindings/js/JSCryptoAlgorithmDictionary.cpp:
(WebCore::createRsaOaepParams):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForEncrypt):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForDecrypt):
(WebCore::JSCryptoAlgorithmDictionary::createParametersForImportKey):
Added RSA-OAEP parameters.
* bindings/js/JSCryptoKeySerializationJWK.cpp:
(WebCore::JSCryptoKeySerializationJWK::reconcileAlgorithm):
(WebCore::JSCryptoKeySerializationJWK::keySizeIsValid):
(WebCore::JSCryptoKeySerializationJWK::addJWKAlgorithmToJSON):
Support RSA-OAEP in JWK. It is more limited than general WebCrypto, as JWK only
allows SHA-1 as hash.
* crypto/CommonCryptoUtilities.cpp: Added. (WebCore::getCommonCryptoDigestAlgorithm):
* crypto/CommonCryptoUtilities.h: Added.
Extracted some shared code and forward declarations for CommonCrypto.
* crypto/CryptoAlgorithmParameters.h: (WebCore::CryptoAlgorithmParameters::Class):
* crypto/parameters/CryptoAlgorithmRsaOaepParams.h: Added.
Added RsaOaepParams.
* crypto/algorithms/CryptoAlgorithmRSA_OAEP.cpp: Added.
* crypto/algorithms/CryptoAlgorithmRSA_OAEP.h: Added.
* crypto/mac/CryptoAlgorithmRSA_OAEPMac.cpp: Added.
* crypto/mac/CryptoAlgorithmHMACMac.cpp:
(WebCore::getCommonCryptoHMACAlgorithm):
(WebCore::CryptoAlgorithmHMAC::platformSign):
(WebCore::CryptoAlgorithmHMAC::platformVerify):
* crypto/mac/CryptoAlgorithmRSASSA_PKCS1_v1_5Mac.cpp:
* crypto/mac/CryptoKeyMac.cpp:
* crypto/mac/CryptoKeyRSAMac.cpp:
Use CommonCryptoUtilities.
* crypto/mac/CryptoAlgorithmRegistryMac.cpp:
(WebCore::CryptoAlgorithmRegistry::platformRegisterAlgorithms): Register RSA-OAEP.
2013-12-02 Andres Gomez <agomez@igalia.com>
[GTK] Fails to build with freetype 2.5.1
......@@ -5728,6 +5728,12 @@
E1F80B8E183172B5007885C3 /* JSCryptoKeyPair.h in Headers */ = {isa = PBXBuildFile; fileRef = E1F80B8C183172B5007885C3 /* JSCryptoKeyPair.h */; };
E1FE13641834351100892F13 /* CryptoDigestMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FE13621834351100892F13 /* CryptoDigestMac.cpp */; };
E1FE136718343A1000892F13 /* CryptoDigest.h in Headers */ = {isa = PBXBuildFile; fileRef = E1FE136618343A1000892F13 /* CryptoDigest.h */; };
E1FE136A183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FE1368183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.cpp */; };
E1FE136B183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.h in Headers */ = {isa = PBXBuildFile; fileRef = E1FE1369183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.h */; };
E1FE136D183FE21D00892F13 /* CryptoAlgorithmRsaOaepParams.h in Headers */ = {isa = PBXBuildFile; fileRef = E1FE136C183FE21D00892F13 /* CryptoAlgorithmRsaOaepParams.h */; };
E1FE1370183FECF000892F13 /* CryptoAlgorithmRSA_OAEPMac.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FE136E183FECF000892F13 /* CryptoAlgorithmRSA_OAEPMac.cpp */; };
E1FE137418402A6700892F13 /* CommonCryptoUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FE137218402A6700892F13 /* CommonCryptoUtilities.cpp */; };
E1FE137518402A6700892F13 /* CommonCryptoUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = E1FE137318402A6700892F13 /* CommonCryptoUtilities.h */; };
E1FF57A30F01255B00891EBB /* ThreadGlobalData.h in Headers */ = {isa = PBXBuildFile; fileRef = E1FF57A20F01255B00891EBB /* ThreadGlobalData.h */; settings = {ATTRIBUTES = (Private, ); }; };
E1FF57A60F01256B00891EBB /* ThreadGlobalData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FF57A50F01256B00891EBB /* ThreadGlobalData.cpp */; };
E1FF8F5F1807442100132674 /* SubtleCrypto.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1FF8F5D1807442100132674 /* SubtleCrypto.cpp */; };
......@@ -12848,6 +12854,12 @@
E1F80B8C183172B5007885C3 /* JSCryptoKeyPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCryptoKeyPair.h; sourceTree = "<group>"; };
E1FE13621834351100892F13 /* CryptoDigestMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoDigestMac.cpp; path = mac/CryptoDigestMac.cpp; sourceTree = "<group>"; };
E1FE136618343A1000892F13 /* CryptoDigest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoDigest.h; sourceTree = "<group>"; };
E1FE1368183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoAlgorithmRSA_OAEP.cpp; sourceTree = "<group>"; };
E1FE1369183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoAlgorithmRSA_OAEP.h; sourceTree = "<group>"; };
E1FE136C183FE21D00892F13 /* CryptoAlgorithmRsaOaepParams.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoAlgorithmRsaOaepParams.h; path = parameters/CryptoAlgorithmRsaOaepParams.h; sourceTree = "<group>"; };
E1FE136E183FECF000892F13 /* CryptoAlgorithmRSA_OAEPMac.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CryptoAlgorithmRSA_OAEPMac.cpp; path = mac/CryptoAlgorithmRSA_OAEPMac.cpp; sourceTree = "<group>"; };
E1FE137218402A6700892F13 /* CommonCryptoUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CommonCryptoUtilities.cpp; sourceTree = "<group>"; };
E1FE137318402A6700892F13 /* CommonCryptoUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommonCryptoUtilities.h; sourceTree = "<group>"; };
E1FF57A20F01255B00891EBB /* ThreadGlobalData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadGlobalData.h; sourceTree = "<group>"; };
E1FF57A50F01256B00891EBB /* ThreadGlobalData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadGlobalData.cpp; sourceTree = "<group>"; };
E1FF8F5C1807364B00132674 /* SubtleCrypto.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = SubtleCrypto.idl; sourceTree = "<group>"; };
......@@ -20406,10 +20418,13 @@
E172AF71180F343400FBADB9 /* mac */ = {
isa = PBXGroup;
children = (
E1FE137218402A6700892F13 /* CommonCryptoUtilities.cpp */,
E1FE137318402A6700892F13 /* CommonCryptoUtilities.h */,
E125F843182425C900D84CD9 /* CryptoAlgorithmAES_CBCMac.cpp */,
E125F8371822F1EB00D84CD9 /* CryptoAlgorithmHMACMac.cpp */,
E1BB84AC1822CA7400525043 /* CryptoAlgorithmRegistryMac.cpp */,
E1C266D618317AB4003F8B33 /* CryptoAlgorithmRSASSA_PKCS1_v1_5Mac.cpp */,
E1FE136E183FECF000892F13 /* CryptoAlgorithmRSA_OAEPMac.cpp */,
E19AC3F8182566F700349426 /* CryptoKeyMac.cpp */,
E164FAA418315E1A00DB4E61 /* CryptoKeyRSAMac.cpp */,
E1FE13621834351100892F13 /* CryptoDigestMac.cpp */,
......@@ -20424,6 +20439,8 @@
E125F8401824253A00D84CD9 /* CryptoAlgorithmAES_CBC.h */,
E125F82F1822F11B00D84CD9 /* CryptoAlgorithmHMAC.cpp */,
E125F8301822F11B00D84CD9 /* CryptoAlgorithmHMAC.h */,
E1FE1368183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.cpp */,
E1FE1369183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.h */,
E1BD3317182D8DDD00C05D9F /* CryptoAlgorithmRSASSA_PKCS1_v1_5.cpp */,
E1BD3318182D8DDD00C05D9F /* CryptoAlgorithmRSASSA_PKCS1_v1_5.h */,
E125F8291822CFEC00D84CD9 /* CryptoAlgorithmSHA1.cpp */,
......@@ -22437,6 +22454,7 @@
1C4C8F020AD85D87009475CE /* DeleteButtonController.h in Headers */,
93309DDF099E64920056E581 /* DeleteFromTextNodeCommand.h in Headers */,
07C59B6417F4D1C4000FBCBB /* MockMediaStreamCenter.h in Headers */,
E1FE136B183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.h in Headers */,
93309DE1099E64920056E581 /* DeleteSelectionCommand.h in Headers */,
FD1660A513787C6D001FFA7B /* DenormalDisabler.h in Headers */,
E100EE761546EAC100BA11D1 /* DeprecatedStyleBuilder.h in Headers */,
......@@ -22586,6 +22604,7 @@
BC00F0090E0A185500FD04E3 /* DOMFileListInternal.h in Headers */,
2ED609BD1145B07100C8684E /* DOMFormData.h in Headers */,
BC1A37B6097C715F0019F3D8 /* DOMHTML.h in Headers */,
E1FE137518402A6700892F13 /* CommonCryptoUtilities.h in Headers */,
85DF81270AA7787200486AD7 /* DOMHTMLAnchorElement.h in Headers */,
B595FF471824CEE300FF51CD /* RenderIterator.h in Headers */,
85E7119B0AC5D5350053270F /* DOMHTMLAnchorElementInternal.h in Headers */,
......@@ -23706,6 +23725,7 @@
E19AC3EF1824DC7900349426 /* CryptoAlgorithmSHA224.h in Headers */,
078E092B17D14D1C00420AA1 /* RTCStatsRequestImpl.h in Headers */,
B266CD4E0C3AEC6500EB08D2 /* JSSVGException.h in Headers */,
E1FE136D183FE21D00892F13 /* CryptoAlgorithmRsaOaepParams.h in Headers */,
B2FA3D6B0AB75A6F000E5AC4 /* JSSVGFEBlendElement.h in Headers */,
B2FA3D6D0AB75A6F000E5AC4 /* JSSVGFEColorMatrixElement.h in Headers */,
B2FA3D6F0AB75A6F000E5AC4 /* JSSVGFEComponentTransferElement.h in Headers */,
......@@ -26712,6 +26732,7 @@
1403BA0C09EB18C700797C7F /* JSDOMWindow.cpp in Sources */,
BC6932730D7E293900AE44D1 /* JSDOMWindowBase.cpp in Sources */,
BCD9C2620C17AA67005C90A2 /* JSDOMWindowCustom.cpp in Sources */,
E1FE136A183FE1AB00892F13 /* CryptoAlgorithmRSA_OAEP.cpp in Sources */,
BCBFB53C0DCD29CF0019B3E5 /* JSDOMWindowShell.cpp in Sources */,
FD7868B9136B999200D403DF /* JSDynamicsCompressorNode.cpp in Sources */,
65DF31F909D1CC60000BE325 /* JSElement.cpp in Sources */,
......@@ -28159,6 +28180,7 @@
1FAFBF1815A5FA6E00083A20 /* UTIUtilities.mm in Sources */,
2E3BBF071162DA1100B9409A /* UUID.cpp in Sources */,
50D32857163B313F0016111E /* ValidatedCustomFilterOperation.cpp in Sources */,
E1FE137418402A6700892F13 /* CommonCryptoUtilities.cpp in Sources */,
F5A154271279534D00D0B0C0 /* ValidationMessage.cpp in Sources */,
FD3160AE12B026F700C1A359 /* VectorMath.cpp in Sources */,
BE88E0DE1715D2A200658D98 /* VideoTrack.cpp in Sources */,
......@@ -28202,6 +28224,7 @@
01D3CF8414BD0A3000FE9970 /* WebGLContextObject.cpp in Sources */,
A0EE0DF5144F825500F80B0D /* WebGLDebugRendererInfo.cpp in Sources */,
A0EE0DF7144F825500F80B0D /* WebGLDebugShaders.cpp in Sources */,
E1FE1370183FECF000892F13 /* CryptoAlgorithmRSA_OAEPMac.cpp in Sources */,
6E3FAE8E14733FDB00E42307 /* WebGLDepthTexture.cpp in Sources */,
6EBF0E5412A8929800DB1709 /* WebGLExtension.cpp in Sources */,
49C7B9CE1042D32F0009D447 /* WebGLFramebuffer.cpp in Sources */,
......@@ -35,6 +35,7 @@
#include "CryptoAlgorithmRegistry.h"
#include "CryptoAlgorithmRsaKeyGenParams.h"
#include "CryptoAlgorithmRsaKeyParamsWithHash.h"
#include "CryptoAlgorithmRsaOaepParams.h"
#include "CryptoAlgorithmRsaSsaParams.h"
#include "ExceptionCode.h"
#include "JSCryptoOperationData.h"
......@@ -244,6 +245,40 @@ static std::unique_ptr<CryptoAlgorithmParameters> createRsaKeyParamsWithHash(Exe
return std::make_unique<CryptoAlgorithmRsaKeyParamsWithHash>();
}
static std::unique_ptr<CryptoAlgorithmParameters> createRsaOaepParams(ExecState* exec, JSValue value)
{
if (!value.isObject()) {
throwTypeError(exec);
return nullptr;
}
JSDictionary jsDictionary(exec, value.getObject());
auto result = std::make_unique<CryptoAlgorithmRsaOaepParams>();
if (!getHashAlgorithm(jsDictionary, result->hash)) {
ASSERT(exec->hadException());
return nullptr;
}
JSValue labelValue = getProperty(exec, value.getObject(), "label");
if (exec->hadException())
return nullptr;
result->hasLabel = !labelValue.isUndefinedOrNull();
if (!result->hasLabel)
return std::move(result);
CryptoOperationData labelData;
if (!cryptoOperationDataFromJSValue(exec, labelValue, labelData)) {
ASSERT(exec->hadException());
return nullptr;
}
result->label.append(labelData.first, labelData.second);
return std::move(result);
}
static std::unique_ptr<CryptoAlgorithmParameters> createRsaSsaParams(ExecState* exec, JSValue value)
{
if (!value.isObject()) {
......@@ -268,7 +303,10 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSA_PSS:
setDOMException(exec, NOT_SUPPORTED_ERR);
return nullptr;
case CryptoAlgorithmIdentifier::RSA_OAEP:
return createRsaOaepParams(exec, value);
case CryptoAlgorithmIdentifier::ECDSA:
case CryptoAlgorithmIdentifier::ECDH:
case CryptoAlgorithmIdentifier::AES_CTR:
......@@ -300,7 +338,10 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
case CryptoAlgorithmIdentifier::RSAES_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
case CryptoAlgorithmIdentifier::RSA_PSS:
setDOMException(exec, NOT_SUPPORTED_ERR);
return nullptr;
case CryptoAlgorithmIdentifier::RSA_OAEP:
return createRsaOaepParams(exec, value);
case CryptoAlgorithmIdentifier::ECDSA:
case CryptoAlgorithmIdentifier::ECDH:
case CryptoAlgorithmIdentifier::AES_CTR:
......@@ -528,7 +569,9 @@ std::unique_ptr<CryptoAlgorithmParameters> JSCryptoAlgorithmDictionary::createPa
case CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5:
return createRsaKeyParamsWithHash(exec, value);
case CryptoAlgorithmIdentifier::RSA_PSS:
return std::make_unique<CryptoAlgorithmParameters>();
case CryptoAlgorithmIdentifier::RSA_OAEP:
return createRsaKeyParamsWithHash(exec, value);
case CryptoAlgorithmIdentifier::ECDSA:
case CryptoAlgorithmIdentifier::ECDH:
case CryptoAlgorithmIdentifier::AES_CTR:
......
......@@ -190,6 +190,9 @@ bool JSCryptoKeySerializationJWK::reconcileAlgorithm(std::unique_ptr<CryptoAlgor
} else if (m_jwkAlgorithmName == "RS512") {
algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5);
parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_512);
} else if (m_jwkAlgorithmName == "RSA-OAEP") {
algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::RSA_OAEP);
parameters = createRSAKeyParametersWithHash(CryptoAlgorithmIdentifier::SHA_1);
} else if (m_jwkAlgorithmName == "A128CBC") {
algorithm = CryptoAlgorithmRegistry::shared().create(CryptoAlgorithmIdentifier::AES_CBC);
parameters = std::make_unique<CryptoAlgorithmParameters>();
......@@ -218,7 +221,8 @@ bool JSCryptoKeySerializationJWK::reconcileAlgorithm(std::unique_ptr<CryptoAlgor
if (algorithm->identifier() == CryptoAlgorithmIdentifier::HMAC)
return toCryptoAlgorithmHmacParams(*parameters).hash == toCryptoAlgorithmHmacParams(*suggestedParameters).hash;
if (algorithm->identifier() == CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5) {
if (algorithm->identifier() == CryptoAlgorithmIdentifier::RSASSA_PKCS1_v1_5
|| algorithm->identifier() == CryptoAlgorithmIdentifier::RSA_OAEP) {
CryptoAlgorithmRsaKeyParamsWithHash& rsaKeyParameters = toCryptoAlgorithmRsaKeyParamsWithHash(*parameters);
CryptoAlgorithmRsaKeyParamsWithHash& suggestedRSAKeyParameters = toCryptoAlgorithmRsaKeyParamsWithHash(*suggestedParameters);
ASSERT(rsaKeyParameters.hasHash);
......@@ -283,6 +287,8 @@ bool JSCryptoKeySerializationJWK::keySizeIsValid(size_t sizeInBits) const
return sizeInBits >= 2048;
if (m_jwkAlgorithmName == "RS512")
return sizeInBits >= 2048;
if (m_jwkAlgorithmName == "RSA_OAEP")
return sizeInBits >= 2048;
return true;
}
......@@ -538,6 +544,17 @@ void JSCryptoKeySerializationJWK::addJWKAlgorithmToJSON(ExecState* exec, JSObjec
}
break;
}
case CryptoAlgorithmIdentifier::RSA_OAEP: {
const CryptoKeyRSA& rsaKey = toCryptoKeyRSA(key);
CryptoAlgorithmIdentifier hash;
// WebCrypto RSA-OAEP keys are not tied to any particular hash, unless previously imported from JWK, which only supports SHA-1.
if (rsaKey.isRestrictedToHash(hash) && hash != CryptoAlgorithmIdentifier::SHA_1)
break;
if (rsaKey.keySizeInBits() < 2048)
break;
jwkAlgorithm = "RSA-OAEP";
break;
}
default:
break;
}
......
/*
* Copyright (C) 2013 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright