Skip to content

Commit 21ceca3

Browse files
[GCrypt] Implement CryptoKeyRSA PKCS#8 imports
https://bugs.webkit.org/show_bug.cgi?id=173696 Reviewed by Jiewen Tan. Source/WebCore: Implement the PKCS#8 import operation for RSA keys for platforms that use libgcrypt. In CryptoKeyRSA::importPkcs8(), the provided key data is decoded against the 'PrivateKeyInfo` ASN.1 structure. We then validate the `version` element and check that the `privateKeyAlgorithm.algorithm` element contains a supported object identifier. This check is for now mostly superficial, only ensuring that the object identifier is either id-rsaEncryption, id-RSAES-OAEP or id-RSASSA-PSS. This has to be further extended to also check the id-sha{1,256,384,512}WithRSAEncryption identifiers as well as decoding the `privateKeyAlgorithm.parameters` element against a specific ASN.1 structure, if necessary (RSASSA-PSS-params or RSAES-OAEP-params), and cross-checking the specified digest algorithm with the algorithm that's specified through the main object identifier or the structure contained in `privateKeyAlgorithm.parameters`. This is avoided for now because no test in WebKit or the web-platform-tests suite covers this detail of the specification. Data under the `privateKey` element is decoded against the `RSAPrivateKey` ASN.1 structure, and the `version` element of that structure is validated. We then retrieve data from that structure for the modulus, public exponent, private exponent, both primes, both exponents and the coefficient parameters, bailing if any of them is missing. Because libgcrypt switches the use of p and q parameters, deviating from the standard use, we have to recompute the u parameter (the coefficient). With that calculated, we're then able to construct the `private-key` s-expression, embedding into it all the necessary parameters, and transferring the ownership of this object to the new CryptoKeyRSA object that's then returned from the importPkcs8() method. No new tests -- related tests are now passing and are unskipped. * crypto/gcrypt/CryptoKeyRSAGCrypt.cpp: (WebCore::CryptoKeyRSA::importPkcs8): LayoutTests: * platform/gtk/TestExpectations: Unskip the RSA PKCS#8 import tests that are now passing. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@219535 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent c722fd5 commit 21ceca3

File tree

4 files changed

+141
-8
lines changed

4 files changed

+141
-8
lines changed

LayoutTests/ChangeLog

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
2017-07-14 Zan Dobersek <[email protected]>
2+
3+
[GCrypt] Implement CryptoKeyRSA PKCS#8 imports
4+
https://bugs.webkit.org/show_bug.cgi?id=173696
5+
6+
Reviewed by Jiewen Tan.
7+
8+
* platform/gtk/TestExpectations: Unskip the RSA PKCS#8 import tests
9+
that are now passing.
10+
111
2017-07-14 Chris Dumez <[email protected]>
212

313
Possible crash in ~UserGestureIndicator() when on non-main thread

LayoutTests/platform/gtk/TestExpectations

-5
Original file line numberDiff line numberDiff line change
@@ -767,20 +767,16 @@ webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html
767767
webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html [ Skip ]
768768
webkit.org/b/133122 crypto/subtle/rsa-export-key-malformed-parameters.html [ Skip ]
769769
webkit.org/b/133122 crypto/subtle/rsa-import-jwk-key-export-pkcs8-key.html [ Skip ]
770-
webkit.org/b/133122 crypto/subtle/rsa-import-pkcs8-key-export-jwk-key.html [ Skip ]
771770
webkit.org/b/133122 crypto/subtle/rsa-import-pkcs8-key-export-pkcs8-key.html [ Skip ]
772771
webkit.org/b/133122 crypto/subtle/rsa-import-spki-key-export-spki-key.html [ Skip ]
773772
webkit.org/b/133122 crypto/subtle/rsa-indexeddb-non-exportable-private.html [ Skip ]
774773
webkit.org/b/133122 crypto/subtle/rsa-indexeddb-non-exportable.html [ Skip ]
775774
webkit.org/b/133122 crypto/subtle/rsa-indexeddb-private.html [ Skip ]
776775
webkit.org/b/133122 crypto/subtle/rsa-indexeddb.html [ Skip ]
777776
webkit.org/b/133122 crypto/subtle/rsa-oaep-generate-export-key-pkcs8.html [ Skip ]
778-
webkit.org/b/133122 crypto/subtle/rsa-oaep-import-pkcs8-key.html [ Skip ]
779777
webkit.org/b/133122 crypto/subtle/rsa-pss-generate-export-key-pkcs8.html [ Skip ]
780778
webkit.org/b/133122 crypto/subtle/rsaes-pkcs1-v1_5-generate-export-key-pkcs8.html [ Skip ]
781-
webkit.org/b/133122 crypto/subtle/rsaes-pkcs1-v1_5-import-pkcs8-key.html [ Skip ]
782779
webkit.org/b/133122 crypto/subtle/rsassa-pkcs1-v1_5-generate-export-key-pkcs8.html [ Skip ]
783-
webkit.org/b/133122 crypto/subtle/rsassa-pkcs1-v1_5-import-pkcs8-key.html [ Skip ]
784780
webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-decrypt.html [ Skip ]
785781
webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-encrypt.html [ Skip ]
786782
webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-unwrap-key.html [ Skip ]
@@ -793,7 +789,6 @@ webkit.org/b/133122 crypto/workers/subtle/hrsa-postMessage-worker.html [ Skip ]
793789
webkit.org/b/133122 crypto/workers/subtle/multiple-postMessage-worker.html [ Skip ]
794790
webkit.org/b/133122 crypto/workers/subtle/raw-postMessage-worker.html [ Skip ]
795791
webkit.org/b/133122 crypto/workers/subtle/rsa-export-pkcs8-key.html [ Skip ]
796-
webkit.org/b/133122 crypto/workers/subtle/rsa-import-pkcs8-key.html [ Skip ]
797792
webkit.org/b/133122 crypto/workers/subtle/rsa-postMessage-worker.html [ Skip ]
798793
webkit.org/b/133122 crypto/workers/subtle/rsa-pss-import-key-sign.html [ Skip ]
799794
webkit.org/b/133122 crypto/workers/subtle/rsa-pss-import-key-verify.html [ Skip ]

