Title: [219535] trunk
Revision
219535
Author
zandober...@gmail.com
Date
2017-07-14 22:20:32 -0700 (Fri, 14 Jul 2017)

Log Message

[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.

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (219534 => 219535)


--- trunk/LayoutTests/ChangeLog	2017-07-15 00:29:52 UTC (rev 219534)
+++ trunk/LayoutTests/ChangeLog	2017-07-15 05:20:32 UTC (rev 219535)
@@ -1,3 +1,13 @@
+2017-07-14  Zan Dobersek  <zdober...@igalia.com>
+
+        [GCrypt] Implement CryptoKeyRSA PKCS#8 imports
+        https://bugs.webkit.org/show_bug.cgi?id=173696
+
+        Reviewed by Jiewen Tan.
+
+        * platform/gtk/TestExpectations: Unskip the RSA PKCS#8 import tests
+        that are now passing.
+
 2017-07-14  Chris Dumez  <cdu...@apple.com>
 
         Possible crash in ~UserGestureIndicator() when on non-main thread

Modified: trunk/LayoutTests/platform/gtk/TestExpectations (219534 => 219535)


--- trunk/LayoutTests/platform/gtk/TestExpectations	2017-07-15 00:29:52 UTC (rev 219534)
+++ trunk/LayoutTests/platform/gtk/TestExpectations	2017-07-15 05:20:32 UTC (rev 219535)
@@ -767,7 +767,6 @@
 webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-export-key-malformed-parameters.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-import-jwk-key-export-pkcs8-key.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/rsa-import-pkcs8-key-export-jwk-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-import-pkcs8-key-export-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-import-spki-key-export-spki-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-indexeddb-non-exportable-private.html [ Skip ]
@@ -775,12 +774,9 @@
 webkit.org/b/133122 crypto/subtle/rsa-indexeddb-private.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-indexeddb.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-oaep-generate-export-key-pkcs8.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/rsa-oaep-import-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsa-pss-generate-export-key-pkcs8.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsaes-pkcs1-v1_5-generate-export-key-pkcs8.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/rsaes-pkcs1-v1_5-import-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/rsassa-pkcs1-v1_5-generate-export-key-pkcs8.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/rsassa-pkcs1-v1_5-import-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-decrypt.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-encrypt.html [ Skip ]
 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/multiple-postMessage-worker.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/raw-postMessage-worker.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/rsa-export-pkcs8-key.html [ Skip ]
-webkit.org/b/133122 crypto/workers/subtle/rsa-import-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/rsa-postMessage-worker.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/rsa-pss-import-key-sign.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/rsa-pss-import-key-verify.html [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (219534 => 219535)


--- trunk/Source/WebCore/ChangeLog	2017-07-15 00:29:52 UTC (rev 219534)
+++ trunk/Source/WebCore/ChangeLog	2017-07-15 05:20:32 UTC (rev 219535)
@@ -1,3 +1,43 @@
+2017-07-14  Zan Dobersek  <zdober...@igalia.com>
+
+        [GCrypt] Implement CryptoKeyRSA PKCS#8 imports
+        https://bugs.webkit.org/show_bug.cgi?id=173696
+
+        Reviewed by Jiewen Tan.
+
+        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):
+
 2017-07-14  Chris Dumez  <cdu...@apple.com>
 
         Possible crash in ~UserGestureIndicator() when on non-main thread

Modified: trunk/Source/WebCore/crypto/gcrypt/CryptoKeyRSAGCrypt.cpp (219534 => 219535)


--- trunk/Source/WebCore/crypto/gcrypt/CryptoKeyRSAGCrypt.cpp	2017-07-15 00:29:52 UTC (rev 219534)
+++ trunk/Source/WebCore/crypto/gcrypt/CryptoKeyRSAGCrypt.cpp	2017-07-15 05:20:32 UTC (rev 219535)
@@ -321,11 +321,99 @@
     return adoptRef(new CryptoKeyRSA(identifier, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, CryptoKeyType::Public, platformKey.release(), extractable, usages));
 }
 
