4aaf0cb8d343a84971a8e1897ed5883f7e81bd10
[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 "CryptoAlgorithmDescriptionBuilder.h"
32 #include "CryptoAlgorithmRegistry.h"
33 #include "CryptoKeyDataRSAComponents.h"
34 #include "CryptoKeyPair.h"
35 #include "JSDOMPromise.h"
36 #include <CommonCrypto/CommonCryptor.h>
37
38 #if defined(__has_include)
39 #if __has_include(<CommonCrypto/CommonRSACryptor.h>)
40 #include <CommonCrypto/CommonRSACryptor.h>
41 #endif
42 #endif
43
44 #ifndef _CC_RSACRYPTOR_H_
45 enum {
46     ccRSAKeyPublic          = 0,
47     ccRSAKeyPrivate         = 1
48 };
49 typedef uint32_t CCRSAKeyType;
50 #endif
51
52 extern "C" CCCryptorStatus CCRSACryptorCreateFromData(CCRSAKeyType keyType, uint8_t *modulus, size_t modulusLength, uint8_t *exponent, size_t exponentLength, uint8_t *p, size_t pLength, uint8_t *q, size_t qLength, CCRSACryptorRef *ref);
53 extern "C" CCCryptorStatus CCRSACryptorGeneratePair(size_t keysize, uint32_t e, CCRSACryptorRef *publicKey, CCRSACryptorRef *privateKey);
54 extern "C" CCRSACryptorRef CCRSACryptorGetPublicKeyFromPrivateKey(CCRSACryptorRef privkey);
55 extern "C" void CCRSACryptorRelease(CCRSACryptorRef key);
56 extern "C" CCCryptorStatus CCRSAGetKeyComponents(CCRSACryptorRef rsaKey, uint8_t *modulus, size_t *modulusLength, uint8_t *exponent, size_t *exponentLength, uint8_t *p, size_t *pLength, uint8_t *q, size_t *qLength);
57 extern "C" CCRSAKeyType CCRSAGetKeyType(CCRSACryptorRef key);
58
59 namespace WebCore {
60
61 CryptoKeyRSA::CryptoKeyRSA(CryptoAlgorithmIdentifier identifier, CryptoKeyType type, PlatformRSAKey platformKey, bool extractable, CryptoKeyUsage usage)
62     : CryptoKey(identifier, type, extractable, usage)
63     , m_platformKey(platformKey)
64     , m_restrictedToSpecificHash(false)
65 {
66 }
67
68 PassRefPtr<CryptoKeyRSA> CryptoKeyRSA::create(CryptoAlgorithmIdentifier identifier, const CryptoKeyDataRSAComponents& keyData, bool extractable, CryptoKeyUsage usage)
69 {
70     if (keyData.type() == CryptoKeyDataRSAComponents::Type::Private && !keyData.hasAdditionalPrivateKeyParameters()) {
71         WTFLogAlways("Private keys without additional data are not supported");
72         return nullptr;
73     }
74     if (keyData.otherPrimeInfos().size()) {
75         // <rdar://problem/15444074> tracks adding support.
76         WTFLogAlways("Keys with more than two primes are not supported");
77         return nullptr;
78     }
79     CCRSACryptorRef cryptor;
80     CCCryptorStatus status = CCRSACryptorCreateFromData(
81         keyData.type() == CryptoKeyDataRSAComponents::Type::Public ? ccRSAKeyPublic : ccRSAKeyPrivate,
82         (uint8_t*)keyData.modulus().data(), keyData.modulus().size(),
83         (uint8_t*)keyData.exponent().data(), keyData.exponent().size(),
84         (uint8_t*)keyData.firstPrimeInfo().primeFactor.data(), keyData.firstPrimeInfo().primeFactor.size(),
85         (uint8_t*)keyData.secondPrimeInfo().primeFactor.data(), keyData.secondPrimeInfo().primeFactor.size(),
86         &cryptor);
87
88     if (status) {
89         LOG_ERROR("Couldn't create RSA key from data, error %d", status);
90         return nullptr;
91     }
92
93     return adoptRef(new CryptoKeyRSA(identifier, keyData.type() == CryptoKeyDataRSAComponents::Type::Public ? CryptoKeyType::Public : CryptoKeyType::Private, cryptor, extractable, usage));
94 }
95
96 CryptoKeyRSA::~CryptoKeyRSA()
97 {
98     CCRSACryptorRelease(m_platformKey);
99 }
100
101 void CryptoKeyRSA::restrictToHash(CryptoAlgorithmIdentifier identifier)
102 {
103     m_restrictedToSpecificHash = true;
104     m_hash = identifier;
105 }
106
107 void CryptoKeyRSA::buildAlgorithmDescription(CryptoAlgorithmDescriptionBuilder& builder) const
108 {
109     CryptoKey::buildAlgorithmDescription(builder);
110
111     ASSERT(CCRSAGetKeyType(m_platformKey) == ccRSAKeyPublic || CCRSAGetKeyType(m_platformKey) == ccRSAKeyPrivate);
112     bool platformKeyIsPublic = CCRSAGetKeyType(m_platformKey) == ccRSAKeyPublic;
113     CCRSACryptorRef publicKey = platformKeyIsPublic ? m_platformKey : CCRSACryptorGetPublicKeyFromPrivateKey(m_platformKey);
114
115     uint8_t modulus[16384];
116     size_t modulusLength = sizeof(modulus);
117     uint8_t publicExponent[16384];
118     size_t exponentLength = sizeof(16384);
119     uint8_t p[16384];
120     size_t pLength = sizeof(p);
121     uint8_t q[16384];
122     size_t qLength = sizeof(q);
123     CCCryptorStatus status = CCRSAGetKeyComponents(publicKey, modulus, &modulusLength, publicExponent, &exponentLength, p, &pLength, q, &qLength);
124     if (!platformKeyIsPublic) {
125         // CCRSACryptorGetPublicKeyFromPrivateKey has "Get" in the name, but its result needs to be released (see <rdar://problem/15449697>).
126         CCRSACryptorRelease(publicKey);
127     }
128     if (status) {
129         WTFLogAlways("Couldn't get RSA key components, status %d", status);
130         return;
131     }
132
133     builder.add("modulusLength", modulusLength * 8);
134
135     Vector<unsigned char> publicExponentVector;
136     publicExponentVector.append(publicExponent, exponentLength);
137     builder.add("publicExponent", publicExponentVector);
138
139     if (m_restrictedToSpecificHash) {
140         auto hashDescriptionBuilder = builder.createEmptyClone();
141         hashDescriptionBuilder->add("name", CryptoAlgorithmRegistry::shared().nameForIdentifier(m_hash));
142         builder.add("hash", *hashDescriptionBuilder);
143     }
144 }
145
146 std::unique_ptr<CryptoKeyData> CryptoKeyRSA::exportData() const
147 {
148     // Not implemented yet.
149     ASSERT(extractable());
150     return nullptr;
151 }
152
153 static bool bigIntegerToUInt32(const Vector<char>& bigInteger, uint32_t& result)
154 {
155     result = 0;
156     for (size_t i = 0; i + 4 < bigInteger.size(); ++i) {
157         if (bigInteger[i])
158             return false; // Too big to fit in 32 bits.
159     }
160
161     for (size_t i = bigInteger.size() > 4 ? bigInteger.size() - 4 : 0; i < bigInteger.size(); ++i) {
162         result <<= 8;
163         result += static_cast<unsigned char>(bigInteger[i]);
164     }
165     return true;
166 }
167
168 void CryptoKeyRSA::generatePair(CryptoAlgorithmIdentifier algorithm, unsigned modulusLength, const Vector<char>& publicExponent, bool extractable, CryptoKeyUsage usage, std::unique_ptr<PromiseWrapper> promise)
169 {
170     uint32_t e;
171     if (!bigIntegerToUInt32(publicExponent, e)) {
172         // Adding support is tracked as <rdar://problem/15444034>.
173         WTFLogAlways("Public exponent is too big, not supported by CommonCrypto");
174         promise->reject(nullptr);
175         return;
176     }
177
178     PromiseWrapper* localPromise = promise.release();
179
180     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
181         CCRSACryptorRef ccPublicKey;
182         CCRSACryptorRef ccPrivateKey;
183         CCCryptorStatus status = CCRSACryptorGeneratePair(modulusLength, e, &ccPublicKey, &ccPrivateKey);
184         if (status) {
185             WTFLogAlways("Could not generate a key pair, status %d", status);
186             dispatch_async(dispatch_get_main_queue(), ^{
187                 localPromise->reject(nullptr);
188                 delete localPromise;
189             });
190             return;
191         }
192         dispatch_async(dispatch_get_main_queue(), ^{
193             RefPtr<CryptoKeyRSA> publicKey = CryptoKeyRSA::create(algorithm, CryptoKeyType::Public, ccPublicKey, extractable, usage);
194             RefPtr<CryptoKeyRSA> privateKey = CryptoKeyRSA::create(algorithm, CryptoKeyType::Private, ccPrivateKey, extractable, usage);
195             localPromise->fulfill(CryptoKeyPair::create(publicKey.release(), privateKey.release()));
196             delete localPromise;
197         });
198     });
199 }
200
201 } // namespace WebCore
202
203 #endif // ENABLE(SUBTLE_CRYPTO)