Add more tests for SubtleCrypto::importKey and SubtleCrypto::exportKey
[WebKit-https.git] / Source / WebCore / crypto / mac / CryptoKeyRSAMac.cpp
1 /*
2  * Copyright (C) 2013 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 #if ENABLE(SUBTLE_CRYPTO)
30
31 #include "CommonCryptoUtilities.h"
32 #include "CryptoAlgorithmRegistry.h"
33 #include "CryptoKeyDataRSAComponents.h"
34 #include "CryptoKeyPair.h"
35 #include "ScriptExecutionContext.h"
36 #include <wtf/MainThread.h>
37
38 namespace WebCore {
39
40 static CCCryptorStatus getPublicKeyComponents(CCRSACryptorRef rsaKey, Vector<uint8_t>& modulus, Vector<uint8_t>& publicExponent)
41 {
42     ASSERT(CCRSAGetKeyType(rsaKey) == ccRSAKeyPublic || CCRSAGetKeyType(rsaKey) == ccRSAKeyPrivate);
43     bool keyIsPublic = CCRSAGetKeyType(rsaKey) == ccRSAKeyPublic;
44     CCRSACryptorRef publicKey = keyIsPublic ? rsaKey : CCRSACryptorGetPublicKeyFromPrivateKey(rsaKey);
45
46     modulus.resize(16384);
47     size_t modulusLength = modulus.size();
48     publicExponent.resize(16384);
49     size_t exponentLength = publicExponent.size();
50     CCCryptorStatus status = CCRSAGetKeyComponents(publicKey, modulus.data(), &modulusLength, publicExponent.data(), &exponentLength, 0, 0, 0, 0);
51     if (!keyIsPublic) {
52         // CCRSACryptorGetPublicKeyFromPrivateKey has "Get" in the name, but its result needs to be released (see <rdar://problem/15449697>).
53         CCRSACryptorRelease(publicKey);
54     }
55     if (status)
56         return status;
57
58     modulus.shrink(modulusLength);
59     publicExponent.shrink(exponentLength);
60     return status;
61 }
62
63 static CCCryptorStatus getPrivateKeyComponents(CCRSACryptorRef rsaKey, Vector<uint8_t>& privateExponent, CryptoKeyDataRSAComponents::PrimeInfo& firstPrimeInfo, CryptoKeyDataRSAComponents::PrimeInfo& secondPrimeInfo)
64 {
65     ASSERT(CCRSAGetKeyType(rsaKey) == ccRSAKeyPrivate);
66
67     Vector<uint8_t> unusedModulus(16384);
68     size_t modulusLength = unusedModulus.size();
69     privateExponent.resize(16384);
70     size_t exponentLength = privateExponent.size();
71     firstPrimeInfo.primeFactor.resize(16384);
72     size_t pLength = firstPrimeInfo.primeFactor.size();
73     secondPrimeInfo.primeFactor.resize(16384);
74     size_t qLength = secondPrimeInfo.primeFactor.size();
75
76     CCCryptorStatus status = CCRSAGetKeyComponents(rsaKey, unusedModulus.data(), &modulusLength, privateExponent.data(), &exponentLength, firstPrimeInfo.primeFactor.data(), &pLength, secondPrimeInfo.primeFactor.data(), &qLength);
77     if (status)
78         return status;
79
80     privateExponent.shrink(exponentLength);
81     firstPrimeInfo.primeFactor.shrink(pLength);
82     secondPrimeInfo.primeFactor.shrink(qLength);
83
84     CCBigNum d(privateExponent.data(), privateExponent.size());
85     CCBigNum p(firstPrimeInfo.primeFactor.data(), firstPrimeInfo.primeFactor.size());
86     CCBigNum q(secondPrimeInfo.primeFactor.data(), secondPrimeInfo.primeFactor.size());
87
88     CCBigNum dp = d % (p - 1);
89     CCBigNum dq = d % (q - 1);
90     CCBigNum qi = q.inverse(p);
91
92     firstPrimeInfo.factorCRTExponent = dp.data();
93     secondPrimeInfo.factorCRTExponent = dq.data();
94     secondPrimeInfo.factorCRTCoefficient = qi.data();
95
96     return status;
97 }
98
99 CryptoKeyRSA::CryptoKeyRSA(CryptoAlgorithmIdentifier identifier, CryptoAlgorithmIdentifier hash, bool hasHash, CryptoKeyType type, PlatformRSAKey platformKey, bool extractable, CryptoKeyUsageBitmap usage)
100     : CryptoKey(identifier, type, extractable, usage)
101     , m_platformKey(platformKey)
102     , m_restrictedToSpecificHash(hasHash)
103     , m_hash(hash)
104 {
105 }
106
107 RefPtr<CryptoKeyRSA> CryptoKeyRSA::create(CryptoAlgorithmIdentifier identifier, CryptoAlgorithmIdentifier hash, bool hasHash, const CryptoKeyDataRSAComponents& keyData, bool extractable, CryptoKeyUsageBitmap usage)
108 {
109     if (keyData.type() == CryptoKeyDataRSAComponents::Type::Private && !keyData.hasAdditionalPrivateKeyParameters()) {
110         // <rdar://problem/15452324> tracks adding support.
111         WTFLogAlways("Private keys without additional data are not supported");
112         return nullptr;
113     }
114     if (keyData.otherPrimeInfos().size()) {
115         // <rdar://problem/15444074> tracks adding support.
116         WTFLogAlways("Keys with more than two primes are not supported");
117         return nullptr;
118     }
119     CCRSACryptorRef cryptor;
120     // FIXME: It is so weired that we recaculate the private exponent from first prime factor and second prime factor,
121     // given the fact that we have already had it. Also, the re-caculated private exponent may not match the given one.
122     // See <rdar://problem/15452324>.
123     CCCryptorStatus status = CCRSACryptorCreateFromData(
124         keyData.type() == CryptoKeyDataRSAComponents::Type::Public ? ccRSAKeyPublic : ccRSAKeyPrivate,
125         (uint8_t*)keyData.modulus().data(), keyData.modulus().size(),
126         (uint8_t*)keyData.exponent().data(), keyData.exponent().size(),
127         (uint8_t*)keyData.firstPrimeInfo().primeFactor.data(), keyData.firstPrimeInfo().primeFactor.size(),
128         (uint8_t*)keyData.secondPrimeInfo().primeFactor.data(), keyData.secondPrimeInfo().primeFactor.size(),
129         &cryptor);
130
131     if (status) {
132         LOG_ERROR("Couldn't create RSA key from data, error %d", status);
133         return nullptr;
134     }
135
136     return adoptRef(new CryptoKeyRSA(identifier, hash, hasHash, keyData.type() == CryptoKeyDataRSAComponents::Type::Public ? CryptoKeyType::Public : CryptoKeyType::Private, cryptor, extractable, usage));
137 }
138
139 CryptoKeyRSA::~CryptoKeyRSA()
140 {
141     CCRSACryptorRelease(m_platformKey);
142 }
143
144 bool CryptoKeyRSA::isRestrictedToHash(CryptoAlgorithmIdentifier& identifier) const
145 {
146     if (!m_restrictedToSpecificHash)
147         return false;
148
149     identifier = m_hash;
150     return true;
151 }
152
153 size_t CryptoKeyRSA::keySizeInBits() const
154 {
155     Vector<uint8_t> modulus;
156     Vector<uint8_t> publicExponent;
157     CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
158     if (status) {
159         WTFLogAlways("Couldn't get RSA key components, status %d", status);
160         return 0;
161     }
162
163     return modulus.size() * 8;
164 }
165
166 std::unique_ptr<KeyAlgorithm> CryptoKeyRSA::buildAlgorithm() const
167 {
168     String name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
169     Vector<uint8_t> modulus;
170     Vector<uint8_t> publicExponent;
171     CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
172     if (status) {
173         WTFLogAlways("Couldn't get RSA key components, status %d", status);
174         publicExponent.clear();
175         return std::make_unique<RsaKeyAlgorithm>(name, 0, WTFMove(publicExponent));
176     }
177
178     size_t modulusLength = modulus.size() * 8;
179     if (m_restrictedToSpecificHash)
180         return std::make_unique<RsaHashedKeyAlgorithm>(name, modulusLength, WTFMove(publicExponent), CryptoAlgorithmRegistry::singleton().name(m_hash));
181     return std::make_unique<RsaKeyAlgorithm>(name, modulusLength, WTFMove(publicExponent));
182 }
183
184 std::unique_ptr<CryptoKeyData> CryptoKeyRSA::exportData() const
185 {
186     switch (CCRSAGetKeyType(m_platformKey)) {
187     case ccRSAKeyPublic: {
188         Vector<uint8_t> modulus;
189         Vector<uint8_t> publicExponent;
190         CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
191         if (status) {
192             WTFLogAlways("Couldn't get RSA key components, status %d", status);
193             return nullptr;
194         }
195         return CryptoKeyDataRSAComponents::createPublic(modulus, publicExponent);
196     }
197     case ccRSAKeyPrivate: {
198         Vector<uint8_t> modulus;
199         Vector<uint8_t> publicExponent;
200         CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
201         if (status) {
202             WTFLogAlways("Couldn't get RSA key components, status %d", status);
203             return nullptr;
204         }
205         Vector<uint8_t> privateExponent;
206         CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
207         CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
208         Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos; // Always empty, CommonCrypto only supports two primes (cf. <rdar://problem/15444074>).
209         status = getPrivateKeyComponents(m_platformKey, privateExponent, firstPrimeInfo, secondPrimeInfo);
210         if (status) {
211             WTFLogAlways("Couldn't get RSA key components, status %d", status);
212             return nullptr;
213         }
214         return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, publicExponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
215     }
216     default:
217         return nullptr;
218     }
219 }
220
221 static bool bigIntegerToUInt32(const Vector<uint8_t>& bigInteger, uint32_t& result)
222 {
223     result = 0;
224     for (size_t i = 0; i + 4 < bigInteger.size(); ++i) {
225         if (bigInteger[i])
226             return false; // Too big to fit in 32 bits.
227     }
228
229     for (size_t i = bigInteger.size() > 4 ? bigInteger.size() - 4 : 0; i < bigInteger.size(); ++i) {
230         result <<= 8;
231         result += bigInteger[i];
232     }
233     return true;
234 }
235
236 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)
237 {
238     uint32_t e;
239     if (!bigIntegerToUInt32(publicExponent, e)) {
240         // Adding support is tracked as <rdar://problem/15444034>.
241         WTFLogAlways("Public exponent is too big, not supported");
242         failureCallback();
243         return;
244     }
245
246     // We only use the callback functions when back on the main/worker thread, but captured variables are copied on a secondary thread too.
247     KeyPairCallback* localCallback = new KeyPairCallback(WTFMove(callback));
248     VoidCallback* localFailureCallback = new VoidCallback(WTFMove(failureCallback));
249     context->ref();
250
251     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
252         ASSERT(context);
253         CCRSACryptorRef ccPublicKey;
254         CCRSACryptorRef ccPrivateKey;
255         CCCryptorStatus status = CCRSACryptorGeneratePair(modulusLength, e, &ccPublicKey, &ccPrivateKey);
256         if (status) {
257             WTFLogAlways("Could not generate a key pair, status %d", status);
258             context->postTask([localCallback, localFailureCallback](ScriptExecutionContext& context) {
259                 (*localFailureCallback)();
260                 delete localCallback;
261                 delete localFailureCallback;
262                 context.deref();
263             });
264             return;
265         }
266         context->postTask([algorithm, hash, hasHash, extractable, usage, localCallback, localFailureCallback, ccPublicKey, ccPrivateKey](ScriptExecutionContext& context) {
267             auto publicKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Public, ccPublicKey, true, usage);
268             auto privateKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Private, ccPrivateKey, extractable, usage);
269             (*localCallback)(CryptoKeyPair::create(WTFMove(publicKey), WTFMove(privateKey)));
270             delete localCallback;
271             delete localFailureCallback;
272             context.deref();
273         });
274     });
275 }
276
277 } // namespace WebCore
278
279 #endif // ENABLE(SUBTLE_CRYPTO)