Source/WebCore/ChangeLog

+40
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,43 @@
1+
2017-07-14 Zan Dobersek <[email protected]>
2+
3+
[GCrypt] Implement CryptoKeyRSA PKCS#8 imports
4+
https://bugs.webkit.org/show_bug.cgi?id=173696
5+
6+
Reviewed by Jiewen Tan.
7+
8+
Implement the PKCS#8 import operation for RSA keys for platforms that use
9+
libgcrypt.
10+
11+
In CryptoKeyRSA::importPkcs8(), the provided key data is decoded against the
12+
'PrivateKeyInfo` ASN.1 structure. We then validate the `version` element and
13+
check that the `privateKeyAlgorithm.algorithm` element contains a supported
14+
object identifier. This check is for now mostly superficial, only ensuring
15+
that the object identifier is either id-rsaEncryption, id-RSAES-OAEP or
16+
id-RSASSA-PSS. This has to be further extended to also check the
17+
id-sha{1,256,384,512}WithRSAEncryption identifiers as well as decoding the
18+
`privateKeyAlgorithm.parameters` element against a specific ASN.1 structure, if
19+
necessary (RSASSA-PSS-params or RSAES-OAEP-params), and cross-checking the
20+
specified digest algorithm with the algorithm that's specified through the main
21+
object identifier or the structure contained in `privateKeyAlgorithm.parameters`.
22+
This is avoided for now because no test in WebKit or the web-platform-tests
23+
suite covers this detail of the specification.
24+
25+
Data under the `privateKey` element is decoded against the `RSAPrivateKey` ASN.1
26+
structure, and the `version` element of that structure is validated. We then
27+
retrieve data from that structure for the modulus, public exponent, private
28+
exponent, both primes, both exponents and the coefficient parameters, bailing if
29+
any of them is missing. Because libgcrypt switches the use of p and q parameters,
30+
deviating from the standard use, we have to recompute the u parameter (the
31+
coefficient). With that calculated, we're then able to construct the `private-key`
32+
s-expression, embedding into it all the necessary parameters, and transferring
33+
the ownership of this object to the new CryptoKeyRSA object that's then returned
34+
from the importPkcs8() method.
35+
36+
No new tests -- related tests are now passing and are unskipped.
37+
38+
* crypto/gcrypt/CryptoKeyRSAGCrypt.cpp:
39+
(WebCore::CryptoKeyRSA::importPkcs8):
40+
141
2017-07-14 Chris Dumez <[email protected]>
242

343
Possible crash in ~UserGestureIndicator() when on non-main thread

Source/WebCore/crypto/gcrypt/CryptoKeyRSAGCrypt.cpp

+91-3
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,99 @@ RefPtr<CryptoKeyRSA> CryptoKeyRSA::importSpki(CryptoAlgorithmIdentifier identifi
321321
return adoptRef(new CryptoKeyRSA(identifier, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, CryptoKeyType::Public, platformKey.release(), extractable, usages));
322322
}
323323

