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