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