0d97559b6e7f232fb11b866d4cf7a342f94d1856
[WebKit-https.git] / Source / WebCore / crypto / keys / CryptoKeyRSA.cpp
1 /*
2  * Copyright (C) 2016 Apple Inc. 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 #include "CryptoKeyDataRSAComponents.h"
30 #include "JsonWebKey.h"
31 #include <JavaScriptCore/GenericTypedArrayViewInlines.h>
32 #include <JavaScriptCore/JSGenericTypedArrayViewInlines.h>
33 #include <heap/HeapInlines.h>
34 #include <wtf/text/Base64.h>
35
36 #if ENABLE(SUBTLE_CRYPTO)
37
38 namespace WebCore {
39
40 CryptoRsaKeyAlgorithm RsaKeyAlgorithm::dictionary() const
41 {
42     CryptoRsaKeyAlgorithm result;
43     result.name = this->name();
44     result.modulusLength = this->modulusLength();
45     result.publicExponent = Uint8Array::create(this->publicExponent().data(), this->publicExponent().size());
46     return result;
47 }
48
49 CryptoRsaHashedKeyAlgorithm RsaHashedKeyAlgorithm::dictionary() const
50 {
51     CryptoRsaHashedKeyAlgorithm result;
52     result.name = this->name();
53     result.modulusLength = this->modulusLength();
54     result.publicExponent = Uint8Array::create(this->publicExponent().data(), this->publicExponent().size());
55     result.hash.name = this->hash();
56     return result;
57 }
58
59 RefPtr<CryptoKeyRSA> CryptoKeyRSA::importJwk(CryptoAlgorithmIdentifier algorithm, std::optional<CryptoAlgorithmIdentifier> hash, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
60 {
61     if (keyData.kty != "RSA")
62         return nullptr;
63     if (keyData.key_ops && ((keyData.usages & usages) != usages))
64         return nullptr;
65     if (keyData.ext && !keyData.ext.value() && extractable)
66         return nullptr;
67
68     if (keyData.n.isNull() || keyData.e.isNull())
69         return nullptr;
70     Vector<uint8_t> modulus;
71     if (!WTF::base64URLDecode(keyData.n, modulus))
72         return nullptr;
73     // Per RFC 7518 Section 6.3.1.1: https://tools.ietf.org/html/rfc7518#section-6.3.1.1
74     if (!modulus.isEmpty() && !modulus[0])
75         modulus.remove(0);
76     Vector<uint8_t> exponent;
77     if (!WTF::base64URLDecode(keyData.e, exponent))
78         return nullptr;
79     if (keyData.d.isNull()) {
80         // import public key
81         auto publicKeyComponents = CryptoKeyDataRSAComponents::createPublic(WTFMove(modulus), WTFMove(exponent));
82         // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
83         return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *publicKeyComponents, extractable, usages);
84     }
85
86     // import private key
87     Vector<uint8_t> privateExponent;
88     if (!WTF::base64URLDecode(keyData.d, privateExponent))
89         return nullptr;
90     if (keyData.p.isNull() && keyData.q.isNull() && keyData.dp.isNull() && keyData.dp.isNull() && keyData.qi.isNull()) {
91         auto privateKeyComponents = CryptoKeyDataRSAComponents::createPrivate(WTFMove(modulus), WTFMove(exponent), WTFMove(privateExponent));
92         // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
93         return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
94     }
95
96     if (keyData.p.isNull() || keyData.q.isNull() || keyData.dp.isNull() || keyData.dq.isNull() || keyData.qi.isNull())
97         return nullptr;
98     CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
99     CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
100     if (!WTF::base64URLDecode(keyData.p, firstPrimeInfo.primeFactor))
101         return nullptr;
102     if (!WTF::base64URLDecode(keyData.dp, firstPrimeInfo.factorCRTExponent))
103         return nullptr;
104     if (!WTF::base64URLDecode(keyData.q, secondPrimeInfo.primeFactor))
105         return nullptr;
106     if (!WTF::base64URLDecode(keyData.dq, secondPrimeInfo.factorCRTExponent))
107         return nullptr;
108     if (!WTF::base64URLDecode(keyData.qi, secondPrimeInfo.factorCRTCoefficient))
109         return nullptr;
110     if (!keyData.oth) {
111         auto privateKeyComponents = CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(WTFMove(modulus), WTFMove(exponent), WTFMove(privateExponent), WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), { });
112         // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
113         return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
114     }
115
116     Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos;
117     for (auto value : keyData.oth.value()) {
118         CryptoKeyDataRSAComponents::PrimeInfo info;
119         if (!WTF::base64URLDecode(value.r, info.primeFactor))
120             return nullptr;
121         if (!WTF::base64URLDecode(value.d, info.factorCRTExponent))
122             return nullptr;
123         if (!WTF::base64URLDecode(value.t, info.factorCRTCoefficient))
124             return nullptr;
125         otherPrimeInfos.append(info);
126     }
127
128     auto privateKeyComponents = CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(WTFMove(modulus), WTFMove(exponent), WTFMove(privateExponent), WTFMove(firstPrimeInfo), WTFMove(secondPrimeInfo), WTFMove(otherPrimeInfos));
129     // Notice: CryptoAlgorithmIdentifier::SHA_1 is just a placeholder. It should not have any effect if hash is std::nullopt.
130     return CryptoKeyRSA::create(algorithm, hash.value_or(CryptoAlgorithmIdentifier::SHA_1), !!hash, *privateKeyComponents, extractable, usages);
131 }
132
133 JsonWebKey CryptoKeyRSA::exportJwk() const
134 {
135     JsonWebKey result;
136     result.kty = "RSA";
137     result.key_ops = usages();
138     result.ext = extractable();
139
140     auto keyData = exportData();
141     const auto& rsaKeyData = downcast<CryptoKeyDataRSAComponents>(*keyData);
142     // public key
143     result.n = base64URLEncode(rsaKeyData.modulus());
144     result.e = base64URLEncode(rsaKeyData.exponent());
145     if (rsaKeyData.type() == CryptoKeyDataRSAComponents::Type::Public)
146         return result;
147
148     // private key
149     result.d = base64URLEncode(rsaKeyData.privateExponent());
150     if (!rsaKeyData.hasAdditionalPrivateKeyParameters())
151         return result;
152
153     result.p = base64URLEncode(rsaKeyData.firstPrimeInfo().primeFactor);
154     result.q = base64URLEncode(rsaKeyData.secondPrimeInfo().primeFactor);
155     result.dp = base64URLEncode(rsaKeyData.firstPrimeInfo().factorCRTExponent);
156     result.dq = base64URLEncode(rsaKeyData.secondPrimeInfo().factorCRTExponent);
157     result.qi = base64URLEncode(rsaKeyData.secondPrimeInfo().factorCRTCoefficient);
158     if (rsaKeyData.otherPrimeInfos().isEmpty())
159         return result;
160
161     Vector<RsaOtherPrimesInfo> oth;
162     for (auto info : rsaKeyData.otherPrimeInfos()) {
163         RsaOtherPrimesInfo otherInfo;
164         otherInfo.r = base64URLEncode(info.primeFactor);
165         otherInfo.d = base64URLEncode(info.factorCRTExponent);
166         otherInfo.t = base64URLEncode(info.factorCRTCoefficient);
167         oth.append(WTFMove(otherInfo));
168     }
169     result.oth = WTFMove(oth);
170     return result;
171 }
172
173 } // namespace WebCore
174
175 #endif // ENABLE(SUBTLE_CRYPTO)