b4e4c1e16b3c25545af5317b8c4d28c4e72cac06
[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     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 std::unique_ptr<KeyAlgorithm> CryptoKeyRSA::buildAlgorithm() const
164 {
165     String name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
166     Vector<uint8_t> modulus;
167     Vector<uint8_t> publicExponent;
168     CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
169     if (status) {
170         WTFLogAlways("Couldn't get RSA key components, status %d", status);
171         publicExponent.clear();
172         return std::make_unique<RsaKeyAlgorithm>(name, 0, WTFMove(publicExponent));
173     }
174
175     size_t modulusLength = modulus.size() * 8;
176     if (m_restrictedToSpecificHash)
177         return std::make_unique<RsaHashedKeyAlgorithm>(name, modulusLength, WTFMove(publicExponent), CryptoAlgorithmRegistry::singleton().name(m_hash));
178     return std::make_unique<RsaKeyAlgorithm>(name, modulusLength, WTFMove(publicExponent));
179 }
180
181 std::unique_ptr<CryptoKeyData> CryptoKeyRSA::exportData() const
182 {
183     switch (CCRSAGetKeyType(m_platformKey)) {
184     case ccRSAKeyPublic: {
185         Vector<uint8_t> modulus;
186         Vector<uint8_t> publicExponent;
187         CCCryptorStatus status = getPublicKeyComponents(m_platformKey, modulus, publicExponent);
188         if (status) {
189             WTFLogAlways("Couldn't get RSA key components, status %d", status);
190             return nullptr;
191         }
192         return CryptoKeyDataRSAComponents::createPublic(modulus, publicExponent);
193     }
194     case ccRSAKeyPrivate: {
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         Vector<uint8_t> privateExponent;
203         CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo;
204         CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo;
205         Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos; // Always empty, CommonCrypto only supports two primes (cf. <rdar://problem/15444074>).
206         status = getPrivateKeyComponents(m_platformKey, privateExponent, firstPrimeInfo, secondPrimeInfo);
207         if (status) {
208             WTFLogAlways("Couldn't get RSA key components, status %d", status);
209             return nullptr;
210         }
211         return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, publicExponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos);
212     }
213     default:
214         return nullptr;
215     }
216 }
217
218 static bool bigIntegerToUInt32(const Vector<uint8_t>& bigInteger, uint32_t& result)
219 {
220     result = 0;
221     for (size_t i = 0; i + 4 < bigInteger.size(); ++i) {
222         if (bigInteger[i])
223             return false; // Too big to fit in 32 bits.
224     }
225
226     for (size_t i = bigInteger.size() > 4 ? bigInteger.size() - 4 : 0; i < bigInteger.size(); ++i) {
227         result <<= 8;
228         result += bigInteger[i];
229     }
230     return true;
231 }
232
233 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)
234 {
235     uint32_t e;
236     if (!bigIntegerToUInt32(publicExponent, e)) {
237         // Adding support is tracked as <rdar://problem/15444034>.
238         WTFLogAlways("Public exponent is too big, not supported");
239         failureCallback();
240         return;
241     }
242
243     // We only use the callback functions when back on the main/worker thread, but captured variables are copied on a secondary thread too.
244     KeyPairCallback* localCallback = new KeyPairCallback(WTFMove(callback));
245     VoidCallback* localFailureCallback = new VoidCallback(WTFMove(failureCallback));
246     context->ref();
247
248     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
249         ASSERT(context);
250         CCRSACryptorRef ccPublicKey;
251         CCRSACryptorRef ccPrivateKey;
252         CCCryptorStatus status = CCRSACryptorGeneratePair(modulusLength, e, &ccPublicKey, &ccPrivateKey);
253         if (status) {
254             WTFLogAlways("Could not generate a key pair, status %d", status);
255             context->postTask([localCallback, localFailureCallback](ScriptExecutionContext& context) {
256                 (*localFailureCallback)();
257                 delete localCallback;
258                 delete localFailureCallback;
259                 context.deref();
260             });
261             return;
262         }
263         context->postTask([algorithm, hash, hasHash, extractable, usage, localCallback, localFailureCallback, ccPublicKey, ccPrivateKey](ScriptExecutionContext& context) {
264             auto publicKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Public, ccPublicKey, true, usage);
265             auto privateKey = CryptoKeyRSA::create(algorithm, hash, hasHash, CryptoKeyType::Private, ccPrivateKey, extractable, usage);
266             (*localCallback)(CryptoKeyPair::create(WTFMove(publicKey), WTFMove(privateKey)));
267             delete localCallback;
268             delete localFailureCallback;
269             context.deref();
270         });
271     });
272 }
273
274 } // namespace WebCore
275
276 #endif // ENABLE(SUBTLE_CRYPTO)