Skip to content

Commit c9d128a

Browse files
[GCrypt] Implement CryptoKeyRSA PKCS#8 exports
https://bugs.webkit.org/show_bug.cgi?id=173697 Reviewed by Jiewen Tan. Source/WebCore: Implement the PKCS#8 import operation for RSA keys for platforms that use libgcrypt. In CryptoKeyRSA::exportPkcs8(), we bail early with an invalid access exception if this export is not being done for a private key. Otherwise, we start with creating the `RSAPrivateKey` ASN.1 structure, writing out '0' under the `version` element and then retrieving the modulus, public and private exponent and both primes. MPI data for those parameters is written out into corresponding elements in the `RSAPrivateKey` structure. We then manually compute values of both exponents and the coefficient parameters, using the private exponent's and both primes' MPI values. The p and q parameters (i.e. the primes) are switched in libgcrypt, deviating from the standard practice, so we have to operate with those two accordingly. We eliminate the optional `otherPrimeInfos` attribute on the `RSAPrivateKey` structure. Support for this attribute will be added later. We then create the `PrivateKeyInfo` ASN.1 structure, and write out '0' under the `version` element. The id-rsaEncryption object identifier is written out under the `algorithm.algorithm` element. In the future, an object identifier that matches this key's algorithm will have to be written out here (id-RSASSA-PSS or id-RSAES-OAEP), along with the appropriate parameters structure, but no test in WebKit or the web-platform-tests suite covers this detail. For now, a null value is written out under the `algorithm.parameters` element. Data for the `RSAPrivateKey` structure is retrieved and written out under the `privateKey` element. The optional `attributes` element on the `PrivateKeyInfo` structure is eliminated. Data that was encoded through the `PrivateKeyInfo` structure is then retrieved and returned from the exportPkcs8() method. No new tests -- related tests are now passing and are unskipped. * crypto/gcrypt/CryptoKeyRSAGCrypt.cpp: (WebCore::CryptoKeyRSA::exportPkcs8): LayoutTests: * platform/gtk/TestExpectations: Unskip the RSA PKCS#8 export tests git-svn-id: http://svn.webkit.org/repository/webkit/trunk@219536 268f45cc-cd09-0410-ab3c-d52691b4dbfc
1 parent 21ceca3 commit c9d128a

File tree

4 files changed

+185
-8
lines changed

4 files changed

+185
-8
lines changed

LayoutTests/ChangeLog

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
2017-07-14 Zan Dobersek <[email protected]>
2+
3+
[GCrypt] Implement CryptoKeyRSA PKCS#8 exports
4+
https://bugs.webkit.org/show_bug.cgi?id=173697
5+
6+
Reviewed by Jiewen Tan.
7+
8+
* platform/gtk/TestExpectations: Unskip the RSA PKCS#8 export tests
9+
110
2017-07-14 Zan Dobersek <[email protected]>
211

312
[GCrypt] Implement CryptoKeyRSA PKCS#8 imports

LayoutTests/platform/gtk/TestExpectations

