Diff
Modified: trunk/LayoutTests/ChangeLog (160028 => 160029)
--- trunk/LayoutTests/ChangeLog 2013-12-03 20:12:09 UTC (rev 160028)
+++ trunk/LayoutTests/ChangeLog 2013-12-03 20:18:14 UTC (rev 160029)
@@ -1,5 +1,15 @@
2013-12-03 Alexey Proskuryakov <[email protected]>
+ Support exporting private WebCrypto RSA keys
+ https://bugs.webkit.org/show_bug.cgi?id=124483
+
+ Reviewed by Anders Carlsson.
+
+ * crypto/subtle/rsa-export-private-key-expected.txt: Added.
+ * crypto/subtle/rsa-export-private-key.html: Added.
+
+2013-12-03 Alexey Proskuryakov <[email protected]>
+
WebCrypto HMAC doesn't check key algorithm's hash
https://bugs.webkit.org/show_bug.cgi?id=125114
Added: trunk/LayoutTests/crypto/subtle/rsa-export-private-key-expected.txt (0 => 160029)
--- trunk/LayoutTests/crypto/subtle/rsa-export-private-key-expected.txt (rev 0)
+++ trunk/LayoutTests/crypto/subtle/rsa-export-private-key-expected.txt 2013-12-03 20:18:14 UTC (rev 160029)
@@ -0,0 +1,26 @@
+Test exporting a private RSA key.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+Importing a JWK key...
+
+Exporting the key as JWK...
+PASS exportedJWK.kty is 'RSA'
+PASS exportedJWK.n is privateKeyJSON.n
+PASS exportedJWK.e is privateKeyJSON.e
+PASS exportedJWK.d is privateKeyJSON.d
+PASS exportedJWK.p is privateKeyJSON.p
+PASS exportedJWK.q is privateKeyJSON.q
+PASS exportedJWK.dp is privateKeyJSON.dp
+PASS exportedJWK.dq is privateKeyJSON.dq
+PASS exportedJWK.qi is privateKeyJSON.qi
+PASS exportedJWK.oth is privateKeyJSON.oth
+PASS exportedJWK.alg is privateKeyJSON.alg
+PASS exportedJWK.extractable is true
+PASS exportedJWK.use is 'sig'
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Property changes on: trunk/LayoutTests/crypto/subtle/rsa-export-private-key-expected.txt
___________________________________________________________________
Added: svn:mime-type
Added: svn:eol-style
Added: trunk/LayoutTests/crypto/subtle/rsa-export-private-key.html (0 => 160029)
--- trunk/LayoutTests/crypto/subtle/rsa-export-private-key.html (rev 0)
+++ trunk/LayoutTests/crypto/subtle/rsa-export-private-key.html 2013-12-03 20:18:14 UTC (rev 160029)
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+
+<script>
+description("Test exporting a private RSA key.");
+
+jsTestIsAsync = true;
+
+var extractable = true;
+var nonExtractable = false;
+
+// Example from JWK specification.
+var privateKeyJSON = {
+ "kty":"RSA",
+ "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
+ "e":"AQAB",
+ "d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q",
+ "p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs",
+ "q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk",
+ "dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0",
+ "dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk",
+ "qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU",
+ "alg":"RS256",
+ "kid":"2011-04-29"
+}
+var jwkKeyAsArrayBuffer = asciiToUint8Array(JSON.stringify(privateKeyJSON));
+
+debug("\nImporting a JWK key...");
+crypto.subtle.importKey("jwk", jwkKeyAsArrayBuffer, "RSASSA-PKCS1-v1_5", extractable, ['sign', 'verify']).then(function(result) {
+ key = result;
+
+ debug("\nExporting the key as JWK...");
+ return crypto.subtle.exportKey("jwk", key);
+}).then(function(result) {
+ exportedJWK = JSON.parse(bytesToASCIIString(result));
+
+ shouldBe("exportedJWK.kty", "'RSA'");
+ shouldBe("exportedJWK.n", "privateKeyJSON.n");
+ shouldBe("exportedJWK.e", "privateKeyJSON.e");
+ shouldBe("exportedJWK.d", "privateKeyJSON.d");
+ shouldBe("exportedJWK.p", "privateKeyJSON.p");
+ shouldBe("exportedJWK.q", "privateKeyJSON.q");
+ shouldBe("exportedJWK.dp", "privateKeyJSON.dp");
+ shouldBe("exportedJWK.dq", "privateKeyJSON.dq");
+ shouldBe("exportedJWK.qi", "privateKeyJSON.qi");
+ shouldBe("exportedJWK.oth", "privateKeyJSON.oth");
+ shouldBe("exportedJWK.alg", "privateKeyJSON.alg");
+ shouldBe("exportedJWK.extractable", "true");
+ shouldBe("exportedJWK.use", "'sig'");
+
+ finishJSTest();
+});
+</script>
+
+<script src=""
+</body>
+</html>
Property changes on: trunk/LayoutTests/crypto/subtle/rsa-export-private-key.html
___________________________________________________________________
Added: svn:mime-type
Modified: trunk/Source/WebCore/ChangeLog (160028 => 160029)
--- trunk/Source/WebCore/ChangeLog 2013-12-03 20:12:09 UTC (rev 160028)
+++ trunk/Source/WebCore/ChangeLog 2013-12-03 20:18:14 UTC (rev 160029)
@@ -1,3 +1,30 @@
+2013-12-03 Alexey Proskuryakov <[email protected]>
+
+ Support exporting private WebCrypto RSA keys
+ https://bugs.webkit.org/show_bug.cgi?id=124483
+
+ Reviewed by Anders Carlsson.
+
+ Test: crypto/subtle/rsa-export-private-key.html
+
+ It might be better to have our own bignum implementation in WTF, but we currently
+ don't, and the need for this computation is Common Crypto specific anyway.
+
+ * crypto/CommonCryptoUtilities.h:
+ * crypto/CommonCryptoUtilities.cpp:
+ (WebCore::CCBigNum::CCBigNum):
+ (WebCore::CCBigNum::~CCBigNum):
+ (WebCore::CCBigNum::operator=):
+ (WebCore::CCBigNum::data):
+ (WebCore::CCBigNum::operator-):
+ (WebCore::CCBigNum::operator%):
+ (WebCore::CCBigNum::inverse):
+ Added a minimal wrapper around CommonCrypto BigNum.
+
+ * crypto/mac/CryptoKeyRSAMac.cpp:
+ (WebCore::getPrivateKeyComponents): Compute missing parts using CCBigNum.
+ (WebCore::CryptoKeyRSA::exportData): Implemented private key case.
+
2013-12-03 Ryosuke Niwa <[email protected]>
XML fragment parsing algorithm doesn't use the context element's default namespace URI
Modified: trunk/Source/WebCore/crypto/CommonCryptoUtilities.cpp (160028 => 160029)
--- trunk/Source/WebCore/crypto/CommonCryptoUtilities.cpp 2013-12-03 20:12:09 UTC (rev 160028)
+++ trunk/Source/WebCore/crypto/CommonCryptoUtilities.cpp 2013-12-03 20:18:14 UTC (rev 160029)
@@ -28,6 +28,23 @@
#if ENABLE(SUBTLE_CRYPTO)
+#if defined(__has_include)
+#if __has_include(<CommonCrypto/CommonBigNum.h>)
+#include <CommonCrypto/CommonBigNum.h>
+#endif
+#endif
+
+typedef CCCryptorStatus CCStatus;
+extern "C" CCBigNumRef CCBigNumFromData(CCStatus *status, const void *s, size_t len);
+extern "C" size_t CCBigNumToData(CCStatus *status, const CCBigNumRef bn, void *to);
+extern "C" uint32_t CCBigNumByteCount(const CCBigNumRef bn);
+extern "C" CCBigNumRef CCCreateBigNum(CCStatus *status);
+extern "C" void CCBigNumFree(CCBigNumRef bn);
+extern "C" CCBigNumRef CCBigNumCopy(CCStatus *status, const CCBigNumRef bn);
+extern "C" CCStatus CCBigNumSubI(CCBigNumRef result, const CCBigNumRef a, const uint32_t b);
+extern "C" CCStatus CCBigNumMod(CCBigNumRef result, CCBigNumRef dividend, CCBigNumRef modulus);
+extern "C" CCStatus CCBigNumInverseMod(CCBigNumRef result, const CCBigNumRef a, const CCBigNumRef modulus);
+
namespace WebCore {
bool getCommonCryptoDigestAlgorithm(CryptoAlgorithmIdentifier hashFunction, CCDigestAlgorithm& algorithm)
@@ -53,6 +70,106 @@
}
}
+CCBigNum::CCBigNum(CCBigNumRef number)
+ : m_number(number)
+{
+}
+
+CCBigNum::CCBigNum(const uint8_t* data, size_t size)
+{
+ CCStatus status = kCCSuccess;
+ m_number = CCBigNumFromData(&status, data, size);
+ RELEASE_ASSERT(!status);
+}
+
+CCBigNum::~CCBigNum()
+{
+ CCBigNumFree(m_number);
+}
+
+CCBigNum::CCBigNum(const CCBigNum& other)
+{
+ CCStatus status = kCCSuccess;
+ m_number = CCBigNumCopy(&status, other.m_number);
+ RELEASE_ASSERT(!status);
+}
+
+CCBigNum::CCBigNum(CCBigNum&& other)
+{
+ m_number = other.m_number;
+ other.m_number = nullptr;
+}
+
+CCBigNum& CCBigNum::operator=(const CCBigNum& other)
+{
+ if (this == &other)
+ return *this;
+
+ CCBigNumFree(m_number);
+
+ CCStatus status = kCCSuccess;
+ m_number = CCBigNumCopy(&status, other.m_number);
+ RELEASE_ASSERT(!status);
+ return *this;
+}
+
+CCBigNum& CCBigNum::operator=(CCBigNum&& other)
+{
+ if (this == &other)
+ return *this;
+
+ m_number = other.m_number;
+ other.m_number = nullptr;
+
+ return *this;
+}
+
+Vector<uint8_t> CCBigNum::data() const
+{
+ Vector<uint8_t> result(CCBigNumByteCount(m_number));
+ CCStatus status = kCCSuccess;
+ CCBigNumToData(&status, m_number, result.data());
+ RELEASE_ASSERT(!status);
+
+ return result;
+}
+
+CCBigNum CCBigNum::operator-(uint32_t b) const
+{
+ CCStatus status = kCCSuccess;
+ CCBigNumRef result = CCCreateBigNum(&status);
+ RELEASE_ASSERT(!status);
+
+ status = CCBigNumSubI(result, m_number, b);
+ RELEASE_ASSERT(!status);
+
+ return result;
+}
+
+CCBigNum CCBigNum::operator%(const CCBigNum& modulus) const
+{
+ CCStatus status = kCCSuccess;
+ CCBigNumRef result = CCCreateBigNum(&status);
+ RELEASE_ASSERT(!status);
+
+ status = CCBigNumMod(result, m_number, modulus.m_number);
+ RELEASE_ASSERT(!status);
+
+ return result;
+}
+
+CCBigNum CCBigNum::inverse(const CCBigNum& modulus) const
+{
+ CCStatus status = kCCSuccess;
+ CCBigNumRef result = CCCreateBigNum(&status);
+ RELEASE_ASSERT(!status);
+
+ status = CCBigNumInverseMod(result, m_number, modulus.m_number);
+ RELEASE_ASSERT(!status);
+
+ return result;
+}
+
} // namespace WebCore
#endif // ENABLE(SUBTLE_CRYPTO)
Modified: trunk/Source/WebCore/crypto/CommonCryptoUtilities.h (160028 => 160029)
--- trunk/Source/WebCore/crypto/CommonCryptoUtilities.h 2013-12-03 20:12:09 UTC (rev 160028)
+++ trunk/Source/WebCore/crypto/CommonCryptoUtilities.h 2013-12-03 20:18:14 UTC (rev 160029)
@@ -29,8 +29,8 @@
#if ENABLE(SUBTLE_CRYPTO)
#include "CryptoAlgorithmIdentifier.h"
-
#include <CommonCrypto/CommonCryptor.h>
+#include <wtf/Vector.h>
#if defined(__has_include)
#if __has_include(<CommonCrypto/CommonRSACryptor.h>)
@@ -71,6 +71,8 @@
};
#endif
+typedef struct _CCBigNumRef *CCBigNumRef;
+
typedef struct __CCRandom *CCRandomRef;
extern const CCRandomRef kCCRandomDefault;
extern "C" int CCRandomCopyBytes(CCRandomRef rnd, void *bytes, size_t count);
@@ -89,6 +91,28 @@
namespace WebCore {
+class CCBigNum {
+public:
+ CCBigNum(const uint8_t*, size_t);
+ ~CCBigNum();
+
+ CCBigNum(const CCBigNum&);
+ CCBigNum(CCBigNum&&);
+ CCBigNum& operator=(const CCBigNum&);
+ CCBigNum& operator=(CCBigNum&&);
+
+ Vector<uint8_t> data() const;
+
+ CCBigNum operator-(uint32_t) const;
+ CCBigNum operator%(const CCBigNum&) const;
+ CCBigNum inverse(const CCBigNum& modulus) const;
+
+private:
+ CCBigNum(CCBigNumRef);
+
+ CCBigNumRef m_number;
+};
+
bool getCommonCryptoDigestAlgorithm(CryptoAlgorithmIdentifier, CCDigestAlgorithm&);
} // namespace WebCore
Modified: trunk/Source/WebCore/crypto/mac/CryptoKeyRSAMac.cpp (160028 => 160029)
--- trunk/Source/WebCore/crypto/mac/CryptoKeyRSAMac.cpp 2013-12-03 20:12:09 UTC (rev 160028)
+++ trunk/Source/WebCore/crypto/mac/CryptoKeyRSAMac.cpp 2013-12-03 20:18:14 UTC (rev 160029)
@@ -59,6 +59,42 @@
return status;
}
+static CCCryptorStatus getPrivateKeyComponents(CCRSACryptorRef rsaKey, Vector<uint8_t>& privateExponent, CryptoKeyDataRSAComponents::PrimeInfo& firstPrimeInfo, CryptoKeyDataRSAComponents::PrimeInfo& secondPrimeInfo)
+{
+ ASSERT(CCRSAGetKeyType(rsaKey) == ccRSAKeyPrivate);
+
+ Vector<uint8_t> unusedModulus(16384);
+ size_t modulusLength = unusedModulus.size();
+ privateExponent.resize(16384);
+ size_t exponentLength = privateExponent.size();
+ firstPrimeInfo.primeFactor.resize(16384);
+ size_t pLength = firstPrimeInfo.primeFactor.size();
+ secondPrimeInfo.primeFactor.resize(16384);
+ size_t qLength = secondPrimeInfo.primeFactor.size();
+
+ CCCryptorStatus status = CCRSAGetKeyComponents(rsaKey, unusedModulus.data(), &modulusLength, privateExponent.data(), &exponentLength, firstPrimeInfo.primeFactor.data(), &pLength, secondPrimeInfo.primeFactor.data(), &qLength);
+ if (status)
+ return status;
+
+ privateExponent.shrink(exponentLength);
+ firstPrimeInfo.primeFactor.shrink(pLength);
+ secondPrimeInfo.primeFactor.shrink(qLength);
+
+ CCBigNum d(privateExponent.data(), privateExponent.size());
+ CCBigNum p(firstPrimeInfo.primeFactor.data(), firstPrimeInfo.primeFactor.size());
+ CCBigNum q(secondPrimeInfo.primeFactor.data(), secondPrimeInfo.primeFactor.size());
+
+ CCBigNum dp = d % (p - 1);
+ CCBigNum dq = d % (q - 1);
+ CCBigNum qi = q.inverse(p);
+
+ firstPrimeInfo.factorCRTExponent = dp.data();
+ secondPrimeInfo.factorCRTExponent = dq.data();
+ secondPrimeInfo.factorCRTCoefficient = qi.data();
+
+ return status;
+}
+
CryptoKeyRSA::CryptoKeyRSA(CryptoAlgorithmIdentifier identifier, CryptoKeyType type, PlatformRSAKey platformKey, bool extractable, CryptoKeyUsage usage)
: CryptoKey(identifier, type, extractable, usage)
, m_platformKey(platformKey)
@@ -165,8 +201,25 @@
}
return CryptoKeyDataRSAComponents::createPublic(modulus, publicExponent);
}
- case ccRSAKeyPrivate:
- // Not supported yet.
+ case ccRSAKeyPrivate: {
+ Vector<uint8_t> modulus;
+ Vector<uint8_t> publicExponent;
+ CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
+ if (status) {
+ WTFLogAlways("Couldn't get RSA key components, status %d", status);
+ return nullptr;
+ }
+ Vector<uint8_t> privateExponent;
+ CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
+ CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
+ Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos; // Always empty, CommonCrypto only supports two primes (cf. <rdar://problem/15444074>).
+ status = getPrivateKeyComponents(m_platformKey, privateExponent, firstPrimeInfo, secondPrimeInfo);
+ if (status) {
+ WTFLogAlways("Couldn't get RSA key components, status %d", status);
+ return nullptr;
+ }
+ return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, publicExponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
+ }
default:
return nullptr;
}