1/* 2 * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19/* 20 * FEEKeys.cpp - FEE-related asymmetric key pair classes. 21 * 22 */ 23 24#ifdef CRYPTKIT_CSP_ENABLE 25 26#include "FEEKeys.h" 27#include "FEECSPUtils.h" 28#include "CryptKitSpace.h" 29#include <security_cryptkit/feePublicKey.h> 30#include <security_cryptkit/falloc.h> 31#include <security_cdsa_utilities/cssmdata.h> 32#include "AppleCSPSession.h" 33#include "AppleCSPUtils.h" 34#include <assert.h> 35#include <security_utilities/debugging.h> 36 37#define feeKeyDebug(args...) secdebug("feeKey", ## args) 38 39/*** 40 *** FEE-style BinaryKey 41 ***/ 42 43/* constructor with optional existing feePubKey */ 44CryptKit::FEEBinaryKey::FEEBinaryKey(feePubKey feeKey) 45 : mFeeKey(feeKey) 46{ 47 if(mFeeKey == NULL) { 48 mFeeKey = feePubKeyAlloc(); 49 if(mFeeKey == NULL) { 50 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); 51 } 52 } 53} 54 55CryptKit::FEEBinaryKey::~FEEBinaryKey() 56{ 57 if(mFeeKey) { 58 feePubKeyFree(mFeeKey); 59 mFeeKey = NULL; 60 } 61} 62 63void CryptKit::FEEBinaryKey::generateKeyBlob( 64 Allocator &allocator, 65 CssmData &blob, 66 CSSM_KEYBLOB_FORMAT &format, 67 AppleCSPSession &session, 68 const CssmKey *paramKey, /* optional, unused here */ 69 CSSM_KEYATTR_FLAGS &attrFlags) /* IN/OUT */ 70{ 71 unsigned char *keyBlob; 72 unsigned len; 73 feeReturn frtn = FR_Internal; 74 bool freeTheKey = false; 75 feePubKey keyToEncode = mFeeKey; 76 77 assert(mFeeKey != NULL); 78 if((format == CSSM_KEYBLOB_RAW_FORMAT_DIGEST) && 79 (mKeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY)) { 80 /* key digest calculation; special case for private keys: cook 81 * up the associated public key and encode that */ 82 keyToEncode = feePubKeyAlloc(); 83 if(keyToEncode == NULL) { 84 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); 85 } 86 frtn = feePubKeyInitPubKeyFromPriv(mFeeKey, keyToEncode); 87 if(frtn) { 88 feePubKeyFree(keyToEncode); 89 throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv"); 90 } 91 freeTheKey = true; 92 } 93 94 bool badFormat = false; 95 int isPrivate = feePubKeyIsPrivate(keyToEncode); 96 97 switch(mKeyHeader.AlgorithmId) { 98 case CSSM_ALGID_FEE: 99 if(isPrivate) { 100 /* FEE private key */ 101 switch(format) { 102 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: 103 format = CSSM_KEYBLOB_RAW_FORMAT_NONE; 104 /* and drop thru */ 105 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 106 frtn = feePubKeyCreateDERPrivBlob(keyToEncode, &keyBlob, &len); 107 break; 108 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 109 frtn = feePubKeyCreatePrivBlob(keyToEncode, &keyBlob, &len); 110 break; 111 default: 112 badFormat = true; 113 break; 114 } 115 } 116 else { 117 /* FEE Public key */ 118 switch(format) { 119 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: 120 format = CSSM_KEYBLOB_RAW_FORMAT_NONE; 121 /* and drop thru */ 122 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 123 frtn = feePubKeyCreateDERPubBlob(keyToEncode, &keyBlob, &len); 124 break; 125 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 126 frtn = feePubKeyCreatePubBlob(keyToEncode, &keyBlob, &len); 127 break; 128 default: 129 badFormat = true; 130 break; 131 } 132 } 133 /* end of base ALGID_FEE */ 134 break; 135 136 case CSSM_ALGID_ECDSA: 137 if(isPrivate) { 138 /* ECDSA/ECDH private key */ 139 switch(format) { 140 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: 141 /* ECDSA private key: PKCS8 */ 142 frtn = feePubKeyCreatePKCS8Blob(keyToEncode, &keyBlob, &len); 143 break; 144 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 145 /* set to default format, drop thru */ 146 format = CSSM_KEYBLOB_RAW_FORMAT_OPENSSL; 147 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: 148 /* ECDSA private key, SEC1/OpenSSL format */ 149 frtn = feePubKeyCreateOpenSSLBlob(keyToEncode, &keyBlob, &len); 150 break; 151 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: 152 format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; 153 /* and drop thru */ 154 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 155 /* raw private key bytes */ 156 frtn = feeCreateECDSAPrivBlob(keyToEncode, &keyBlob, &len); 157 break; 158 default: 159 badFormat = true; 160 break; 161 } 162 } 163 else { 164 /* 165 * ECDSA public key. 166 * Note there is no OpenSSL case here, that format is only generated for 167 * private keys. 168 */ 169 switch(format) { 170 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 171 /* set to default format, drop thru */ 172 format = CSSM_KEYBLOB_RAW_FORMAT_X509; 173 case CSSM_KEYBLOB_RAW_FORMAT_X509: 174 /* ECDSA, public key, default: X509 */ 175 frtn = feePubKeyCreateX509Blob(keyToEncode, &keyBlob, &len); 176 break; 177 case CSSM_KEYBLOB_RAW_FORMAT_DIGEST: 178 format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING; 179 /* and drop thru */ 180 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 181 /* raw x|y string */ 182 frtn = feeCreateECDSAPubBlob(keyToEncode, &keyBlob, &len); 183 break; 184 default: 185 badFormat = true; 186 break; 187 } 188 } 189 /* end of case CSSM_ALGID_ECDSA */ 190 break; 191 default: 192 /* not reached */ 193 break; 194 } 195 196 if(badFormat) { 197 CssmError::throwMe(isPrivate ? 198 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT : 199 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT); 200 } 201 if(frtn) { 202 throwCryptKit(frtn, "feePubKeyCreate*Blob"); 203 } 204 setUpCssmData(blob, len, allocator); 205 memmove(blob.data(), keyBlob, len); 206 blob.length(len); 207 ffree(keyBlob); 208 if(freeTheKey) { 209 /* free the temp pub key we created here */ 210 feePubKeyFree(keyToEncode); 211 } 212} 213 214/*** 215 *** FEE-style AppleKeyPairGenContext 216 ***/ 217 218/* 219 * This one is specified in, and called from, CSPFullPluginSession. Our 220 * only job is to prepare two subclass-specific BinaryKeys and call up to 221 * AppleKeyPairGenContext. 222 */ 223void CryptKit::FEEKeyPairGenContext::generate( 224 const Context &context, 225 CssmKey &pubKey, 226 CssmKey &privKey) 227{ 228 FEEBinaryKey *pubBinKey = new FEEBinaryKey(); 229 FEEBinaryKey *privBinKey = new FEEBinaryKey(); 230 231 try { 232 AppleKeyPairGenContext::generate(context, 233 session(), 234 pubKey, 235 pubBinKey, 236 privKey, 237 privBinKey); 238 } 239 catch (...) { 240 delete pubBinKey; 241 delete privBinKey; 242 throw; 243 } 244 245} 246 247// this one is specified in, and called from, AppleKeyPairGenContext 248void CryptKit::FEEKeyPairGenContext::generate( 249 const Context &context, 250 BinaryKey &pubBinKey, 251 BinaryKey &privBinKey, 252 uint32 &keyBits) 253{ 254 /* 255 * These casts throw exceptions if the keys are of the 256 * wrong classes, which would be a major bogon, since we created 257 * the keys in the above generate() function. 258 */ 259 FEEBinaryKey &fPubBinKey = 260 dynamic_cast<FEEBinaryKey &>(pubBinKey); 261 FEEBinaryKey &fPrivBinKey = 262 dynamic_cast<FEEBinaryKey &>(privBinKey); 263 264 /* 265 * Two parameters from context. Key size in bits is required; 266 * seed is optional. If not present, we cook up random private data. 267 */ 268 keyBits = context.getInt(CSSM_ATTRIBUTE_KEY_LENGTH, 269 CSSMERR_CSP_MISSING_ATTR_KEY_LENGTH); 270 CssmCryptoData *cseed = context.get<CssmCryptoData>(CSSM_ATTRIBUTE_SEED); 271 CssmData *seed; 272 bool haveSeed; 273 CssmAutoData aSeed(session()); // malloc on demand 274 if(cseed) { 275 /* caller specified seed */ 276 haveSeed = true; 277 seed = &cseed->param(); 278 } 279 else { 280 /* generate random seed */ 281 haveSeed = false; 282 unsigned keyBytes = ((keyBits + 7) / 8) + 1; 283 aSeed.malloc(keyBytes); 284 session().getRandomBytes(keyBytes, aSeed); 285 seed = &aSeed.get(); 286 } 287 288 CSSM_ALGORITHMS algId = context.algorithm(); 289 290 /* Curve and prime types - optional */ 291 feePrimeType primeType = FPT_Default; 292 uint32 uPrimeType = context.getInt(CSSM_ATTRIBUTE_FEE_PRIME_TYPE); 293 switch(uPrimeType) { 294 case CSSM_FEE_PRIME_TYPE_DEFAULT: 295 break; 296 case CSSM_FEE_PRIME_TYPE_MERSENNE: 297 primeType = FPT_Mersenne; 298 break; 299 case CSSM_FEE_PRIME_TYPE_FEE: 300 primeType = FPT_FEE; 301 break; 302 case CSSM_FEE_PRIME_TYPE_GENERAL: 303 primeType = FPT_General; 304 break; 305 default: 306 /* FIXME - maybe we should be more specific */ 307 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS); 308 } 309 feeCurveType curveType = FCT_Default; 310 switch(algId) { 311 case CSSM_ALGID_ECDSA: 312 /* no options */ 313 curveType = FCT_ANSI; 314 break; 315 default: 316 { 317 uint32 uCurveType = context.getInt(CSSM_ATTRIBUTE_FEE_CURVE_TYPE); 318 switch(uCurveType) { 319 case CSSM_FEE_CURVE_TYPE_DEFAULT: 320 break; 321 case CSSM_FEE_CURVE_TYPE_MONTGOMERY: 322 curveType = FCT_Montgomery; 323 break; 324 case CSSM_FEE_CURVE_TYPE_WEIERSTRASS: 325 curveType = FCT_Weierstrass; 326 break; 327 case CSSM_FEE_CURVE_TYPE_ANSI_X9_62: 328 curveType = FCT_ANSI; 329 break; 330 default: 331 /* FIXME - maybe we should be more specific */ 332 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_ALG_PARAMS); 333 } 334 break; 335 } 336 } 337 feeReturn frtn = feePubKeyInitFromPrivDataKeyBits( 338 fPrivBinKey.feeKey(), 339 (unsigned char *)seed->data(), 340 (unsigned int)seed->length(), 341 keyBits, 342 primeType, 343 curveType, 344 /* 345 * our random seed: trust it 346 * caller's seed: hash it 347 */ 348 haveSeed ? 1 : 0); 349 if(frtn) { 350 throwCryptKit(frtn, "feePubKeyInitFromPrivDataKeyBits"); 351 } 352 frtn = feePubKeyInitPubKeyFromPriv(fPrivBinKey.feeKey(), 353 fPubBinKey.feeKey()); 354 if(frtn) { 355 throwCryptKit(frtn, "feePubKeyInitPubKeyFromPriv"); 356 } 357} 358 359 360/*** 361 *** FEE-style CSPKeyInfoProvider. 362 ***/ 363CryptKit::FEEKeyInfoProvider::FEEKeyInfoProvider( 364 const CssmKey &cssmKey, 365 AppleCSPSession &session) : 366 CSPKeyInfoProvider(cssmKey, session) 367{ 368} 369CSPKeyInfoProvider *FEEKeyInfoProvider::provider( 370 const CssmKey &cssmKey, 371 AppleCSPSession &session) 372{ 373 switch(cssmKey.algorithm()) { 374 case CSSM_ALGID_FEE: 375 case CSSM_ALGID_ECDSA: 376 break; 377 default: 378 return NULL; 379 } 380 switch(cssmKey.keyClass()) { 381 case CSSM_KEYCLASS_PUBLIC_KEY: 382 case CSSM_KEYCLASS_PRIVATE_KEY: 383 /* FIXME - verify proper CSSM_KEYBLOB_RAW_FORMAT_xx */ 384 break; 385 default: 386 return NULL; 387 } 388 /* OK, we'll handle this one */ 389 return new FEEKeyInfoProvider(cssmKey, session); 390} 391 392/* Given a raw key, cook up a Binary key */ 393void CryptKit::FEEKeyInfoProvider::CssmKeyToBinary( 394 CssmKey *paramKey, // optional, ignored 395 CSSM_KEYATTR_FLAGS &attrFlags, // IN/OUT 396 BinaryKey **binKey) 397{ 398 *binKey = NULL; 399 feePubKey feeKey = NULL; 400 401 /* first cook up a feePubKey, then drop that into a BinaryKey */ 402 feeKey = rawCssmKeyToFee(mKey); 403 FEEBinaryKey *feeBinKey = new FEEBinaryKey(feeKey); 404 *binKey = feeBinKey; 405} 406 407/* 408 * Obtain key size in bits. 409 * Currently only raw public keys are dealt with (they're the ones 410 * which come from certs, the only current use for this function). 411 * Note that if we need to handle ref keys, we'll need a session ref... 412 */ 413void CryptKit::FEEKeyInfoProvider::QueryKeySizeInBits( 414 CSSM_KEY_SIZE &keySize) 415{ 416 feePubKey feeKey = NULL; 417 418 if(mKey.blobType() != CSSM_KEYBLOB_RAW) { 419 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_FORMAT); 420 } 421 feeKey = rawCssmKeyToFee(mKey); 422 keySize.LogicalKeySizeInBits = feePubKeyBitsize(feeKey); 423 keySize.EffectiveKeySizeInBits = keySize.LogicalKeySizeInBits; 424 feePubKeyFree(feeKey); 425} 426 427/* 428 * Obtain blob suitable for hashing in CSSM_APPLECSP_KEYDIGEST 429 * passthrough. 430 */ 431bool CryptKit::FEEKeyInfoProvider::getHashableBlob( 432 Allocator &allocator, 433 CssmData &blob) // blob to hash goes here 434{ 435 /* 436 * The optimized case, a raw key in the "proper" format already. 437 * Currently this is: 438 * FEE public key in default/NONE form (which happens to be DER) 439 */ 440 assert(mKey.blobType() == CSSM_KEYBLOB_RAW); 441 if((mKey.algorithm() == CSSM_ALGID_FEE) && 442 (mKey.blobFormat() == CSSM_KEYBLOB_RAW_FORMAT_NONE) && 443 (mKey.keyClass() == CSSM_KEYCLASS_PUBLIC_KEY)) { 444 const CssmData &keyBlob = CssmData::overlay(mKey.KeyData); 445 copyCssmData(keyBlob, blob, allocator); 446 return true; 447 } 448 449 /* caller converts to binary and proceeds */ 450 return false; 451} 452 453#endif /* CRYPTKIT_CSP_ENABLE */ 454