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