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
35namespace WebCore {
36
37RefPtr<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.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
111JsonWebKey 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