[iOS] ASSERTION FAILED: m_scriptExecutionContext->isContextThread() in ContextDestruc...
[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 "CryptoAlgorithmDescriptionBuilder.h"
33 #include "CryptoAlgorithmRegistry.h"
34 #include "CryptoKeyDataRSAComponents.h"
35 #include "CryptoKeyPair.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, CryptoKeyType type, PlatformRSAKey platformKey, bool extractable, CryptoKeyUsage usage)
100     : CryptoKey(identifier, type, extractable, usage)
101     , m_platformKey(platformKey)
102     , m_restrictedToSpecificHash(false)
103 {
104 }
105
106 PassRefPtr<CryptoKeyRSA> CryptoKeyRSA::create(CryptoAlgorithmIdentifier identifier, const CryptoKeyDataRSAComponents& keyData, bool extractable, CryptoKeyUsage usage)
107 {
108     if (keyData.type() == CryptoKeyDataRSAComponents::Type::Private && !keyData.hasAdditionalPrivateKeyParameters()) {
109         // <rdar://problem/15452324> tracks adding support.
110         WTFLogAlways("Private keys without additional data are not supported");
111         return nullptr;
112     }
113     if (keyData.otherPrimeInfos().size()) {
114         // <rdar://problem/15444074> tracks adding support.
115         WTFLogAlways("Keys with more than two primes are not supported");
116         return nullptr;
117     }
118     CCRSACryptorRef cryptor;
119     CCCryptorStatus status = CCRSACryptorCreateFromData(
120         keyData.type() == CryptoKeyDataRSAComponents::Type::Public ? ccRSAKeyPublic : ccRSAKeyPrivate,
121         (uint8_t*)keyData.modulus().data(), keyData.modulus().size(),
122         (uint8_t*)keyData.exponent().data(), keyData.exponent().size(),
123         (uint8_t*)keyData.firstPrimeInfo().primeFactor.data(), keyData.firstPrimeInfo().primeFactor.size(),
124         (uint8_t*)keyData.secondPrimeInfo().primeFactor.data(), keyData.secondPrimeInfo().primeFactor.size(),
125         &cryptor);
126
127     if (status) {
128         LOG_ERROR("Couldn't create RSA key from data, error %d", status);
129         return nullptr;
130     }
131
132     return adoptRef(new CryptoKeyRSA(identifier, keyData.type() == CryptoKeyDataRSAComponents::Type::Public ? CryptoKeyType::Public : CryptoKeyType::Private, cryptor, extractable, usage));
133 }
134
135 CryptoKeyRSA::~CryptoKeyRSA()
136 {
137     CCRSACryptorRelease(m_platformKey);
138 }
139
140 void CryptoKeyRSA::restrictToHash(CryptoAlgorithmIdentifier identifier)
141 {
142     m_restrictedToSpecificHash = true;
143     m_hash = identifier;
144 }
145
146 bool CryptoKeyRSA::isRestrictedToHash(CryptoAlgorithmIdentifier& identifier) const
147 {
148     if (!m_restrictedToSpecificHash)
149         return false;
150
151     identifier = m_hash;
152     return true;
153 }
154
155 size_t CryptoKeyRSA::keySizeInBits() const
156 {
157     Vector<uint8_t> modulus;
158     Vector<uint8_t> publicExponent;
159     CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
160     if (status) {
161         WTFLogAlways("Couldn't get RSA key components, status %d", status);
162         return 0;
163     }
164
165     return modulus.size() * 8;
166 }
167
168 void CryptoKeyRSA::buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder& builder) const
169 {
170     CryptoKey::buildAlgorithmDescription(builder);
171
172     Vector<uint8_t> modulus;
173     Vector<uint8_t> publicExponent;
174     CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
175     if (status) {
176         WTFLogAlways("Couldn't get RSA key components, status %d", status);
177         return;
178     }
179
180     builder.add("modulusLength", modulus.size() * 8);
181     builder.add("publicExponent", publicExponent);
182
183     if (m_restrictedToSpecificHash) {
184         auto hashDescriptionBuilder = builder.createEmptyClone();
185         hashDescriptionBuilder->add("name", CryptoAlgorithmRegistry::singleton().nameForIdentifier(m_hash));
186         builder.add("hash", *hashDescriptionBuilder);
187     }
188 }
189
190 std::unique_ptr<CryptoKeyData> CryptoKeyRSA::exportData() const
191 {
192     switch (CCRSAGetKeyType(m_platformKey)) {
193     case ccRSAKeyPublic: {
194         Vector<uint8_t> modulus;
195         Vector<uint8_t> publicExponent;
196         CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
197         if (status) {
198             WTFLogAlways("Couldn't get RSA key components, status %d", status);
199             return nullptr;
200         }
201         return CryptoKeyDataRSAComponents::createPublic(modulus, publicExponent);
202     }
203     case ccRSAKeyPrivate: {
204         Vector<uint8_t> modulus;
205         Vector<uint8_t> publicExponent;
206         CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
207         if (status) {
208             WTFLogAlways("Couldn't get RSA key components, status %d", status);
209             return nullptr;
210         }
211         Vector<uint8_t> privateExponent;
212         CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
213         CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
214         Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos; // Always empty, CommonCrypto only supports two primes (cf. <rdar://problem/15444074>).
215         status = getPrivateKeyComponents(m_platformKey, privateExponent, firstPrimeInfo, secondPrimeInfo);
216         if (status) {
217             WTFLogAlways("Couldn't get RSA key components, status %d", status);
218             return nullptr;
219         }
220         return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, publicExponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
221     }
222     default:
223         return nullptr;
224     }
225 }
226
227 static bool bigIntegerToUInt32(const Vector<uint8_t>& bigInteger, uint32_t& result)
228 {
229     result = 0;
230     for (size_t i = 0; i + 4 < bigInteger.size(); ++i) {
231         if (bigInteger[i])
232             return false; // Too big to fit in 32 bits.
233     }
234
235     for (size_t i = bigInteger.size() > 4 ? bigInteger.size() - 4 : 0; i < bigInteger.size(); ++i) {
236         result <<= 8;
237         result += bigInteger[i];
238     }
239     return true;
240 }
241
242 void CryptoKeyRSA::generatePair(CryptoAlgorithmIdentifier algorithm, unsigned modulusLength, const Vector<uint8_t>& publicExponent, bool extractable, CryptoKeyUsage usage, KeyPairCallback callback, VoidCallback failureCallback)
243 {
244     uint32_t e;
245     if (!bigIntegerToUInt32(publicExponent, e)) {
246         // Adding support is tracked as <rdar://problem/15444034>.
247         WTFLogAlways("Public exponent is too big, not supported");
248         failureCallback();
249         return;
250     }
251
252     // We only use the callback functions when back on the main thread, but captured variables are copied on a secondary thread too.
253     KeyPairCallback* localCallback = new KeyPairCallback(WTF::move(callback));
254     VoidCallback* localFailureCallback = new VoidCallback(WTF::move(failureCallback));
255
256     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
257         CCRSACryptorRef ccPublicKey;
258         CCRSACryptorRef ccPrivateKey;
259         CCCryptorStatus status = CCRSACryptorGeneratePair(modulusLength, e, &ccPublicKey, &ccPrivateKey);
260         if (status) {
261             WTFLogAlways("Could not generate a key pair, status %d", status);
262             callOnWebThreadOrDispatchAsyncOnMainThread(^{
263                 (*localFailureCallback)();
264                 delete localFailureCallback;
265             });
266             return;
267         }
268         callOnWebThreadOrDispatchAsyncOnMainThread(^{
269             RefPtr<CryptoKeyRSA> publicKey = CryptoKeyRSA::create(algorithm, CryptoKeyType::Public, ccPublicKey, true, usage);
270             RefPtr<CryptoKeyRSA> privateKey = CryptoKeyRSA::create(algorithm, CryptoKeyType::Private, ccPrivateKey, extractable, usage);
271             (*localCallback)(CryptoKeyPair::create(publicKey.release(), privateKey.release()));
272             delete localCallback;
273         });
274     });
275 }
276
277 } // namespace WebCore
278
279 #endif // ENABLE(SUBTLE_CRYPTO)