-RefPtr<CryptoKeyRSA> CryptoKeyRSA::importPkcs8(CryptoAlgorithmIdentifier, std::optional<CryptoAlgorithmIdentifier>, Vector<uint8_t>&&, bool, CryptoKeyUsageBitmap)
+RefPtr<CryptoKeyRSA> CryptoKeyRSA::importPkcs8(CryptoAlgorithmIdentifier identifier, std::optional<CryptoAlgorithmIdentifier> hash, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
 {
-    notImplemented();
+    // Decode the `PrivateKeyInfo` structure using the provided key data.
+    PAL::TASN1::Structure pkcs8;
+    if (!PAL::TASN1::decodeStructure(&pkcs8, "WebCrypto.PrivateKeyInfo", keyData))
+        return nullptr;
 
-    return nullptr;
+    // Validate `version`.
+    {
+        auto version = PAL::TASN1::elementData(pkcs8, "version");
+        if (!version)
+            return nullptr;
+
+        if (version->size() != 1 || version->at(0) != 0x00)
+            return nullptr;
+    }
+
+    // Validate `privateKeyAlgorithm.algorithm`.
+    {
+        auto algorithm = PAL::TASN1::elementData(pkcs8, "privateKeyAlgorithm.algorithm");
+        if (!algorithm)
+            return nullptr;
+
+        if (!supportedAlgorithmIdentifier(algorithm->data(), algorithm->size()))
+            return nullptr;
+    }
+
+    // Decode the `RSAPrivateKey` structure using the `privateKey` data.
+    PAL::TASN1::Structure rsaPrivateKey;
+    {
+        auto privateKey = PAL::TASN1::elementData(pkcs8, "privateKey");
+        if (!privateKey)
+            return nullptr;
+
+        if (!PAL::TASN1::decodeStructure(&rsaPrivateKey, "WebCrypto.RSAPrivateKey", *privateKey))
+            return nullptr;
+    }
+
+    // Validate `privateKey.version`.
+    {
+        auto version = PAL::TASN1::elementData(rsaPrivateKey, "version");
+        if (!version)
+            return nullptr;
+
+        if (version->size() != 1 || version->at(0) != 0x00)
+            return nullptr;
+    }
+
+    // Retrieve the `modulus`, `publicExponent`, `privateExponent`, `prime1`, `prime2`,
+    // `exponent1`, `exponent2` and `coefficient` data and embed it into the `public-key` s-_expression_.
+    PAL::GCrypt::Handle<gcry_sexp_t> platformKey;
+    {
+        auto modulus = PAL::TASN1::elementData(rsaPrivateKey, "modulus");
+        auto publicExponent = PAL::TASN1::elementData(rsaPrivateKey, "publicExponent");
+        auto privateExponent = PAL::TASN1::elementData(rsaPrivateKey, "privateExponent");
+        auto prime1 = PAL::TASN1::elementData(rsaPrivateKey, "prime1");
+        auto prime2 = PAL::TASN1::elementData(rsaPrivateKey, "prime2");
+        auto exponent1 = PAL::TASN1::elementData(rsaPrivateKey, "exponent1");
+        auto exponent2 = PAL::TASN1::elementData(rsaPrivateKey, "exponent2");
+        auto coefficient = PAL::TASN1::elementData(rsaPrivateKey, "coefficient");
+
+        if (!modulus || !publicExponent || !privateExponent
+            || !prime1 || !prime2 || !exponent1 || !exponent2 || !coefficient)
+            return nullptr;
+
+        // libgcrypt inverts the use of p and q parameters, so we have to recalculate the `coefficient` value.
+        PAL::GCrypt::Handle<gcry_mpi_t> uMPI(gcry_mpi_new(0));
+        {
+            PAL::GCrypt::Handle<gcry_mpi_t> pMPI;
+            gcry_error_t error = gcry_mpi_scan(&pMPI, GCRYMPI_FMT_USG, prime1->data(), prime1->size(), nullptr);
+            if (error != GPG_ERR_NO_ERROR)
+                return nullptr;
+
+            PAL::GCrypt::Handle<gcry_mpi_t> qMPI;
+            error = gcry_mpi_scan(&qMPI, GCRYMPI_FMT_USG, prime2->data(), prime2->size(), nullptr);
+            if (error != GPG_ERR_NO_ERROR)
+                return nullptr;
+
+            gcry_mpi_invm(uMPI, qMPI, pMPI);
+        }
+
+        gcry_error_t error = gcry_sexp_build(&platformKey, nullptr, "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %M)))",
+            modulus->size(), modulus->data(),
+            publicExponent->size(), publicExponent->data(),
+            privateExponent->size(), privateExponent->data(),
+            prime2->size(), prime2->data(), prime1->size(), prime1->data(), uMPI.handle());
+        if (error != GPG_ERR_NO_ERROR) {
+            PAL::GCrypt::logError(error);
+            return nullptr;
+        }
+    }
+
+    return adoptRef(new CryptoKeyRSA(identifier, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, CryptoKeyType::Private, platformKey.release(), extractable, usages));
 }
 
 ExceptionOr<Vector<uint8_t>> CryptoKeyRSA::exportSpki() const
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to