[GCrypt] Implement CryptoKeyEC PKCS#8 exports
authorzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jul 2017 13:59:37 +0000 (13:59 +0000)
committerzandobersek@gmail.com <zandobersek@gmail.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jul 2017 13:59:37 +0000 (13:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=173648

Reviewed by Jiewen Tan.

Source/WebCore:

Implement the PKCS#8 export operation for EC keys for platforms that use
libgcrypt.

First, the `ECParameters` and the `ECPrivateKey` ASN.1 structures are created
and filled out accordingly. For the former, the appropriate object identifier
is written under the `namedCurve` element of the structure. For the latter, we
write out '1' under `version`, and eliminate the optional `parameters` element.
An libgcrypt EC context is then used to retrieve the private and public key
MPIs that are then written out under the `privateKey` and `publicKey` elements,
respectively.

After that, we can proceed to create and fill out the `PrivateKeyInfo` structure.
0 is written out under the `version` element, and the id-ecPublicKey object
identifier is written out under the `privateKeyAlgorithm.algorithm` element. This
doesn't strictly follow the specification, since the id-ecDH identifier should be
used for ECDH keys, but no test in WebKit or the web-platform-tests suite covers
this, so this specific detail should be revisited later.

Data of the previously-constructed `ECParameters` structure is retrieved and
written out under the `privateKeyAlgorithm.parameters` element. Similarly is done
for the `ECPrivateKey` structure, writing out its data under the `privateKey`
element. Finally, the optional `attributes` element of the `PrivateKeyInfo`
structure is eliminated, and the encoded data of this structure is retrieved and
returned.

No new tests -- relevant tests are now passing and are unskipped.

* crypto/gcrypt/CryptoKeyECGCrypt.cpp:
(WebCore::CryptoKeyEC::platformExportPkcs8):

LayoutTests:

* platform/gtk/TestExpectations: Unskip the EC PKCS#8 export tests
that are now passing.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@219392 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/platform/gtk/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/crypto/gcrypt/CryptoKeyECGCrypt.cpp

index bbbdc73..8e37512 100644 (file)
@@ -1,3 +1,13 @@
+2017-07-12  Zan Dobersek  <zdobersek@igalia.com>
+
+        [GCrypt] Implement CryptoKeyEC PKCS#8 exports
+        https://bugs.webkit.org/show_bug.cgi?id=173648
+
+        Reviewed by Jiewen Tan.
+
+        * platform/gtk/TestExpectations: Unskip the EC PKCS#8 export tests
+        that are now passing.
+
 2017-07-11  Carlos Alberto Lopez Perez  <clopez@igalia.com>
 
         REGRESSION(r219332): [GTK] 9 new failures on fast/forms spinbutton related tests.
index a95b297..97dc43f 100644 (file)
@@ -754,13 +754,9 @@ webkit.org/b/133122 crypto/subtle/aes-cfb-import-key-wrap-jwk-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/aes-cfb-import-key-wrap-raw-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/aes-cfb-import-raw-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/ecdh-derive-bits-malformed-parametrs.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/ecdh-generate-export-key-pkcs8-p256.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/ecdh-generate-export-key-pkcs8-p384.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/ecdh-import-pkcs8-key-p256.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/ecdh-import-pkcs8-key-p384.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/ecdsa-generate-export-key-pkcs8.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/ecdsa-import-pkcs8-key.html [ Skip ]
-webkit.org/b/133122 crypto/subtle/ec-import-jwk-key-export-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html [ Skip ]
 webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p384.html [ Skip ]
@@ -798,7 +794,6 @@ 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 ]
 webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-wrap-key.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/aes-postMessage-worker.html [ Skip ]
-webkit.org/b/133122 crypto/workers/subtle/ec-generate-export-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/ec-import-pkcs8-key.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/ec-postMessage-worker.html [ Skip ]
 webkit.org/b/133122 crypto/workers/subtle/hmac-postMessage-worker.html [ Skip ]
index bd8d19d..1b2ec67 100644 (file)
@@ -1,5 +1,42 @@
 2017-07-12  Zan Dobersek  <zdobersek@igalia.com>
 
+        [GCrypt] Implement CryptoKeyEC PKCS#8 exports
+        https://bugs.webkit.org/show_bug.cgi?id=173648
+
+        Reviewed by Jiewen Tan.
+
+        Implement the PKCS#8 export operation for EC keys for platforms that use
+        libgcrypt.
+
+        First, the `ECParameters` and the `ECPrivateKey` ASN.1 structures are created
+        and filled out accordingly. For the former, the appropriate object identifier
+        is written under the `namedCurve` element of the structure. For the latter, we
+        write out '1' under `version`, and eliminate the optional `parameters` element.
+        An libgcrypt EC context is then used to retrieve the private and public key
+        MPIs that are then written out under the `privateKey` and `publicKey` elements,
+        respectively.
+
+        After that, we can proceed to create and fill out the `PrivateKeyInfo` structure.
+        0 is written out under the `version` element, and the id-ecPublicKey object
+        identifier is written out under the `privateKeyAlgorithm.algorithm` element. This
+        doesn't strictly follow the specification, since the id-ecDH identifier should be
+        used for ECDH keys, but no test in WebKit or the web-platform-tests suite covers
+        this, so this specific detail should be revisited later.
+
+        Data of the previously-constructed `ECParameters` structure is retrieved and
+        written out under the `privateKeyAlgorithm.parameters` element. Similarly is done
+        for the `ECPrivateKey` structure, writing out its data under the `privateKey`
+        element. Finally, the optional `attributes` element of the `PrivateKeyInfo`
+        structure is eliminated, and the encoded data of this structure is retrieved and
+        returned.
+
+        No new tests -- relevant tests are now passing and are unskipped.
+
+        * crypto/gcrypt/CryptoKeyECGCrypt.cpp:
+        (WebCore::CryptoKeyEC::platformExportPkcs8):
+
+2017-07-12  Zan Dobersek  <zdobersek@igalia.com>
+
         [WPE] Use libepoxy
         https://bugs.webkit.org/show_bug.cgi?id=172104
 