324-
RefPtr<CryptoKeyRSA> CryptoKeyRSA::importPkcs8(CryptoAlgorithmIdentifier, std::optional<CryptoAlgorithmIdentifier>, Vector<uint8_t>&&, bool, CryptoKeyUsageBitmap)
324+
RefPtr<CryptoKeyRSA> CryptoKeyRSA::importPkcs8(CryptoAlgorithmIdentifier identifier, std::optional<CryptoAlgorithmIdentifier> hash, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
325325
{
326-
notImplemented();
326+
// Decode the `PrivateKeyInfo` structure using the provided key data.
327+
PAL::TASN1::Structure pkcs8;
328+
if (!PAL::TASN1::decodeStructure(&pkcs8, "WebCrypto.PrivateKeyInfo", keyData))
329+
return nullptr;
330+
331+
// Validate `version`.
332+
{
333+
auto version = PAL::TASN1::elementData(pkcs8, "version");
334+
if (!version)
335+
return nullptr;
336+
337+
if (version->size() != 1 || version->at(0) != 0x00)
338+
return nullptr;
339+
}
340+
341+
// Validate `privateKeyAlgorithm.algorithm`.
342+
{
343+
auto algorithm = PAL::TASN1::elementData(pkcs8, "privateKeyAlgorithm.algorithm");
344+
if (!algorithm)
345+
return nullptr;
346+
347+
if (!supportedAlgorithmIdentifier(algorithm->data(), algorithm->size()))
348+
return nullptr;
349+
}
350+
351+
// Decode the `RSAPrivateKey` structure using the `privateKey` data.
352+
PAL::TASN1::Structure rsaPrivateKey;
353+
{
354+
auto privateKey = PAL::TASN1::elementData(pkcs8, "privateKey");
355+
if (!privateKey)
356+
return nullptr;
357+
358+
if (!PAL::TASN1::decodeStructure(&rsaPrivateKey, "WebCrypto.RSAPrivateKey", *privateKey))
359+
return nullptr;
360+
}
361+
362+
// Validate `privateKey.version`.
363+
{
364+
auto version = PAL::TASN1::elementData(rsaPrivateKey, "version");
365+
if (!version)
366+
return nullptr;
367+
368+
if (version->size() != 1 || version->at(0) != 0x00)
369+
return nullptr;
370+
}
371+
372+
// Retrieve the `modulus`, `publicExponent`, `privateExponent`, `prime1`, `prime2`,
373+
// `exponent1`, `exponent2` and `coefficient` data and embed it into the `public-key` s-expression.
374+
PAL::GCrypt::Handle<gcry_sexp_t> platformKey;
375+
{
376+
auto modulus = PAL::TASN1::elementData(rsaPrivateKey, "modulus");
377+
auto publicExponent = PAL::TASN1::elementData(rsaPrivateKey, "publicExponent");
378+
auto privateExponent = PAL::TASN1::elementData(rsaPrivateKey, "privateExponent");
379+
auto prime1 = PAL::TASN1::elementData(rsaPrivateKey, "prime1");
380+
auto prime2 = PAL::TASN1::elementData(rsaPrivateKey, "prime2");
381+
auto exponent1 = PAL::TASN1::elementData(rsaPrivateKey, "exponent1");
382+
auto exponent2 = PAL::TASN1::elementData(rsaPrivateKey, "exponent2");
383+
auto coefficient = PAL::TASN1::elementData(rsaPrivateKey, "coefficient");
384+
385+
if (!modulus || !publicExponent || !privateExponent
386+
|| !prime1 || !prime2 || !exponent1 || !exponent2 || !coefficient)
387+
return nullptr;
388+
389+
// libgcrypt inverts the use of p and q parameters, so we have to recalculate the `coefficient` value.
390+
PAL::GCrypt::Handle<gcry_mpi_t> uMPI(gcry_mpi_new(0));
391+
{
392+
PAL::GCrypt::Handle<gcry_mpi_t> pMPI;
393+
gcry_error_t error = gcry_mpi_scan(&pMPI, GCRYMPI_FMT_USG, prime1->data(), prime1->size(), nullptr);
394+
if (error != GPG_ERR_NO_ERROR)
395+
return nullptr;
396+
397+
PAL::GCrypt::Handle<gcry_mpi_t> qMPI;
398+
error = gcry_mpi_scan(&qMPI, GCRYMPI_FMT_USG, prime2->data(), prime2->size(), nullptr);
399+
if (error != GPG_ERR_NO_ERROR)
400+
return nullptr;
401+
402+
gcry_mpi_invm(uMPI, qMPI, pMPI);
403+
}
404+
405+
gcry_error_t error = gcry_sexp_build(&platformKey, nullptr, "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %M)))",
406+
modulus->size(), modulus->data(),
407+
publicExponent->size(), publicExponent->data(),
408+
privateExponent->size(), privateExponent->data(),
409+
prime2->size(), prime2->data(), prime1->size(), prime1->data(), uMPI.handle());
410+
if (error != GPG_ERR_NO_ERROR) {
411+
PAL::GCrypt::logError(error);
412+
return nullptr;
413+
}
414+
}
327415

328-
return nullptr;
416+
return adoptRef(new CryptoKeyRSA(identifier, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, CryptoKeyType::Private, platformKey.release(), extractable, usages));
329417
}
330418

331419
ExceptionOr<Vector<uint8_t>> CryptoKeyRSA::exportSpki() const

0 commit comments

Comments
 (0)