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