Use Optional::valueOr() instead of Optional::value_or()
[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(WEB_CRYPTO)
30
31 #include "CryptoAlgorithmRegistry.h"
32 #include "CryptoKeyPair.h"
33 #include "CryptoKeyRSAComponents.h"
34 #include "GCryptUtilities.h"
35 #include "ScriptExecutionContext.h"
36 #include <JavaScriptCore/GenericTypedArrayViewInlines.h>
37 #include <JavaScriptCore/HeapInlines.h>
38 #include <JavaScriptCore/JSGenericTypedArrayViewInlines.h>
39 #include <pal/crypto/gcrypt/Handle.h>
40 #include <pal/crypto/gcrypt/Utilities.h>
41 #include <pal/crypto/tasn1/Utilities.h>
42
43 namespace WebCore {
44
45 static size_t getRSAModulusLength(gcry_sexp_t keySexp)
46 {
47     // Retrieve the s-expression token for the public modulus N of the given RSA key.
48     PAL::GCrypt::Handle<gcry_sexp_t> nSexp(gcry_sexp_find_token(keySexp, "n", 0));
49     if (!nSexp)
50         return 0;
51
52     // Retrieve the MPI length for the corresponding s-expression token, in bits.
53     auto length = mpiLength(nSexp);
54     if (!length)
55         return 0;
56
57     return *length * 8;
58 }
59
60 static Vector<uint8_t> getRSAKeyParameter(gcry_sexp_t keySexp, const char* name)
61 {
62     // Retrieve the s-expression token for the specified parameter of the given RSA key.
63     PAL::GCrypt::Handle<gcry_sexp_t> paramSexp(gcry_sexp_find_token(keySexp, name, 0));
64     if (!paramSexp)
65         return { };
66
67     // Retrieve the MPI data for the corresponding s-expression token.
68     auto data = mpiData(paramSexp);
69     if (!data)
70         return { };
71
72     return WTFMove(data.value());
73 }
74
75 RefPtr<CryptoKeyRSA> CryptoKeyRSA::create(CryptoAlgorithmIdentifier identifier, CryptoAlgorithmIdentifier hash, bool hasHash, const CryptoKeyRSAComponents& keyData, bool extractable, CryptoKeyUsageBitmap usages)
76 {
77     // When creating a private key, we require the p and q prime information.
78     if (keyData.type() == CryptoKeyRSAComponents::Type::Private && !keyData.hasAdditionalPrivateKeyParameters())
79         return nullptr;
80
81     // But we don't currently support creating keys with any additional prime information.
82     if (!keyData.otherPrimeInfos().isEmpty())
83         return nullptr;
84
85     // Validate the key data.
86     {
87         bool valid = true;
88
89         // For both public and private keys, we need the public modulus and exponent.
90         valid &= !keyData.modulus().isEmpty() && !keyData.exponent().isEmpty();
91
92         // For private keys, we require the private exponent, as well as p and q prime information.
93         if (keyData.type() == CryptoKeyRSAComponents::Type::Private)
94             valid &= !keyData.privateExponent().isEmpty() && !keyData.firstPrimeInfo().primeFactor.isEmpty() && !keyData.secondPrimeInfo().primeFactor.isEmpty();
95
96         if (!valid)
97             return nullptr;
98     }
99
100     CryptoKeyType keyType;
101     switch (keyData.type()) {
102     case CryptoKeyRSAComponents::Type::Public:
103         keyType = CryptoKeyType::Public;
104         break;
105     case CryptoKeyRSAComponents::Type::Private:
106         keyType = CryptoKeyType::Private;
107         break;
108     }
109
110     // Construct the key s-expression, using the data that's available.
111     PAL::GCrypt::Handle<gcry_sexp_t> keySexp;
112     {
113         gcry_error_t error = GPG_ERR_NO_ERROR;
114
115         switch (keyType) {
116         case CryptoKeyType::Public:
117             error = gcry_sexp_build(&keySexp, nullptr, "(public-key(rsa(n %b)(e %b)))",
118                 keyData.modulus().size(), keyData.modulus().data(),
119                 keyData.exponent().size(), keyData.exponent().data());
120             break;
121         case CryptoKeyType::Private:
122             if (keyData.hasAdditionalPrivateKeyParameters()) {
123                 error = gcry_sexp_build(&keySexp, nullptr, "(private-key(rsa(n %b)(e %b)(d %b)(p %b)(q %b)))",
124                     keyData.modulus().size(), keyData.modulus().data(),
125                     keyData.exponent().size(), keyData.exponent().data(),
126                     keyData.privateExponent().size(), keyData.privateExponent().data(),
127                     keyData.secondPrimeInfo().primeFactor.size(), keyData.secondPrimeInfo().primeFactor.data(),
128                     keyData.firstPrimeInfo().primeFactor.size(), keyData.firstPrimeInfo().primeFactor.data());
129                 break;
130             }
131
132             error = gcry_sexp_build(&keySexp, nullptr, "(private-key(rsa(n %b)(e %b)(d %b)))",
133                 keyData.modulus().size(), keyData.modulus().data(),
134                 keyData.exponent().size(), keyData.exponent().data(),
135                 keyData.privateExponent().size(), keyData.privateExponent().data());
136             break;
137         case CryptoKeyType::Secret:
138             ASSERT_NOT_REACHED();
139             return nullptr;
140         }
141
142         if (error != GPG_ERR_NO_ERROR) {
143             PAL::GCrypt::logError(error);
144             return nullptr;
145         }
146     }
147
148     return adoptRef(new CryptoKeyRSA(identifier, hash, hasHash, keyType, keySexp.release(), extractable, usages));
149 }
150
151 CryptoKeyRSA::CryptoKeyRSA(CryptoAlgorithmIdentifier identifier, CryptoAlgorithmIdentifier hash, bool hasHash, CryptoKeyType type, PlatformRSAKey platformKey, bool extractable, CryptoKeyUsageBitmap usage)
152     : CryptoKey(identifier, type, extractable, usage)
153     , m_platformKey(platformKey)
154     , m_restrictedToSpecificHash(hasHash)
155     , m_hash(hash)
156 {
157 }
158
159 CryptoKeyRSA::~CryptoKeyRSA()
160 {
161     if (m_platformKey)
162         PAL::GCrypt::HandleDeleter<gcry_sexp_t>()(m_platformKey);
163 }
164
165 bool CryptoKeyRSA::isRestrictedToHash(CryptoAlgorithmIdentifier& identifier) const
166 {
167     if (!m_restrictedToSpecificHash)
168         return false;
169
170     identifier = m_hash;
171     return true;
172 }
173
174 size_t CryptoKeyRSA::keySizeInBits() const
175 {
176     return getRSAModulusLength(m_platformKey);
177 }
178
179 // Convert the exponent vector to a 32-bit value, if possible.
180 static Optional<uint32_t> exponentVectorToUInt32(const Vector<uint8_t>& exponent)
181 {
182     if (exponent.size() > 4) {
183         if (std::any_of(exponent.begin(), exponent.end() - 4, [](uint8_t element) { return !!element; }))
184             return WTF::nullopt;
185     }
186
187     uint32_t result = 0;
188     for (size_t size = exponent.size(), i = std::min<size_t>(4, size); i > 0; --i) {
189         result <<= 8;
190         result += exponent[size - i];
191     }
192
193     return result;
194 }
195
196 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)
197 {
198     // libgcrypt doesn't report an error if the exponent is smaller than three or even.
199     auto e = exponentVectorToUInt32(publicExponent);
200     if (!e || *e < 3 || !(*e & 0x1)) {
201         failureCallback();
202         return;
203     }
204
205     // libgcrypt doesn't support generating primes of less than 16 bits.
206     if (modulusLength < 16) {
207         failureCallback();
208         return;
209     }
210
211     PAL::GCrypt::Handle<gcry_sexp_t> genkeySexp;
212     gcry_error_t error = gcry_sexp_build(&genkeySexp, nullptr, "(genkey(rsa(nbits %d)(rsa-use-e %d)))", modulusLength, *e);
213     if (error != GPG_ERR_NO_ERROR) {
214         PAL::GCrypt::logError(error);
215         failureCallback();
216         return;
217     }
218
219     PAL::GCrypt::Handle<gcry_sexp_t> keyPairSexp;
220     error = gcry_pk_genkey(&keyPairSexp, genkeySexp);
221     if (error != GPG_ERR_NO_ERROR) {
222         PAL::GCrypt::logError(error);
223         failureCallback();
224         return;
225     }
226
227     PAL::GCrypt::Handle<gcry_sexp_t> publicKeySexp(gcry_sexp_find_token(keyPairSexp, "public-key", 0));
228     PAL::GCrypt::Handle<gcry_sexp_t> privateKeySexp(gcry_sexp_find_token(keyPairSexp, "private-key", 0));
229     if (!publicKeySexp || !privateKeySexp) {
230         failureCallback();
231         return;
232     }
233
234     context->postTask(
235         [algorithm, hash, hasHash, extractable, usage, publicKeySexp = publicKeySexp.release(), privateKeySexp = privateKeySexp.release(), callback = WTFMove(callback)](auto&) mutable {
236             auto publicKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Public, publicKeySexp, true, usage);
237             auto privateKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Private, privateKeySexp, extractable, usage);
238
239             callback(CryptoKeyPair { WTFMove(publicKey), WTFMove(privateKey) });
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, 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.valueOr(CryptoAlgorithmIdentifier::SHA_1), !!hash, CryptoKeyType::Public, platformKey.release(), extractable, usages));
317 }
318
319 RefPtr<CryptoKeyRSA> CryptoKeyRSA::importPkcs8(CryptoAlgorithmIdentifier identifier, 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.valueOr(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 auto CryptoKeyRSA::algorithm() const -> KeyAlgorithm
624 {
625     auto modulusLength = getRSAModulusLength(m_platformKey);
626     auto publicExponent = getRSAKeyParameter(m_platformKey, "e");
627
628     if (m_restrictedToSpecificHash) {
629         CryptoRsaHashedKeyAlgorithm result;
630         result.name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
631         result.modulusLength = modulusLength;
632         result.publicExponent = Uint8Array::tryCreate(publicExponent.data(), publicExponent.size());
633         result.hash.name = CryptoAlgorithmRegistry::singleton().name(m_hash);
634         return result;
635     }
636
637     CryptoRsaKeyAlgorithm result;
638     result.name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
639     result.modulusLength = modulusLength;
640     result.publicExponent = Uint8Array::tryCreate(publicExponent.data(), publicExponent.size());
641     return result;
642 }
643
644 std::unique_ptr<CryptoKeyRSAComponents> CryptoKeyRSA::exportData() const
645 {
646     switch (type()) {
647     case CryptoKeyType::Public:
648         return CryptoKeyRSAComponents::createPublic(getRSAKeyParameter(m_platformKey, "n"), getRSAKeyParameter(m_platformKey, "e"));
649     case CryptoKeyType::Private: {
650         auto parameterMPI =
651             [](gcry_sexp_t sexp, const char* name) -> gcry_mpi_t {
652                 PAL::GCrypt::Handle<gcry_sexp_t> paramSexp(gcry_sexp_find_token(sexp, name, 0));
653                 if (!paramSexp)
654                     return nullptr;
655                 return gcry_sexp_nth_mpi(paramSexp, 1, GCRYMPI_FMT_USG);
656             };
657
658         PAL::GCrypt::Handle<gcry_mpi_t> dMPI(parameterMPI(m_platformKey, "d"));
659         // libgcrypt internally uses p and q such that p < q, while usually it's q < p.
660         // Switch the two primes here and continue with assuming the latter.
661         PAL::GCrypt::Handle<gcry_mpi_t> pMPI(parameterMPI(m_platformKey, "q"));
662         PAL::GCrypt::Handle<gcry_mpi_t> qMPI(parameterMPI(m_platformKey, "p"));
663         if (!dMPI || !pMPI || !qMPI)
664             return nullptr;
665
666         CryptoKeyRSAComponents::PrimeInfo firstPrimeInfo;
667         if (auto data = mpiData(pMPI))
668             firstPrimeInfo.primeFactor = WTFMove(data.value());
669
670         CryptoKeyRSAComponents::PrimeInfo secondPrimeInfo;
671         if (auto data = mpiData(qMPI))
672             secondPrimeInfo.primeFactor = WTFMove(data.value());
673
674         // dp -- d mod (p - 1)
675         {
676             PAL::GCrypt::Handle<gcry_mpi_t> dpMPI(gcry_mpi_new(0));
677             PAL::GCrypt::Handle<gcry_mpi_t> pm1MPI(gcry_mpi_new(0));
678             gcry_mpi_sub_ui(pm1MPI, pMPI, 1);
679             gcry_mpi_mod(dpMPI, dMPI, pm1MPI);
680
681             if (auto data = mpiData(dpMPI))
682                 firstPrimeInfo.factorCRTExponent = WTFMove(data.value());
683         }
684
685         // dq -- d mod (q - 1)
686         {
687             PAL::GCrypt::Handle<gcry_mpi_t> dqMPI(gcry_mpi_new(0));
688             PAL::GCrypt::Handle<gcry_mpi_t> qm1MPI(gcry_mpi_new(0));
689             gcry_mpi_sub_ui(qm1MPI, qMPI, 1);
690             gcry_mpi_mod(dqMPI, dMPI, qm1MPI);
691
692             if (auto data = mpiData(dqMPI))
693                 secondPrimeInfo.factorCRTExponent = WTFMove(data.value());
694         }
695
696         // qi -- q^(-1) mod p
697         {
698             PAL::GCrypt::Handle<gcry_mpi_t> qiMPI(gcry_mpi_new(0));
699             gcry_mpi_invm(qiMPI, qMPI, pMPI);
700
701             if (auto data = mpiData(qiMPI))
702                 secondPrimeInfo.factorCRTCoefficient = WTFMove(data.value());
703         }
704
705         Vector<uint8_t> privateExponent;
706         if (auto data = mpiData(dMPI))
707             privateExponent = WTFMove(data.value());
708
709         return CryptoKeyRSAComponents::createPrivateWithAdditionalData(
710             getRSAKeyParameter(m_platformKey, "n"), getRSAKeyParameter(m_platformKey, "e"), WTFMove(privateExponent),
711             WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), Vector<CryptoKeyRSAComponents::PrimeInfo> { });
712     }
713     default:
714         ASSERT_NOT_REACHED();
715         return nullptr;
716     }
717 }
718
719 } // namespace WebCore
720
721 #endif // ENABLE(WEB_CRYPTO)