-6
Original file line numberDiff line numberDiff line change
@@ -766,17 +766,12 @@ webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-jwk-key.html [ Skip
766766
webkit.org/b/133122 crypto/subtle/ec-import-pkcs8-key-export-pkcs8-key-p256.html [ Skip ]
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 ]
769-
webkit.org/b/133122 crypto/subtle/rsa-import-jwk-key-export-pkcs8-key.html [ Skip ]
770769
webkit.org/b/133122 crypto/subtle/rsa-import-pkcs8-key-export-pkcs8-key.html [ Skip ]
771770
webkit.org/b/133122 crypto/subtle/rsa-import-spki-key-export-spki-key.html [ Skip ]
772771
webkit.org/b/133122 crypto/subtle/rsa-indexeddb-non-exportable-private.html [ Skip ]
773772
webkit.org/b/133122 crypto/subtle/rsa-indexeddb-non-exportable.html [ Skip ]
774773
webkit.org/b/133122 crypto/subtle/rsa-indexeddb-private.html [ Skip ]
775774
webkit.org/b/133122 crypto/subtle/rsa-indexeddb.html [ Skip ]
776-
webkit.org/b/133122 crypto/subtle/rsa-oaep-generate-export-key-pkcs8.html [ Skip ]
777-
webkit.org/b/133122 crypto/subtle/rsa-pss-generate-export-key-pkcs8.html [ Skip ]
778-
webkit.org/b/133122 crypto/subtle/rsaes-pkcs1-v1_5-generate-export-key-pkcs8.html [ Skip ]
779-
webkit.org/b/133122 crypto/subtle/rsassa-pkcs1-v1_5-generate-export-key-pkcs8.html [ Skip ]
780775
webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-decrypt.html [ Skip ]
781776
webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-encrypt.html [ Skip ]
782777
webkit.org/b/133122 crypto/workers/subtle/aes-cfb-import-key-unwrap-key.html [ Skip ]
@@ -788,7 +783,6 @@ webkit.org/b/133122 crypto/workers/subtle/hmac-postMessage-worker.html [ Skip ]
788783
webkit.org/b/133122 crypto/workers/subtle/hrsa-postMessage-worker.html [ Skip ]
789784
webkit.org/b/133122 crypto/workers/subtle/multiple-postMessage-worker.html [ Skip ]
790785
webkit.org/b/133122 crypto/workers/subtle/raw-postMessage-worker.html [ Skip ]
791-
webkit.org/b/133122 crypto/workers/subtle/rsa-export-pkcs8-key.html [ Skip ]
792786
webkit.org/b/133122 crypto/workers/subtle/rsa-postMessage-worker.html [ Skip ]
793787
webkit.org/b/133122 crypto/workers/subtle/rsa-pss-import-key-sign.html [ Skip ]
794788
webkit.org/b/133122 crypto/workers/subtle/rsa-pss-import-key-verify.html [ Skip ]

Source/WebCore/ChangeLog

+42
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,45 @@
1+
2017-07-14 Zan Dobersek <[email protected]>
2+
3+
[GCrypt] Implement CryptoKeyRSA PKCS#8 exports
4+
https://bugs.webkit.org/show_bug.cgi?id=173697
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::exportPkcs8(), we bail early with an invalid access exception if
12+
this export is not being done for a private key. Otherwise, we start with creating
13+
the `RSAPrivateKey` ASN.1 structure, writing out '0' under the `version` element
14+
and then retrieving the modulus, public and private exponent and both primes.
15+
MPI data for those parameters is written out into corresponding elements in the
16+
`RSAPrivateKey` structure. We then manually compute values of both exponents and
17+
the coefficient parameters, using the private exponent's and both primes' MPI
18+
values. The p and q parameters (i.e. the primes) are switched in libgcrypt,
19+
deviating from the standard practice, so we have to operate with those two
20+
accordingly. We eliminate the optional `otherPrimeInfos` attribute on the
21+
`RSAPrivateKey` structure. Support for this attribute will be added later.
22+
23+
We then create the `PrivateKeyInfo` ASN.1 structure, and write out '0' under the
24+
`version` element. The id-rsaEncryption object identifier is written out under
25+
the `algorithm.algorithm` element. In the future, an object identifier that
26+
matches this key's algorithm will have to be written out here (id-RSASSA-PSS or
27+
id-RSAES-OAEP), along with the appropriate parameters structure, but no test in
28+
WebKit or the web-platform-tests suite covers this detail. For now, a null value
29+
is written out under the `algorithm.parameters` element.
30+
31+
Data for the `RSAPrivateKey` structure is retrieved and written out under the
32+
`privateKey` element. The optional `attributes` element on the `PrivateKeyInfo`
33+
structure is eliminated.
34+
35+
Data that was encoded through the `PrivateKeyInfo` structure is then retrieved
36+
and returned from the exportPkcs8() method.
37+
38+
No new tests -- related tests are now passing and are unskipped.
39+
40+
* crypto/gcrypt/CryptoKeyRSAGCrypt.cpp:
41+
(WebCore::CryptoKeyRSA::exportPkcs8):
42+
143
2017-07-14 Zan Dobersek <[email protected]>
244

345
[GCrypt] Implement CryptoKeyRSA PKCS#8 imports

Source/WebCore/crypto/gcrypt/CryptoKeyRSAGCrypt.cpp

+134-2
Original file line numberDiff line numberDiff line change
@@ -488,9 +488,141 @@ ExceptionOr<Vector<uint8_t>> CryptoKeyRSA::exportSpki() const
488488

