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