index 0c65ce4..7cbd5a2 100644 (file)
@@ -476,9 +476,108 @@ Vector<uint8_t> CryptoKeyEC::platformExportSpki() const
 
 Vector<uint8_t> CryptoKeyEC::platformExportPkcs8() const
 {
-    notImplemented();
+    PAL::TASN1::Structure ecParameters;
+    {
+        // Create the `ECParameters` structure.
+        if (!PAL::TASN1::createStructure("WebCrypto.ECParameters", &ecParameters))
+            return { };
+
+        // Select the `namedCurve` object identifier as the target `ECParameters` choice.
+        if (!PAL::TASN1::writeElement(ecParameters, "", "namedCurve", 1))
+            return { };
+
+        // Write out the EC curve identifier under `namedCurve`.
+        if (!PAL::TASN1::writeElement(ecParameters, "namedCurve", curveIdentifier(m_curve), 1))
+            return { };
+    }
+
+    PAL::TASN1::Structure ecPrivateKey;
+    {
+        // Create the `ECPrivateKey` structure.
+        if (!PAL::TASN1::createStructure("WebCrypto.ECPrivateKey", &ecPrivateKey))
+            return { };
+
+        // Write out '1' under `version`.
+        if (!PAL::TASN1::writeElement(ecPrivateKey, "version", "1", 0))
+            return { };
+
+        // Construct the EC context that we'll use to retrieve private and public key data.
+        PAL::GCrypt::Handle<gcry_ctx_t> context;
+        gcry_error_t error = gcry_mpi_ec_new(&context, m_platformKey, nullptr);
+        if (error != GPG_ERR_NO_ERROR)
+            return { };
+
+        {
+            // Retrieve the `d` MPI that holds the private key data.
+            PAL::GCrypt::Handle<gcry_mpi_t> dMPI(gcry_mpi_ec_get_mpi("d", context, 0));
+            if (!dMPI)
+                return { };
+
+            // Retrieve the MPI data and write it out under `privateKey`.
+            auto data = mpiData(dMPI);
+            if (!data || !PAL::TASN1::writeElement(ecPrivateKey, "privateKey", data->data(), data->size()))
+                return { };
+        }
+
+        // Eliminate the optional `parameters` element.
+        if (!PAL::TASN1::writeElement(ecPrivateKey, "parameters", nullptr, 0))
+            return { };
 
-    return { };
+        {
+            // Retrieve the `q` MPI that holds the public key data.
+            PAL::GCrypt::Handle<gcry_mpi_t> qMPI(gcry_mpi_ec_get_mpi("q", context, 0));
+            if (!qMPI)
+                return { };
+
+            // Retrieve the MPI data and write it out under `publicKey`. Because this is a
+            // bit string parameter, the data size has to be multiplied by 8.
+            auto data = mpiData(qMPI);
+            if (!data || !PAL::TASN1::writeElement(ecPrivateKey, "publicKey", data->data(), data->size() * 8))
+                return { };
+        }
+    }
+
+    PAL::TASN1::Structure pkcs8;
+    {
+        // Create the `PrivateKeyInfo` structure.
+        if (!PAL::TASN1::createStructure("WebCrypto.PrivateKeyInfo", &pkcs8))
+            return { };
+
+        // Write out '0' under `version`.
+        if (!PAL::TASN1::writeElement(pkcs8, "version", "0", 0))
+            return { };
+
+        // Write out the id-ecPublicKey identifier under `privateKeyAlgorithm.algorithm`.
+        // FIXME: Per specification this should write out id-ecDH when the ECDH algorithm
+        // is specified for this CryptoKeyEC object, but not even the W3C tests expect that.
+        if (!PAL::TASN1::writeElement(pkcs8, "privateKeyAlgorithm.algorithm", "1.2.840.10045.2.1", 1))
+            return { };
+
+        // Write out the `ECParameters` data under `privateKeyAlgorithm.parameters`.
+        {
+            auto data = PAL::TASN1::encodedData(ecParameters, "");
+            if (!data || !PAL::TASN1::writeElement(pkcs8, "privateKeyAlgorithm.parameters", data->data(), data->size()))
+                return { };
+        }
+
+        // Write out the `ECPrivateKey` data under `privateKey`.
+        {
+            auto data = PAL::TASN1::encodedData(ecPrivateKey, "");
+            if (!data || !PAL::TASN1::writeElement(pkcs8, "privateKey", data->data(), data->size()))
+                return { };
+        }
+
+        // Eliminate the optional `attributes` element.
+        if (!PAL::TASN1::writeElement(pkcs8, "attributes", nullptr, 0))
+            return { };
+    }
+
+    // Retrieve the encoded `PrivateKeyInfo` data and return it.
+    auto result = PAL::TASN1::encodedData(pkcs8, "");
+    if (!result)
+        return { };
+
+    return WTFMove(result.value());
 }
 
 } // namespace WebCore