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 , 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.valueOr(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.valueOr(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.valueOr(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.valueOr(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) |
154 | |