237dff1c153edfa928fc741b323647868ec91a77
[WebKit-https.git] / Source / WebCore / crypto / gcrypt / CryptoKeyRSAGCrypt.cpp
1 /*
2  * Copyright (C) 2014 Igalia S.L. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "CryptoKeyRSA.h"
28
29 #if ENABLE(SUBTLE_CRYPTO)
30
31 #include "CryptoAlgorithmRegistry.h"
32 #include "CryptoKeyDataRSAComponents.h"
33 #include "CryptoKeyPair.h"
34 #include "GCryptUtilities.h"
35 #include "NotImplemented.h"
36 #include "ScriptExecutionContext.h"
37 #include <pal/crypto/gcrypt/Handle.h>
38 #include <pal/crypto/gcrypt/Utilities.h>
39 #include <pal/crypto/tasn1/Utilities.h>
40
41 namespace WebCore {
42
43 static size_t getRSAModulusLength(gcry_sexp_t keySexp)
44 {
45     // Retrieve the s-expression token for the public modulus N of the given RSA key.
46     PAL::GCrypt::Handle<gcry_sexp_t> nSexp(gcry_sexp_find_token(keySexp, "n", 0));
47     if (!nSexp)
48         return 0;
49
50     // Retrieve the MPI length for the corresponding s-expression token, in bits.
51     auto length = mpiLength(nSexp);
52     if (!length)
53         return 0;
54
55     return *length * 8;
56 }
57
58 static Vector<uint8_t> getRSAKeyParameter(gcry_sexp_t keySexp, const char* name)
59 {
60     // Retrieve the s-expression token for the specified parameter of the given RSA key.
61     PAL::GCrypt::Handle<gcry_sexp_t> paramSexp(gcry_sexp_find_token(keySexp, name, 0));
62     if (!paramSexp)
63         return { };
64
65     // Retrieve the MPI data for the corresponding s-expression token.
66     auto data = mpiData(paramSexp);
67     if (!data)
68         return { };
69
70     return WTFMove(data.value());
71 }
72
73 RefPtr<CryptoKeyRSA> CryptoKeyRSA::create(CryptoAlgorithmIdentifier identifier, CryptoAlgorithmIdentifier hash, bool hasHash, const CryptoKeyDataRSAComponents& keyData, bool extractable, CryptoKeyUsageBitmap usages)
74 {
75     // When creating a private key, we require the p and q prime information.
76     if (keyData.type() == CryptoKeyDataRSAComponents::Type::Private && !keyData.hasAdditionalPrivateKeyParameters())
77         return nullptr;
78
79     // But we don't currently support creating keys with any additional prime information.
80     if (!keyData.otherPrimeInfos().isEmpty())
81         return nullptr;
82
83     // Validate the key data.
84     {
85         bool valid = true;
86
87         // For both public and private keys, we need the public modulus and exponent.
88         valid &= !keyData.modulus().isEmpty() && !keyData.exponent().isEmpty();
89
90         // For private keys, we require the private exponent, as well as p and q prime information.
91         if (keyData.type() == CryptoKeyDataRSAComponents::Type::Private)
92             valid &= !keyData.privateExponent().isEmpty() && !keyData.firstPrimeInfo().primeFactor.isEmpty() && !keyData.secondPrimeInfo().primeFactor.isEmpty();
93
94         if (!valid)
95             return nullptr;
96     }
97
98     CryptoKeyType keyType;
99     switch (keyData.type()) {
100     case CryptoKeyDataRSAComponents::Type::Public:
101         keyType = CryptoKeyType::Public;
102         break;
103     case CryptoKeyDataRSAComponents::Type::Private:
104         keyType = CryptoKeyType::Private;
105         break;
106     }
107
108     // Construct the key s-expression, using the data that's available.
109     PAL::GCrypt::Handle<gcry_sexp_t> keySexp;
110     {
111         gcry_error_t error = GPG_ERR_NO_ERROR;
112
113         switch (keyType) {
114         case CryptoKeyType::Public:
115             error = gcry_sexp_build(&keySexp, nullptr, "(public-key(rsa(n %b)(e %b)))",
116                 keyData.modulus().size(), keyData.modulus().data(),
117                 keyData.exponent().size(), keyData.exponent().data());
118             break;
119         case CryptoKeyType::Private:
120             if (keyData.hasAdditionalPrivateKeyParameters()) {
121                 error = gcry_sexp_build(&keySexp, nullptr, "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)))",
122                     keyData.modulus().size(), keyData.modulus().data(),
123                     keyData.exponent().size(), keyData.exponent().data(),
124                     keyData.privateExponent().size(), keyData.privateExponent().data(),
125                     keyData.secondPrimeInfo().primeFactor.size(), keyData.secondPrimeInfo().primeFactor.data(),
126                     keyData.firstPrimeInfo().primeFactor.size(), keyData.firstPrimeInfo().primeFactor.data());
127                 break;
128             }
129
130             error = gcry_sexp_build(&keySexp, nullptr, "(private-key(rsa(n %b)(e %b)(d %b)))",
131                 keyData.modulus().size(), keyData.modulus().data(),
132                 keyData.exponent().size(), keyData.exponent().data(),
133                 keyData.privateExponent().size(), keyData.privateExponent().data());
134             break;
135         case CryptoKeyType::Secret:
136             ASSERT_NOT_REACHED();
137             return nullptr;
138         }
139
140         if (error != GPG_ERR_NO_ERROR) {
141             PAL::GCrypt::logError(error);
142             return nullptr;
143         }
144     }
145
146     return adoptRef(new CryptoKeyRSA(identifier, hash, hasHash, keyType, keySexp.release(), extractable, usages));
147 }
148
149 CryptoKeyRSA::CryptoKeyRSA(CryptoAlgorithmIdentifier identifier, CryptoAlgorithmIdentifier hash, bool hasHash, CryptoKeyType type, PlatformRSAKey platformKey, bool extractable, CryptoKeyUsageBitmap usage)
150     : CryptoKey(identifier, type, extractable, usage)
151     , m_platformKey(platformKey)
152     , m_restrictedToSpecificHash(hasHash)
153     , m_hash(hash)
154 {
155 }
156
157 CryptoKeyRSA::~CryptoKeyRSA()
158 {
159     if (m_platformKey)
160         PAL::GCrypt::HandleDeleter<gcry_sexp_t>()(m_platformKey);
161 }
162
163 bool CryptoKeyRSA::isRestrictedToHash(CryptoAlgorithmIdentifier& identifier) const
164 {
165     if (!m_restrictedToSpecificHash)
166         return false;
167
168     identifier = m_hash;
169     return true;
170 }
171
172 size_t CryptoKeyRSA::keySizeInBits() const
173 {
174     return getRSAModulusLength(m_platformKey);
175 }
176
177 // Convert the exponent vector to a 32-bit value, if possible.
178 static std::optional<uint32_t> exponentVectorToUInt32(const Vector<uint8_t>& exponent)
179 {
180     if (exponent.size() > 4) {
181         if (std::any_of(exponent.begin(), exponent.end() - 4, [](uint8_t element) { return !!element; }))
182             return std::nullopt;
183     }
184
185     uint32_t result = 0;
186     for (size_t size = exponent.size(), i = std::min<size_t>(4, size); i > 0; --i) {
187         result <<= 8;
188         result += exponent[size - i];
189     }
190
191     return result;
192 }
193
194 void CryptoKeyRSA::generatePair(CryptoAlgorithmIdentifier algorithm, CryptoAlgorithmIdentifier hash, bool hasHash, unsigned modulusLength, const Vector<uint8_t>& publicExponent, bool extractable, CryptoKeyUsageBitmap usage, KeyPairCallback&& callback, VoidCallback&& failureCallback, ScriptExecutionContext* context)
195 {
196     // libgcrypt doesn't report an error if the exponent is smaller than three or even.
197     auto e = exponentVectorToUInt32(publicExponent);
198     if (!e || *e < 3 || !(*e & 0x1)) {
199         failureCallback();
200         return;
201     }
202
203     // libgcrypt doesn't support generating primes of less than 16 bits.
204     if (modulusLength < 16) {
205         failureCallback();
206         return;
207     }
208
209     PAL::GCrypt::Handle<gcry_sexp_t> genkeySexp;
210     gcry_error_t error = gcry_sexp_build(&genkeySexp, nullptr, "(genkey(rsa(nbits %d)(rsa-use-e %d)))", modulusLength, *e);
211     if (error != GPG_ERR_NO_ERROR) {
212         PAL::GCrypt::logError(error);
213         failureCallback();
214         return;
215     }
216
217     PAL::GCrypt::Handle<gcry_sexp_t> keyPairSexp;
218     error = gcry_pk_genkey(&keyPairSexp, genkeySexp);
219     if (error != GPG_ERR_NO_ERROR) {
220         PAL::GCrypt::logError(error);
221         failureCallback();
222         return;
223     }
224
225     PAL::GCrypt::Handle<gcry_sexp_t> publicKeySexp(gcry_sexp_find_token(keyPairSexp, "public-key", 0));
226     PAL::GCrypt::Handle<gcry_sexp_t> privateKeySexp(gcry_sexp_find_token(keyPairSexp, "private-key", 0));
227     if (!publicKeySexp || !privateKeySexp) {
228         failureCallback();
229         return;
230     }
231
232     context->ref();
233     context->postTask(
234         [algorithm, hash, hasHash, extractable, usage, publicKeySexp = publicKeySexp.release(), privateKeySexp = privateKeySexp.release(), callback = WTFMove(callback)](ScriptExecutionContext& context) mutable {
235             auto publicKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Public, publicKeySexp, true, usage);
236             auto privateKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Private, privateKeySexp, extractable, usage);
237
238             callback(CryptoKeyPair { WTFMove(publicKey), WTFMove(privateKey) });
239             context.deref();
240         });
241 }
242
243 static bool supportedAlgorithmIdentifier(const uint8_t* data, size_t size)
244 {
245     // FIXME: This is far from sufficient. Per the spec, when importing for key algorithm
246     // - RSASSA-PKCS1-v1_5:
247     //     - rsaEncryption, sha{1,256,384,512}WithRSAEncryption OIDs must be supported
248     //     - in case of sha{1,256,384,512}WithRSAEncryption OIDs the specified hash algorithm
249     //       has to match the algorithm in the OID
250     // - RSA-PSS:
251     //     - rsaEncryption, id-RSASSA-PSS OIDs must be supported
252     //     - in case of id-RSASSA-PSS OID the parameters field of AlgorithmIdentifier has
253     //       to be decoded as RSASSA-PSS-params ASN.1 structure, and the hashAlgorithm field
254     //       of that structure has to contain one of id-sha{1,256,384,512} OIDs that match
255     //       the specified hash algorithm
256     // - RSA-OAEP:
257     //     - rsaEncryption, id-RSAES-OAEP OIDS must be supported
258     //     - in case of id-RSAES-OAEP OID the parameters field of AlgorithmIdentifier has
259     //       to be decoded as RSAES-OAEP-params ASN.1 structure, and the hashAlgorithm field
260     //       of that structure has to contain one of id-sha{1,256,384,512} OIDs that match
261     //       the specified hash algorithm
262
263     if (CryptoConstants::matches(data, size, CryptoConstants::s_rsaEncryptionIdentifier))
264         return true;
265     if (CryptoConstants::matches(data, size, CryptoConstants::s_RSAES_OAEPIdentifier))
266         return false; // Not yet supported.
267     if (CryptoConstants::matches(data, size, CryptoConstants::s_RSASSA_PSSIdentifier))
268         return false; // Not yet supported.
269     return false;
270 }
271
272 RefPtr<CryptoKeyRSA> CryptoKeyRSA::importSpki(CryptoAlgorithmIdentifier identifier, std::optional<CryptoAlgorithmIdentifier> hash, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
273 {
274     // Decode the `SubjectPublicKeyInfo` structure using the provided key data.
275     PAL::TASN1::Structure spki;
276     if (!PAL::TASN1::decodeStructure(&spki, "WebCrypto.SubjectPublicKeyInfo", keyData))
277         return nullptr;
278
279     // Validate `algorithm.algorithm`.
280     {
281         auto algorithm = PAL::TASN1::elementData(spki, "algorithm.algorithm");
282         if (!algorithm)
283             return nullptr;
284
285         if (!supportedAlgorithmIdentifier(algorithm->data(), algorithm->size()))
286             return nullptr;
287     }
288
289     // Decode the `RSAPublicKey` structure using the `subjectPublicKey` data.
290     PAL::TASN1::Structure rsaPublicKey;
291     {
292         auto subjectPublicKey = PAL::TASN1::elementData(spki, "subjectPublicKey");
293         if (!subjectPublicKey)
294             return nullptr;
295
296         if (!PAL::TASN1::decodeStructure(&rsaPublicKey, "WebCrypto.RSAPublicKey", *subjectPublicKey))
297             return nullptr;
298     }
299
300     // Retrieve the `modulus` and `publicExponent` data and embed it into the `public-key` s-expression.
301     PAL::GCrypt::Handle<gcry_sexp_t> platformKey;
302     {
303         auto modulus = PAL::TASN1::elementData(rsaPublicKey, "modulus");
304         auto publicExponent = PAL::TASN1::elementData(rsaPublicKey, "publicExponent");
305         if (!modulus || !publicExponent)
306             return nullptr;
307
308         gcry_error_t error = gcry_sexp_build(&platformKey, nullptr, "(public-key(rsa(n %b)(e %b)))",
309             modulus->size(), modulus->data(), publicExponent->size(), publicExponent->data());
310         if (error != GPG_ERR_NO_ERROR) {
311             PAL::GCrypt::logError(error);
312             return nullptr;
313         }
314     }
315
316     return adoptRef(new CryptoKeyRSA(identifier, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, CryptoKeyType::Public, platformKey.release(), extractable, usages));
317 }
318
319 RefPtr<CryptoKeyRSA> CryptoKeyRSA::importPkcs8(CryptoAlgorithmIdentifier identifier, std::optional<CryptoAlgorithmIdentifier> hash, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
320 {
321     // Decode the `PrivateKeyInfo` structure using the provided key data.
322     PAL::TASN1::Structure pkcs8;
323     if (!PAL::TASN1::decodeStructure(&pkcs8, "WebCrypto.PrivateKeyInfo", keyData))
324         return nullptr;
325
326     // Validate `version`.
327     {
328         auto version = PAL::TASN1::elementData(pkcs8, "version");
329         if (!version)
330             return nullptr;
331
332         if (!CryptoConstants::matches(version->data(), version->size(), CryptoConstants::s_asn1Version0))
333             return nullptr;
334     }
335
336     // Validate `privateKeyAlgorithm.algorithm`.
337     {
338         auto algorithm = PAL::TASN1::elementData(pkcs8, "privateKeyAlgorithm.algorithm");
339         if (!algorithm)
340             return nullptr;
341
342         if (!supportedAlgorithmIdentifier(algorithm->data(), algorithm->size()))
343             return nullptr;
344     }
345
346     // Decode the `RSAPrivateKey` structure using the `privateKey` data.
347     PAL::TASN1::Structure rsaPrivateKey;
348     {
349         auto privateKey = PAL::TASN1::elementData(pkcs8, "privateKey");
350         if (!privateKey)
351             return nullptr;
352
353         if (!PAL::TASN1::decodeStructure(&rsaPrivateKey, "WebCrypto.RSAPrivateKey", *privateKey))
354             return nullptr;
355     }
356
357     // Validate `privateKey.version`.
358     {
359         auto version = PAL::TASN1::elementData(rsaPrivateKey, "version");
360         if (!version)
361             return nullptr;
362
363         if (!CryptoConstants::matches(version->data(), version->size(), CryptoConstants::s_asn1Version0))
364             return nullptr;
365     }
366
367     // Retrieve the `modulus`, `publicExponent`, `privateExponent`, `prime1`, `prime2`,
368     // `exponent1`, `exponent2` and `coefficient` data and embed it into the `public-key` s-expression.
369     PAL::GCrypt::Handle<gcry_sexp_t> platformKey;
370     {
371         auto modulus = PAL::TASN1::elementData(rsaPrivateKey, "modulus");
372         auto publicExponent = PAL::TASN1::elementData(rsaPrivateKey, "publicExponent");
373         auto privateExponent = PAL::TASN1::elementData(rsaPrivateKey, "privateExponent");
374         auto prime1 = PAL::TASN1::elementData(rsaPrivateKey, "prime1");
375         auto prime2 = PAL::TASN1::elementData(rsaPrivateKey, "prime2");
376         auto exponent1 = PAL::TASN1::elementData(rsaPrivateKey, "exponent1");
377         auto exponent2 = PAL::TASN1::elementData(rsaPrivateKey, "exponent2");
378         auto coefficient = PAL::TASN1::elementData(rsaPrivateKey, "coefficient");
379
380         if (!modulus || !publicExponent || !privateExponent
381             || !prime1 || !prime2 || !exponent1 || !exponent2 || !coefficient)
382             return nullptr;
383
384         // libgcrypt inverts the use of p and q parameters, so we have to recalculate the `coefficient` value.
385         PAL::GCrypt::Handle<gcry_mpi_t> uMPI(gcry_mpi_new(0));
386         {
387             PAL::GCrypt::Handle<gcry_mpi_t> pMPI;
388             gcry_error_t error = gcry_mpi_scan(&pMPI, GCRYMPI_FMT_USG, prime1->data(), prime1->size(), nullptr);
389             if (error != GPG_ERR_NO_ERROR)
390                 return nullptr;
391
392             PAL::GCrypt::Handle<gcry_mpi_t> qMPI;
393             error = gcry_mpi_scan(&qMPI, GCRYMPI_FMT_USG, prime2->data(), prime2->size(), nullptr);
394             if (error != GPG_ERR_NO_ERROR)
395                 return nullptr;
396
397             gcry_mpi_invm(uMPI, qMPI, pMPI);
398         }
399
400         gcry_error_t error = gcry_sexp_build(&platformKey, nullptr, "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)(u %M)))",
401             modulus->size(), modulus->data(),
402             publicExponent->size(), publicExponent->data(),
403             privateExponent->size(), privateExponent->data(),
404             prime2->size(), prime2->data(), prime1->size(), prime1->data(), uMPI.handle());
405         if (error != GPG_ERR_NO_ERROR) {
406             PAL::GCrypt::logError(error);
407             return nullptr;
408         }
409     }
410
411     return adoptRef(new CryptoKeyRSA(identifier, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, CryptoKeyType::Private, platformKey.release(), extractable, usages));
412 }
413
414 ExceptionOr<Vector<uint8_t>> CryptoKeyRSA::exportSpki() const
415 {
416     if (type() != CryptoKeyType::Public)
417         return Exception { InvalidAccessError };
418
419     PAL::TASN1::Structure rsaPublicKey;
420     {
421         // Create the `RSAPublicKey` structure.
422         if (!PAL::TASN1::createStructure("WebCrypto.RSAPublicKey", &rsaPublicKey))
423             return Exception { OperationError };
424
425         // Retrieve the modulus and public exponent s-expressions.
426         PAL::GCrypt::Handle<gcry_sexp_t> modulusSexp(gcry_sexp_find_token(m_platformKey, "n", 0));
427         PAL::GCrypt::Handle<gcry_sexp_t> publicExponentSexp(gcry_sexp_find_token(m_platformKey, "e", 0));
428         if (!modulusSexp || !publicExponentSexp)
429             return Exception { OperationError };
430
431         // Retrieve MPI data for the modulus and public exponent components.
432         auto modulus = mpiSignedData(modulusSexp);
433         auto publicExponent = mpiSignedData(publicExponentSexp);
434         if (!modulus || !publicExponent)
435             return Exception { OperationError };
436
437         // Write out the modulus data under `modulus`.
438         if (!PAL::TASN1::writeElement(rsaPublicKey, "modulus", modulus->data(), modulus->size()))
439             return Exception { OperationError };
440
441         // Write out the public exponent data under `publicExponent`.
442         if (!PAL::TASN1::writeElement(rsaPublicKey, "publicExponent", publicExponent->data(), publicExponent->size()))
443             return Exception { OperationError };
444     }
445
446     PAL::TASN1::Structure spki;
447     {
448         // Create the `SubjectPublicKeyInfo` structure.
449         if (!PAL::TASN1::createStructure("WebCrypto.SubjectPublicKeyInfo", &spki))
450             return Exception { OperationError };
451
452         // Write out the id-rsaEncryption identifier under `algorithm.algorithm`.
453         // FIXME: In case the key algorithm is:
454         // - RSA-PSS:
455         //     - this should write out id-RSASSA-PSS, along with setting `algorithm.parameters`
456         //       to a RSASSA-PSS-params structure
457         // - RSA-OAEP:
458         //     - this should write out id-RSAES-OAEP, along with setting `algorithm.parameters`
459         //       to a RSAES-OAEP-params structure
460         if (!PAL::TASN1::writeElement(spki, "algorithm.algorithm", CryptoConstants::s_rsaEncryptionIdentifier.data(), 1))
461             return Exception { OperationError };
462
463         // Write out the null value under `algorithm.parameters`.
464         if (!PAL::TASN1::writeElement(spki, "algorithm.parameters", CryptoConstants::s_asn1NullValue.data(), CryptoConstants::s_asn1NullValue.size()))
465             return Exception { OperationError };
466
467         // Write out the `RSAPublicKey` data under `subjectPublicKey`. Because this is a
468         // bit string parameter, the data size has to be multiplied by 8.
469         {
470             auto data = PAL::TASN1::encodedData(rsaPublicKey, "");
471             if (!data || !PAL::TASN1::writeElement(spki, "subjectPublicKey", data->data(), data->size() * 8))
472                 return Exception { OperationError };
473         }
474     }
475
476     // Retrieve the encoded `SubjectPublicKeyInfo` data and return it.
477     auto result = PAL::TASN1::encodedData(spki, "");
478     if (!result)
479         return Exception { OperationError };
480
481     return WTFMove(result.value());
482 }
483
484 ExceptionOr<Vector<uint8_t>> CryptoKeyRSA::exportPkcs8() const
485 {
486     if (type() != CryptoKeyType::Private)
487         return Exception { InvalidAccessError };
488
489     PAL::TASN1::Structure rsaPrivateKey;
490     {
491         // Create the `RSAPrivateKey` structure.
492         if (!PAL::TASN1::createStructure("WebCrypto.RSAPrivateKey", &rsaPrivateKey))
493             return Exception { OperationError };
494
495         // Write out '0' under `version`.
496         if (!PAL::TASN1::writeElement(rsaPrivateKey, "version", "0", 0))
497             return Exception { OperationError };
498
499         // Retrieve the `n`, `e`, `d`, `q` and `p` s-expression tokens. libgcrypt swaps the usage of
500         // the p and q primes internally, so we adjust the lookup accordingly.
501         PAL::GCrypt::Handle<gcry_sexp_t> nSexp(gcry_sexp_find_token(m_platformKey, "n", 0));
502         PAL::GCrypt::Handle<gcry_sexp_t> eSexp(gcry_sexp_find_token(m_platformKey, "e", 0));
503         PAL::GCrypt::Handle<gcry_sexp_t> dSexp(gcry_sexp_find_token(m_platformKey, "d", 0));
504         PAL::GCrypt::Handle<gcry_sexp_t> pSexp(gcry_sexp_find_token(m_platformKey, "q", 0));
505         PAL::GCrypt::Handle<gcry_sexp_t> qSexp(gcry_sexp_find_token(m_platformKey, "p", 0));
506         if (!nSexp || !eSexp || !dSexp || !pSexp || !qSexp)
507             return Exception { OperationError };
508
509         // Write the MPI data of retrieved s-expression tokens under `modulus`, `publicExponent`,
510         // `privateExponent`, `prime1` and `prime2`.
511         {
512             auto modulus = mpiSignedData(nSexp);
513             auto publicExponent = mpiSignedData(eSexp);
514             auto privateExponent = mpiSignedData(dSexp);
515             auto prime1 = mpiSignedData(pSexp);
516             auto prime2 = mpiSignedData(qSexp);
517             if (!modulus || !publicExponent || !privateExponent || !prime1 || !prime2)
518                 return Exception { OperationError };
519
520             if (!PAL::TASN1::writeElement(rsaPrivateKey, "modulus", modulus->data(), modulus->size())
521                 || !PAL::TASN1::writeElement(rsaPrivateKey, "publicExponent", publicExponent->data(), publicExponent->size())
522                 || !PAL::TASN1::writeElement(rsaPrivateKey, "privateExponent", privateExponent->data(), privateExponent->size())
523                 || !PAL::TASN1::writeElement(rsaPrivateKey, "prime1", prime1->data(), prime1->size())
524                 || !PAL::TASN1::writeElement(rsaPrivateKey, "prime2", prime2->data(), prime2->size()))
525                 return Exception { OperationError };
526         }
527
528         // Manually compute the MPI values for the `exponent1`, `exponent2` and `coefficient`
529         // parameters. Again note the swapped usage of the `p` and `q` s-expression parameters.
530         {
531             PAL::GCrypt::Handle<gcry_mpi_t> dMPI(gcry_sexp_nth_mpi(dSexp, 1, GCRYMPI_FMT_USG));
532             PAL::GCrypt::Handle<gcry_mpi_t> pMPI(gcry_sexp_nth_mpi(pSexp, 1, GCRYMPI_FMT_USG));
533             PAL::GCrypt::Handle<gcry_mpi_t> qMPI(gcry_sexp_nth_mpi(qSexp, 1, GCRYMPI_FMT_USG));
534             if (!dMPI || !pMPI || !qMPI)
535                 return Exception { OperationError };
536
537             // `exponent1`
538             {
539                 PAL::GCrypt::Handle<gcry_mpi_t> dpMPI(gcry_mpi_set_ui(nullptr, 0));
540                 PAL::GCrypt::Handle<gcry_mpi_t> pm1MPI(gcry_mpi_set(nullptr, pMPI));
541                 gcry_mpi_sub_ui(pm1MPI, pm1MPI, 1);
542                 gcry_mpi_mod(dpMPI, dMPI, pm1MPI);
543
544                 auto dp = mpiSignedData(dpMPI);
545                 if (!dp || !PAL::TASN1::writeElement(rsaPrivateKey, "exponent1", dp->data(), dp->size()))
546                     return Exception { OperationError };
547             }
548
549             // `exponent2`
550             {
551                 PAL::GCrypt::Handle<gcry_mpi_t> dqMPI(gcry_mpi_set_ui(nullptr, 0));
552                 PAL::GCrypt::Handle<gcry_mpi_t> qm1MPI(gcry_mpi_set(nullptr, qMPI));
553                 gcry_mpi_sub_ui(qm1MPI, qm1MPI, 1);
554                 gcry_mpi_mod(dqMPI, dMPI, qm1MPI);
555
556                 auto dq = mpiSignedData(dqMPI);
557                 if (!dq || !PAL::TASN1::writeElement(rsaPrivateKey, "exponent2", dq->data(), dq->size()))
558                     return Exception { OperationError };
559             }
560
561             // `coefficient`
562             {
563                 PAL::GCrypt::Handle<gcry_mpi_t> qiMPI(gcry_mpi_set_ui(nullptr, 0));
564                 gcry_mpi_invm(qiMPI, qMPI, pMPI);
565
566                 auto qi = mpiSignedData(qiMPI);
567                 if (!qi || !PAL::TASN1::writeElement(rsaPrivateKey, "coefficient", qi->data(), qi->size()))
568                     return Exception { OperationError };
569             }
570         }
571
572         // Eliminate the optional `otherPrimeInfos` element.
573         // FIXME: this should be supported in the future, if there is such information available.
574         if (!PAL::TASN1::writeElement(rsaPrivateKey, "otherPrimeInfos", nullptr, 0))
575             return Exception { OperationError };
576     }
577
578     PAL::TASN1::Structure pkcs8;
579     {
580         // Create the `PrivateKeyInfo` structure.
581         if (!PAL::TASN1::createStructure("WebCrypto.PrivateKeyInfo", &pkcs8))
582             return Exception { OperationError };
583
584         // Write out '0' under `version`.
585         if (!PAL::TASN1::writeElement(pkcs8, "version", "0", 0))
586             return Exception { OperationError };
587
588         // Write out the id-rsaEncryption identifier under `algorithm.algorithm`.
589         // FIXME: In case the key algorithm is:
590         // - RSA-PSS:
591         //     - this should write out id-RSASSA-PSS, along with setting `algorithm.parameters`
592         //       to a RSASSA-PSS-params structure
593         // - RSA-OAEP:
594         //     - this should write out id-RSAES-OAEP, along with setting `algorithm.parameters`
595         //       to a RSAES-OAEP-params structure
596         if (!PAL::TASN1::writeElement(pkcs8, "privateKeyAlgorithm.algorithm", "1.2.840.113549.1.1.1", 1))
597             return Exception { OperationError };
598
599         // Write out a null value under `algorithm.parameters`.
600         if (!PAL::TASN1::writeElement(pkcs8, "privateKeyAlgorithm.parameters", CryptoConstants::s_asn1NullValue.data(), CryptoConstants::s_asn1NullValue.size()))
601             return Exception { OperationError };
602
603         // Write out the `RSAPrivateKey` data under `privateKey`.
604         {
605             auto data = PAL::TASN1::encodedData(rsaPrivateKey, "");
606             if (!data || !PAL::TASN1::writeElement(pkcs8, "privateKey", data->data(), data->size()))
607                 return Exception { OperationError };
608         }
609
610         // Eliminate the optional `attributes` element.
611         if (!PAL::TASN1::writeElement(pkcs8, "attributes", nullptr, 0))
612             return Exception { OperationError };
613     }
614
615     // Retrieve the encoded `PrivateKeyInfo` data and return it.
616     auto result = PAL::TASN1::encodedData(pkcs8, "");
617     if (!result)
618         return Exception { OperationError };
619
620     return WTFMove(result.value());
621 }
622
623 std::unique_ptr<KeyAlgorithm> CryptoKeyRSA::buildAlgorithm() const
624 {
625     String name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
626     size_t modulusLength = getRSAModulusLength(m_platformKey);
627     Vector<uint8_t> publicExponent = getRSAKeyParameter(m_platformKey, "e");
628
629     if (m_restrictedToSpecificHash)
630         return std::make_unique<RsaHashedKeyAlgorithm>(name, modulusLength, WTFMove(publicExponent), CryptoAlgorithmRegistry::singleton().name(m_hash));
631     return std::make_unique<RsaKeyAlgorithm>(name, modulusLength, WTFMove(publicExponent));
632 }
633
634 std::unique_ptr<CryptoKeyData> CryptoKeyRSA::exportData() const
635 {
636     ASSERT(extractable());
637
638     switch (type()) {
639     case CryptoKeyType::Public:
640         return CryptoKeyDataRSAComponents::createPublic(getRSAKeyParameter(m_platformKey, "n"), getRSAKeyParameter(m_platformKey, "e"));
641     case CryptoKeyType::Private: {
642         auto parameterMPI =
643             [](gcry_sexp_t sexp, const char* name) -> gcry_mpi_t {
644                 PAL::GCrypt::Handle<gcry_sexp_t> paramSexp(gcry_sexp_find_token(sexp, name, 0));
645                 if (!paramSexp)
646                     return nullptr;
647                 return gcry_sexp_nth_mpi(paramSexp, 1, GCRYMPI_FMT_USG);
648             };
649
650         PAL::GCrypt::Handle<gcry_mpi_t> dMPI(parameterMPI(m_platformKey, "d"));
651         // libgcrypt internally uses p and q such that p < q, while usually it's q < p.
652         // Switch the two primes here and continue with assuming the latter.
653         PAL::GCrypt::Handle<gcry_mpi_t> pMPI(parameterMPI(m_platformKey, "q"));
654         PAL::GCrypt::Handle<gcry_mpi_t> qMPI(parameterMPI(m_platformKey, "p"));
655         if (!dMPI || !pMPI || !qMPI)
656             return nullptr;
657
658         CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
659         if (auto data = mpiData(pMPI))
660             firstPrimeInfo.primeFactor = WTFMove(data.value());
661
662         CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
663         if (auto data = mpiData(qMPI))
664             secondPrimeInfo.primeFactor = WTFMove(data.value());
665
666         // dp -- d mod (p - 1)
667         {
668             PAL::GCrypt::Handle<gcry_mpi_t> dpMPI(gcry_mpi_new(0));
669             PAL::GCrypt::Handle<gcry_mpi_t> pm1MPI(gcry_mpi_new(0));
670             gcry_mpi_sub_ui(pm1MPI, pMPI, 1);
671             gcry_mpi_mod(dpMPI, dMPI, pm1MPI);
672
673             if (auto data = mpiData(dpMPI))
674                 firstPrimeInfo.factorCRTExponent = WTFMove(data.value());
675         }
676
677         // dq -- d mod (q - 1)
678         {
679             PAL::GCrypt::Handle<gcry_mpi_t> dqMPI(gcry_mpi_new(0));
680             PAL::GCrypt::Handle<gcry_mpi_t> qm1MPI(gcry_mpi_new(0));
681             gcry_mpi_sub_ui(qm1MPI, qMPI, 1);
682             gcry_mpi_mod(dqMPI, dMPI, qm1MPI);
683
684             if (auto data = mpiData(dqMPI))
685                 secondPrimeInfo.factorCRTExponent = WTFMove(data.value());
686         }
687
688         // qi -- q^(-1) mod p
689         {
690             PAL::GCrypt::Handle<gcry_mpi_t> qiMPI(gcry_mpi_new(0));
691             gcry_mpi_invm(qiMPI, qMPI, pMPI);
692
693             if (auto data = mpiData(qiMPI))
694                 secondPrimeInfo.factorCRTCoefficient = WTFMove(data.value());
695         }
696
697         Vector<uint8_t> privateExponent;
698         if (auto data = mpiData(dMPI))
699             privateExponent = WTFMove(data.value());
700
701         return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(
702             getRSAKeyParameter(m_platformKey, "n"), getRSAKeyParameter(m_platformKey, "e"), WTFMove(privateExponent),
703             WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), Vector<CryptoKeyDataRSAComponents::PrimeInfo> { });
704     }
705     default:
706         ASSERT_NOT_REACHED();
707         return nullptr;
708     }
709 }
710
711 } // namespace WebCore
712
713 #endif // ENABLE(SUBTLE_CRYPTO)