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
37namespace WebCore {
38
39static 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
62static 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
98CryptoKeyRSA::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
105PassRefPtr<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
134CryptoKeyRSA::~CryptoKeyRSA()
135{
136    CCRSACryptorRelease(m_platformKey);
137}
138
139void CryptoKeyRSA::restrictToHash(CryptoAlgorithmIdentifier identifier)
140{
141    m_restrictedToSpecificHash = true;
142    m_hash = identifier;
143}
144
145bool CryptoKeyRSA::isRestrictedToHash(CryptoAlgorithmIdentifier& identifier) const
146{
147    if (!m_restrictedToSpecificHash)
148        return false;
149
150    identifier = m_hash;
151    return true;
152}
153
154size_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
167void 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
189std::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
228static 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
243void 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)
281