489489
ExceptionOr<Vector<uint8_t>> CryptoKeyRSA::exportPkcs8() const
490490
{
491-
notImplemented();
491+
if (type() != CryptoKeyType::Private)
492+
return Exception { INVALID_ACCESS_ERR };
493+
494+
PAL::TASN1::Structure rsaPrivateKey;
495+
{
496+
// Create the `RSAPrivateKey` structure.
497+
if (!PAL::TASN1::createStructure("WebCrypto.RSAPrivateKey", &rsaPrivateKey))
498+
return Exception { OperationError };
499+
500+
// Write out '0' under `version`.
501+
if (!PAL::TASN1::writeElement(rsaPrivateKey, "version", "0", 0))
502+
return Exception { OperationError };
503+
504+
// Retrieve the `n`, `e`, `d`, `q` and `p` s-expression tokens. libgcrypt swaps the usage of
505+
// the p and q primes internally, so we adjust the lookup accordingly.
506+
PAL::GCrypt::Handle<gcry_sexp_t> nSexp(gcry_sexp_find_token(m_platformKey, "n", 0));
507+
PAL::GCrypt::Handle<gcry_sexp_t> eSexp(gcry_sexp_find_token(m_platformKey, "e", 0));
508+
PAL::GCrypt::Handle<gcry_sexp_t> dSexp(gcry_sexp_find_token(m_platformKey, "d", 0));
509+
PAL::GCrypt::Handle<gcry_sexp_t> pSexp(gcry_sexp_find_token(m_platformKey, "q", 0));
510+
PAL::GCrypt::Handle<gcry_sexp_t> qSexp(gcry_sexp_find_token(m_platformKey, "p", 0));
511+
if (!nSexp || !eSexp || !dSexp || !pSexp || !qSexp)
512+
return Exception { OperationError };
513+
514+
// Write the MPI data of retrieved s-expression tokens under `modulus`, `publicExponent`,
515+
// `privateExponent`, `prime1` and `prime2`.
516+
{
517+
auto modulus = mpiSignedData(nSexp);
518+
auto publicExponent = mpiSignedData(eSexp);
519+
auto privateExponent = mpiSignedData(dSexp);
520+
auto prime1 = mpiSignedData(pSexp);
521+
auto prime2 = mpiSignedData(qSexp);
522+
if (!modulus || !publicExponent || !privateExponent || !prime1 || !prime2)
523+
return Exception { OperationError };
524+
525+
if (!PAL::TASN1::writeElement(rsaPrivateKey, "modulus", modulus->data(), modulus->size())
526+
|| !PAL::TASN1::writeElement(rsaPrivateKey, "publicExponent", publicExponent->data(), publicExponent->size())
527+
|| !PAL::TASN1::writeElement(rsaPrivateKey, "privateExponent", privateExponent->data(), privateExponent->size())
528+
|| !PAL::TASN1::writeElement(rsaPrivateKey, "prime1", prime1->data(), prime1->size())
529+
|| !PAL::TASN1::writeElement(rsaPrivateKey, "prime2", prime2->data(), prime2->size()))
530+
return Exception { OperationError };
531+
}
532+
533+
// Manually compute the MPI values for the `exponent1`, `exponent2` and `coefficient`
534+
// parameters. Again note the swapped usage of the `p` and `q` s-expression parameters.
535+
{
536+
PAL::GCrypt::Handle<gcry_mpi_t> dMPI(gcry_sexp_nth_mpi(dSexp, 1, GCRYMPI_FMT_USG));
537+
PAL::GCrypt::Handle<gcry_mpi_t> pMPI(gcry_sexp_nth_mpi(pSexp, 1, GCRYMPI_FMT_USG));
538+
PAL::GCrypt::Handle<gcry_mpi_t> qMPI(gcry_sexp_nth_mpi(qSexp, 1, GCRYMPI_FMT_USG));
539+
if (!dMPI || !pMPI || !qMPI)
540+
return Exception { OperationError };
541+
542+
// `exponent1`
543+
{
544+
PAL::GCrypt::Handle<gcry_mpi_t> dpMPI(gcry_mpi_set_ui(nullptr, 0));
545+
PAL::GCrypt::Handle<gcry_mpi_t> pm1MPI(gcry_mpi_set(nullptr, pMPI));
546+
gcry_mpi_sub_ui(pm1MPI, pm1MPI, 1);
547+
gcry_mpi_mod(dpMPI, dMPI, pm1MPI);
548+
549+
auto dp = mpiSignedData(dpMPI);
550+
if (!dp || !PAL::TASN1::writeElement(rsaPrivateKey, "exponent1", dp->data(), dp->size()))
551+
return Exception { OperationError };
552+
}
553+
554+
// `exponent2`
555+
{
556+
PAL::GCrypt::Handle<gcry_mpi_t> dqMPI(gcry_mpi_set_ui(nullptr, 0));
557+
PAL::GCrypt::Handle<gcry_mpi_t> qm1MPI(gcry_mpi_set(nullptr, qMPI));
558+
gcry_mpi_sub_ui(qm1MPI, qm1MPI, 1);
559+
gcry_mpi_mod(dqMPI, dMPI, qm1MPI);
560+
561+
auto dq = mpiSignedData(dqMPI);
562+
if (!dq || !PAL::TASN1::writeElement(rsaPrivateKey, "exponent2", dq->data(), dq->size()))
563+
return Exception { OperationError };
564+
}
565+
566+
// `coefficient`
567+
{
568+
PAL::GCrypt::Handle<gcry_mpi_t> qiMPI(gcry_mpi_set_ui(nullptr, 0));
569+
gcry_mpi_invm(qiMPI, qMPI, pMPI);
570+
571+
auto qi = mpiSignedData(qiMPI);
572+
if (!qi || !PAL::TASN1::writeElement(rsaPrivateKey, "coefficient", qi->data(), qi->size()))
573+
return Exception { OperationError };
574+
}
575+
}
576+
577+
// Eliminate the optional `otherPrimeInfos` element.
578+
// FIXME: this should be supported in the future, if there is such information available.
579+
if (!PAL::TASN1::writeElement(rsaPrivateKey, "otherPrimeInfos", nullptr, 0))
580+
return Exception { OperationError };
581+
}
582+
583+
PAL::TASN1::Structure pkcs8;
584+
{
585+
// Create the `PrivateKeyInfo` structure.
586+
if (!PAL::TASN1::createStructure("WebCrypto.PrivateKeyInfo", &pkcs8))
587+
return Exception { OperationError };
588+
589+
// Write out '0' under `version`.
590+
if (!PAL::TASN1::writeElement(pkcs8, "version", "0", 0))
591+
return Exception { OperationError };
592+
593+
// Write out the id-rsaEncryption identifier under `algorithm.algorithm`.
594+
// FIXME: In case the key algorithm is:
595+
// - RSA-PSS:
596+
// - this should write out id-RSASSA-PSS, along with setting `algorithm.parameters`
597+
// to a RSASSA-PSS-params structure
598+
// - RSA-OAEP:
599+
// - this should write out id-RSAES-OAEP, along with setting `algorithm.parameters`
600+
// to a RSAES-OAEP-params structure
601+
if (!PAL::TASN1::writeElement(pkcs8, "privateKeyAlgorithm.algorithm", "1.2.840.113549.1.1.1", 1))
602+
return Exception { OperationError };
603+
604+
// Write out a null value under `algorithm.parameters`.
605+
if (!PAL::TASN1::writeElement(pkcs8, "privateKeyAlgorithm.parameters", "\x05\x00", 2))
606+
return Exception { OperationError };
607+
608+
// Write out the `RSAPrivateKey` data under `privateKey`.
609+
{
610+
auto data = PAL::TASN1::encodedData(rsaPrivateKey, "");
611+
if (!data || !PAL::TASN1::writeElement(pkcs8, "privateKey", data->data(), data->size()))
612+
return Exception { OperationError };
613+
}
492614

493-
return Exception { NOT_SUPPORTED_ERR };
615+
// Eliminate the optional `attributes` element.
616+
if (!PAL::TASN1::writeElement(pkcs8, "attributes", nullptr, 0))
617+
return Exception { OperationError };
618+
}
619+
620+
// Retrieve the encoded `PrivateKeyInfo` data and return it.
621+
auto result = PAL::TASN1::encodedData(pkcs8, "");
622+
if (!result)
623+
return Exception { OperationError };
624+
625+
return WTFMove(result.value());
494626
}
495627

496628
std::unique_ptr<KeyAlgorithm> CryptoKeyRSA::buildAlgorithm() const

0 commit comments

Comments
 (0)