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