1/*
2 * Copyright (c) 2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24// #define COMMON_EC_FUNCTIONS
25#include "CommonECCryptor.h"
26#include "CommonDigest.h"
27#include "CommonDigestPriv.h"
28#include "CommonRandomSPI.h"
29#include "ccMemory.h"
30#import <corecrypto/ccec.h>
31#include <AssertMacros.h>
32#include "ccdebug.h"
33
34
35#pragma mark Internal Structures and Functions
36
37typedef struct _CCECCryptor {
38    union {
39        ccec_full_ctx *private;
40        ccec_pub_ctx *public;
41        uint8_t *bytes;
42    } ecKey;
43    size_t keySize;
44    CCECKeyType keyType;
45} CCECCryptor;
46
47
48static CCECCryptor *
49ccMallocECCryptor(size_t nbits, CCECKeyType keyType)
50{
51    CCECCryptor *retval;
52    size_t ctxSize = 0;
53
54
55    if(!ccec_keysize_is_supported(nbits)) return NULL;
56    ccec_const_cp_t cp = ccec_get_cp(nbits);
57    size_t len = ccec_cp_prime_size(cp);
58
59    if((retval = CC_XMALLOC(sizeof(CCECCryptor))) == NULL) return NULL;
60
61    retval->keySize = nbits;
62    retval->ecKey.bytes = NULL;
63
64    switch(keyType) {
65        case ccECKeyPublic:
66            retval->keyType = ccECBlankPublicKey;
67            ctxSize = ccec_pub_ctx_size(len);
68            break;
69        case ccECKeyPrivate:
70            retval->keyType = ccECBlankPrivateKey;
71            ctxSize = ccec_full_ctx_size(len);
72            break;
73        default:
74            goto errOut;
75    }
76
77    if((retval->ecKey.bytes = CC_XMALLOC(ctxSize)) == NULL) goto errOut;
78    ccec_ctx_init(cp, retval->ecKey.public);
79
80    return retval;
81errOut:
82    if(retval) {
83        CC_XFREE(retval, sizeof(CCECCryptor));
84    }
85    return NULL;
86}
87
88static void
89ccECCryptorFree(CCECCryptor *theKey)
90{
91    size_t nbits = theKey->keySize;
92    size_t ctxSize = 0;
93
94    ccec_const_cp_t cp = ccec_get_cp(nbits);
95    size_t len = ccec_cp_prime_size(cp);
96
97    CCECCryptor *key = (CCECCryptor *) theKey;
98    if(!key) return;
99
100    switch(key->keyType) {
101        case ccECKeyPublic:
102        case ccECBlankPublicKey:
103            ctxSize = ccec_pub_ctx_size(len);
104            break;
105        case ccECKeyPrivate:
106        case ccECBlankPrivateKey:
107            ctxSize = ccec_full_ctx_size(len);
108            break;
109        default:
110            break;
111    }
112
113    if(ctxSize && key->ecKey.bytes) {
114        CC_XZEROMEM(key->ecKey.bytes, ctxSize);
115        CC_XFREE(key->ecKey.bytes, ctxSize);
116    }
117
118    CC_XZEROMEM(key, sizeof(CCECCryptor));
119    CC_XFREE(theKey, sizeof(CCECCryptor));
120}
121
122static bool
123ccECpairwiseConsistencyCheck(CCECCryptorRef privateKey, CCECCryptorRef publicKey)
124{
125	CCCryptorStatus status = kCCSuccess;
126    uint8_t digestBuffer[CC_SHA1_DIGEST_LENGTH];
127	size_t signedDataLen = 4096;
128	uint8_t signedData[4096];
129	uint32_t isValid = 0;
130
131    CC_XMEMSET(digestBuffer, 0x0a, CC_SHA1_DIGEST_LENGTH);
132
133	status = CCECCryptorSignHash(privateKey,
134                                 digestBuffer, CC_SHA1_DIGEST_LENGTH,
135                                 signedData, &signedDataLen);
136
137	if (kCCSuccess != status) return false;
138
139	status = CCECCryptorVerifyHash(publicKey,
140                                   digestBuffer, CC_SHA1_DIGEST_LENGTH,
141                                   signedData, signedDataLen, &isValid);
142
143	if (kCCSuccess != status || isValid != 1) return false;
144	return true;
145}
146
147
148#pragma mark API (SPI for now)
149
150
151CCCryptorStatus
152CCECCryptorGeneratePair(size_t nbits, CCECCryptorRef *publicKey, CCECCryptorRef *privateKey)
153{
154    CCCryptorStatus retval;
155    CCECCryptor *privateCryptor = NULL;
156    CCECCryptor *publicCryptor = NULL;
157    struct ccrng_state *theRng = ccDRBGGetRngState();
158
159    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
160    if(!ccec_keysize_is_supported(nbits)) return kCCParamError;
161    ccec_const_cp_t cp = ccec_get_cp(nbits);
162
163    __Require_Action((privateCryptor = ccMallocECCryptor(nbits, ccECKeyPrivate)) != NULL, errOut, retval = kCCMemoryFailure);
164    privateCryptor->keySize = nbits;
165
166    __Require_Action((ccec_generate_key(cp, theRng, privateCryptor->ecKey.private) == 0), errOut, retval = kCCDecodeError);
167
168    privateCryptor->keyType = ccECKeyPrivate;
169
170    __Require_Action((publicCryptor = CCECCryptorGetPublicKeyFromPrivateKey(privateCryptor)) != NULL, errOut, retval = kCCMemoryFailure);
171
172    __Require_Action(ccECpairwiseConsistencyCheck(privateCryptor, publicCryptor) == true, errOut, retval = kCCDecodeError);
173
174    *publicKey = publicCryptor;
175    *privateKey = privateCryptor;
176
177    return kCCSuccess;
178
179errOut:
180    if(privateCryptor) ccECCryptorFree(privateCryptor);
181    if(publicCryptor) ccECCryptorFree(publicCryptor);
182    *publicKey = *privateKey = NULL;
183    return kCCDecodeError;
184
185}
186
187CCECCryptorRef
188CCECCryptorGetPublicKeyFromPrivateKey(CCECCryptorRef privateKey)
189{
190    CCECCryptor *publicCryptor = NULL;
191
192    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
193    __Require((publicCryptor = ccMallocECCryptor(privateKey->keySize, ccECKeyPublic)) != NULL, errOut);
194    ccec_const_cp_t cp = ccec_get_cp(privateKey->keySize);
195    size_t ctx_size = ccec_pub_ctx_size(ccec_cp_prime_size(cp));
196    CC_XMEMCPY(publicCryptor->ecKey.public, privateKey->ecKey.public, ctx_size);
197    publicCryptor->keySize = privateKey->keySize;
198    publicCryptor->keyType = ccECKeyPublic;
199
200    if(ccECpairwiseConsistencyCheck(privateKey, publicCryptor) == false) goto errOut;
201    return publicCryptor;
202
203errOut:
204    if(publicCryptor) ccECCryptorFree(publicCryptor);
205    return NULL;
206
207}
208
209
210CCCryptorStatus
211CCECCryptorGetKeyComponents(CCECCryptorRef ecKey, size_t *keySize,
212                            uint8_t *qX, size_t *qXLength,
213                            uint8_t *qY, size_t *qYLength,
214                            uint8_t *d, size_t *dLength)
215{
216    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
217    switch(ecKey->keyType) {
218        case ccECKeyPublic:
219            if(ccec_get_pubkey_components(ecKey->ecKey.public, keySize,
220                                          qX, qXLength,
221                                          qY, qYLength)) return kCCMemoryFailure;
222            break;
223        case ccECKeyPrivate:
224            if(ccec_get_fullkey_components(ecKey->ecKey.private, keySize,
225                                           qX, qXLength,
226                                           qY, qYLength,
227                                           d, dLength)) return kCCMemoryFailure;
228            break;
229        default: return kCCParamError;
230    }
231    return kCCSuccess;
232}
233
234CCCryptorStatus
235CCECCryptorCreateFromData(size_t nbits,
236                          uint8_t *qX, size_t qXLength,
237                          uint8_t *qY, size_t qYLength,
238                          CCECCryptorRef *ref)
239{
240    CCECCryptor *publicCryptor;
241
242    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
243    *ref = NULL;
244    if((publicCryptor = ccMallocECCryptor(nbits, ccECKeyPublic)) == NULL) return kCCMemoryFailure;
245    if(ccec_make_pub(nbits, qXLength, qX, qYLength, qY, publicCryptor->ecKey.public)) {
246        ccECCryptorFree(publicCryptor);
247        return kCCDecodeError;
248    }
249    publicCryptor->keyType = ccECKeyPublic;
250
251    *ref = publicCryptor;
252    return kCCSuccess;
253}
254
255CCECKeyType CCECGetKeyType(CCECCryptorRef key)
256{
257    CCECCryptor *cryptor = key;
258    CCECKeyType retval;
259
260    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
261    if(key == NULL) return ccECBlankPublicKey;
262    retval = cryptor->keyType;
263    if(retval != ccECKeyPublic && retval != ccECKeyPrivate) return ccECBadKey;
264    return retval;
265}
266
267int CCECGetKeySize(CCECCryptorRef key)
268{
269    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
270    if(key == NULL) return kCCParamError;
271    return (int) key->keySize;
272}
273
274void
275CCECCryptorRelease(CCECCryptorRef key)
276{
277    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
278    ccECCryptorFree(key);
279}
280
281CCCryptorStatus CCECCryptorImportPublicKey(void *keyPackage, size_t keyPackageLen, CCECCryptorRef *key)
282{
283    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
284    return CCECCryptorImportKey(kCCImportKeyBinary, keyPackage, keyPackageLen, ccECKeyPublic, key);
285}
286
287
288CCCryptorStatus CCECCryptorImportKey(CCECKeyExternalFormat format, void *keyPackage, size_t keyPackageLen, CCECKeyType keyType, CCECCryptorRef *key)
289{
290    CCECCryptor *cryptor = NULL;
291    CCCryptorStatus retval = kCCSuccess;
292
293    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
294    if(keyPackage == NULL) return kCCParamError;
295
296    switch(format) {
297        case kCCImportKeyBinary:
298            if(keyType == ccECKeyPrivate) {
299                size_t nbits = ccec_x963_import_priv_size(keyPackageLen);
300                if((cryptor = ccMallocECCryptor(nbits, ccECKeyPrivate)) == NULL) return kCCMemoryFailure;
301                ccec_const_cp_t cp = ccec_get_cp(nbits);
302                __Require_Action(ccec_x963_import_priv(cp, keyPackageLen, keyPackage, cryptor->ecKey.private) == 0, errOut, retval = kCCDecodeError);
303                cryptor->keySize = nbits;
304            } else if(keyType == ccECKeyPublic) {
305                size_t nbits = ccec_x963_import_pub_size(keyPackageLen);
306                if((cryptor = ccMallocECCryptor(nbits, ccECKeyPublic)) == NULL) return kCCMemoryFailure;
307                ccec_const_cp_t cp = ccec_get_cp(nbits);
308                __Require_Action(ccec_x963_import_pub(cp, keyPackageLen, keyPackage, cryptor->ecKey.public) == 0, errOut, retval = kCCDecodeError);
309                cryptor->keySize = nbits;
310            } else return kCCParamError;
311
312            cryptor->keyType = keyType;
313            *key = cryptor;
314            break;
315        case kCCImportKeyDER:
316            retval = kCCUnimplemented;
317            break;
318        default:
319            retval = kCCParamError;
320            break;
321    }
322
323
324errOut:
325    if(retval) {
326        *key = NULL;
327        if(cryptor) ccECCryptorFree(cryptor);
328    }
329
330    return retval;
331}
332
333
334CCCryptorStatus CCECCryptorExportPublicKey(CCECCryptorRef key, void *out, size_t *outLen)
335{
336    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
337    if(key == NULL) return kCCParamError;
338    if(out == NULL) return kCCParamError;
339
340    return CCECCryptorExportKey(kCCImportKeyBinary, out, outLen, ccECKeyPublic, key);
341}
342
343CCCryptorStatus CCECCryptorExportKey(CCECKeyExternalFormat format, void *keyPackage, size_t *keyPackageLen, CCECKeyType keyType, CCECCryptorRef key)
344{
345    CCCryptorStatus retval = kCCSuccess;
346
347    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
348    if(key == NULL) return kCCParamError;
349    if(keyPackage == NULL) return kCCParamError;
350
351    switch(format) {
352        case kCCImportKeyBinary: {
353            size_t len = ccec_x963_export_size(keyType == ccECKeyPrivate, key->ecKey.private);
354
355            if(len > *keyPackageLen) {
356                *keyPackageLen = len;
357                return kCCMemoryFailure;
358            }
359            *keyPackageLen = len;
360
361            ccec_x963_export(keyType == ccECKeyPrivate, keyPackage, key->ecKey.private);
362            break;
363        }
364        case kCCImportKeyDER:
365            retval = kCCUnimplemented;
366            break;
367        default:
368            retval = kCCParamError;
369            break;
370    }
371
372    return retval;
373}
374
375
376
377CCCryptorStatus
378CCECCryptorSignHash(CCECCryptorRef privateKey,
379                    const void *hashToSign, size_t hashSignLen,
380                    void *signedData, size_t *signedDataLen)
381{
382    CCCryptorStatus retval = kCCSuccess;
383
384    // CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
385    if(privateKey == NULL || hashToSign == NULL || signedData == NULL || signedDataLen == NULL) return kCCParamError;
386
387    struct ccrng_state *therng = ccDRBGGetRngState();
388
389    if(ccec_sign(privateKey->ecKey.private, hashSignLen, hashToSign, signedDataLen, signedData, therng) != 0)
390        retval = kCCDecodeError;
391    return retval;
392}
393
394
395
396CCCryptorStatus
397CCECCryptorVerifyHash(CCECCryptorRef publicKey,
398                      const void *hash, size_t hashLen,
399                      const void *signedData, size_t signedDataLen, uint32_t *valid)
400{
401    CCCryptorStatus retval = kCCSuccess;
402    bool           stat = 0;
403
404    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
405    if(publicKey == NULL || hash == NULL || signedData == NULL) return kCCParamError;
406
407    if(ccec_verify(publicKey->ecKey.public, hashLen, hash,
408                   signedDataLen, signedData, &stat)) retval = kCCDecodeError;
409	*valid = stat;
410    return retval;
411}
412
413
414#pragma mark API for ECDH - needs corecrypto key import / export capability (SPI for now)
415
416
417CCCryptorStatus
418CCECCryptorWrapKey(CCECCryptorRef publicKey,
419                   const void *plainText, size_t plainTextLen,
420                   void *cipherText, size_t *cipherTextLen,
421                   CCDigestAlg digestType)
422{
423    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
424    return kCCUnimplemented;
425}
426
427
428CCCryptorStatus
429CCECCryptorUnwrapKey(CCECCryptorRef privateKey,
430                     const void *cipherText, size_t cipherTextLen,
431                     void *plainText, size_t *plainTextLen)
432{
433    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
434    return kCCUnimplemented;
435}
436
437
438CCCryptorStatus
439CCECCryptorComputeSharedSecret(CCECCryptorRef privateKey, CCECCryptorRef publicKey,
440                               void *out, size_t *outLen)
441{
442    CCCryptorStatus retval = kCCSuccess;
443
444    CC_DEBUG_LOG(ASL_LEVEL_ERR, "Entering\n");
445    if(privateKey == NULL || publicKey == NULL) return kCCParamError;
446    if(out == NULL) return kCCParamError;
447
448    if(ccec_compute_key(privateKey->ecKey.private, publicKey->ecKey.public,
449                        outLen, out)) return kCCDecodeError;
450
451    return retval;
452}
453
454
455