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 * FEECSPUtils.h - Misc. utility function for FEE/CryptKit CSP. 21 * 22 */ 23 24#ifdef CRYPTKIT_CSP_ENABLE 25 26#include <security_utilities/debugging.h> 27#include <security_utilities/logging.h> 28#include "FEECSPUtils.h" 29#include "FEEKeys.h" 30#include <security_cryptkit/feeFunctions.h> 31#include <security_cryptkit/feePublicKey.h> 32 33#define feeMiscDebug(args...) secdebug("feeMisc", ## args) 34 35/* Given a FEE error, throw appropriate CssmError */ 36void CryptKit::throwCryptKit( 37 feeReturn frtn, 38 const char *op) /* optional */ 39{ 40 if(op) { 41 Security::Syslog::error("Apple CSP %s: %s", op, feeReturnString(frtn)); 42 } 43 switch(frtn) { 44 case FR_Success: 45 return; 46 case FR_BadPubKey: 47 case FR_BadPubKeyString: 48 case FR_IncompatibleKey: 49 case FR_BadKeyBlob: 50 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 51 case FR_IllegalDepth: 52 CssmError::throwMe(CSSMERR_CSP_UNSUPPORTED_KEY_SIZE); 53 case FR_BadSignatureFormat: /* signature corrupted */ 54 CssmError::throwMe(CSSMERR_CSP_INVALID_SIGNATURE); 55 case FR_InvalidSignature: /* signature intact, but not valid */ 56 CssmError::throwMe(CSSMERR_CSP_VERIFY_FAILED); 57 case FR_IllegalArg: /* illegal argument */ 58 CssmError::throwMe(CSSMERR_CSP_INVALID_CONTEXT); 59 case FR_BadCipherText: /* malformed ciphertext */ 60 case FR_BadEnc64: /* bad enc64() format */ 61 CssmError::throwMe(CSSMERR_CSP_INVALID_DATA); 62 case FR_Unimplemented: /* unimplemented function */ 63 CssmError::throwMe(CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED); 64 case FR_Memory: /* unimplemented function */ 65 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); 66 case FR_ShortPrivData: 67 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_SEED); 68 case FR_IllegalCurve: /* e.g., ECDSA with Montgomery curve */ 69 CssmError::throwMe(CSSMERR_CSP_INVALID_ATTR_KEY); 70 71 /* I don't think we should ever see these no matter what the 72 * caller throws at us */ 73 case FR_WrongSignatureType: /* ElGamal vs. ECDSA */ 74 case FR_BadUsageName: /* bad usageName */ 75 case FR_BadCipherFile: 76 case FR_Internal: /* internal library error */ 77 CssmError::throwMe(CSSMERR_CSP_INTERNAL_ERROR); 78 } 79} 80 81/* 82 * Given a Context: 83 * -- obtain CSSM key of specified CSSM_ATTRIBUTE_TYPE 84 * -- validate keyClass 85 * -- validate keyUsage 86 * -- convert to feePubKey, allocating the feePubKey if necessary 87 * 88 * Returned key can be of algorithm CSSM_ALGID_ECDSA or CSSM_ALGID_FEE; 89 * caller has to verify proper algorithm for operation. 90 */ 91feePubKey CryptKit::contextToFeeKey( 92 const Context &context, 93 AppleCSPSession &session, 94 CSSM_ATTRIBUTE_TYPE attrType, // CSSM_ATTRIBUTE_KEY, CSSM_ATTRIBUTE_PUBLIC_KEY 95 CSSM_KEYCLASS keyClass, // CSSM_KEYCLASS_{PUBLIC,PRIVATE}_KEY 96 CSSM_KEYUSE usage, // CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_SIGN, etc. 97 bool &mallocdKey) // RETURNED 98{ 99 CssmKey &cssmKey = 100 context.get<CssmKey>(attrType, CSSMERR_CSP_MISSING_ATTR_KEY); 101 const CSSM_KEYHEADER &hdr = cssmKey.KeyHeader; 102 switch(hdr.AlgorithmId) { 103 case CSSM_ALGID_FEE: 104 case CSSM_ALGID_ECDSA: 105 break; 106 default: 107 CssmError::throwMe(CSSMERR_CSP_ALGID_MISMATCH); 108 } 109 if(hdr.KeyClass != keyClass) { 110 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); 111 } 112 cspValidateIntendedKeyUsage(&hdr, usage); 113 cspVerifyKeyTimes(hdr); 114 return cssmKeyToFee(cssmKey, session, mallocdKey); 115} 116 117/* 118 * Convert a CssmKey to a feePubKey. May result in the creation of a new 119 * feePubKey (when cssmKey is a raw key); allocdKey is true in that case 120 * in which case the caller generally has to free the allocd key). 121 */ 122feePubKey CryptKit::cssmKeyToFee( 123 const CssmKey &cssmKey, 124 AppleCSPSession &session, 125 bool &allocdKey) // RETURNED 126{ 127 feePubKey feeKey = NULL; 128 allocdKey = false; 129 130 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader; 131 switch(hdr->AlgorithmId) { 132 case CSSM_ALGID_FEE: 133 case CSSM_ALGID_ECDSA: 134 break; 135 default: 136 // someone else's key (should never happen) 137 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); 138 } 139 switch(hdr->BlobType) { 140 case CSSM_KEYBLOB_RAW: 141 feeKey = rawCssmKeyToFee(cssmKey); 142 allocdKey = true; 143 break; 144 case CSSM_KEYBLOB_REFERENCE: 145 { 146 BinaryKey &binKey = session.lookupRefKey(cssmKey); 147 FEEBinaryKey *feeBinKey = dynamic_cast<FEEBinaryKey *>(&binKey); 148 /* this cast failing means that this is some other 149 * kind of binary key */ 150 if(feeBinKey == NULL) { 151 feeMiscDebug("CryptKit::cssmKeyToFee: wrong BinaryKey subclass\n"); 152 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY); 153 } 154 assert(feeBinKey->feeKey() != NULL); 155 feeKey = feeBinKey->feeKey(); 156 break; 157 } 158 default: 159 CssmError::throwMe(CSSMERR_CSP_KEY_BLOB_TYPE_INCORRECT); 160 } 161 return feeKey; 162} 163 164/* 165 * Convert a raw CssmKey to a newly alloc'd feePubKey. 166 */ 167feePubKey CryptKit::rawCssmKeyToFee( 168 const CssmKey &cssmKey) 169{ 170 const CSSM_KEYHEADER *hdr = &cssmKey.KeyHeader; 171 assert(hdr->BlobType == CSSM_KEYBLOB_RAW); 172 173 switch(hdr->AlgorithmId) { 174 case CSSM_ALGID_FEE: 175 case CSSM_ALGID_ECDSA: 176 break; 177 default: 178 // someone else's key (should never happen) 179 CssmError::throwMe(CSSMERR_CSP_INVALID_ALGORITHM); 180 } 181 182 switch(hdr->KeyClass) { 183 case CSSM_KEYCLASS_PUBLIC_KEY: 184 case CSSM_KEYCLASS_PRIVATE_KEY: 185 break; 186 default: 187 // someone else's key 188 CssmError::throwMe(CSSMERR_CSP_INVALID_KEY_CLASS); 189 } 190 191 feePubKey feeKey = feePubKeyAlloc(); 192 if(feeKey == NULL) { 193 CssmError::throwMe(CSSMERR_CSP_MEMORY_ERROR); 194 } 195 196 feeReturn frtn = FR_IllegalArg; 197 bool badFormat = false; 198 199 /* 200 * The actual key init depends on key type and incoming format 201 */ 202 switch(hdr->AlgorithmId) { 203 case CSSM_ALGID_FEE: 204 switch(hdr->KeyClass) { 205 case CSSM_KEYCLASS_PUBLIC_KEY: 206 switch(hdr->Format) { 207 case FEE_KEYBLOB_DEFAULT_FORMAT: 208 /* FEE, public key, default: custom DER */ 209 frtn = feePubKeyInitFromDERPubBlob(feeKey, 210 cssmKey.KeyData.Data, 211 cssmKey.KeyData.Length); 212 break; 213 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 214 /* FEE, public key, native byte stream */ 215 frtn = feePubKeyInitFromPubBlob(feeKey, 216 cssmKey.KeyData.Data, 217 (unsigned int)cssmKey.KeyData.Length); 218 break; 219 default: 220 badFormat = true; 221 break; 222 } 223 break; 224 case CSSM_KEYCLASS_PRIVATE_KEY: 225 switch(hdr->Format) { 226 case FEE_KEYBLOB_DEFAULT_FORMAT: 227 /* FEE, private key, default: custom DER */ 228 frtn = feePubKeyInitFromDERPrivBlob(feeKey, 229 cssmKey.KeyData.Data, 230 cssmKey.KeyData.Length); 231 break; 232 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 233 /* FEE, private key, native byte stream */ 234 frtn = feePubKeyInitFromPrivBlob(feeKey, 235 cssmKey.KeyData.Data, 236 (unsigned int)cssmKey.KeyData.Length); 237 break; 238 default: 239 badFormat = true; 240 break; 241 } 242 break; 243 default: 244 /* not reached, we already checked */ 245 break; 246 } 247 /* end of case ALGID_FEE */ 248 break; 249 250 case CSSM_ALGID_ECDSA: 251 switch(hdr->KeyClass) { 252 case CSSM_KEYCLASS_PUBLIC_KEY: 253 switch(hdr->Format) { 254 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 255 case CSSM_KEYBLOB_RAW_FORMAT_X509: 256 /* ECDSA, public key, default: X509 */ 257 frtn = feePubKeyInitFromX509Blob(feeKey, 258 cssmKey.KeyData.Data, 259 cssmKey.KeyData.Length); 260 break; 261 262 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: 263 /* 264 * An oddity here: we can parse this incoming key, but 265 * it contains both private and public parts. We throw 266 * out the private component here. 267 */ 268 frtn = feePubKeyInitFromOpenSSLBlob(feeKey, 269 1, /* pubOnly */ 270 cssmKey.KeyData.Data, 271 cssmKey.KeyData.Length); 272 break; 273 /* 274 * NOTE: we cannot *import* a key in raw X9.62 format. 275 * We'd need to know the curve, i.e., the feeDepth. 276 * I suppose we could infer that from the blob length but 277 * a better way would be to have a new context attribute 278 * specifying which curve. 279 * For now, imported raw keys have to be in X509 format. 280 */ 281 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 282 default: 283 badFormat = true; 284 break; 285 } 286 break; 287 case CSSM_KEYCLASS_PRIVATE_KEY: 288 switch(hdr->Format) { 289 case CSSM_KEYBLOB_RAW_FORMAT_PKCS8: 290 /* ECDSA, private key, PKCS8 */ 291 frtn = feePubKeyInitFromPKCS8Blob(feeKey, 292 cssmKey.KeyData.Data, 293 cssmKey.KeyData.Length); 294 break; 295 296 case CSSM_KEYBLOB_RAW_FORMAT_NONE: 297 case CSSM_KEYBLOB_RAW_FORMAT_OPENSSL: 298 /* ECDSA, private, default: OpenSSL */ 299 /* see comment above re: OpenSSL public/private keys */ 300 frtn = feePubKeyInitFromOpenSSLBlob(feeKey, 301 0, /* pubOnly */ 302 cssmKey.KeyData.Data, 303 cssmKey.KeyData.Length); 304 break; 305 /* see comment above about X9.62 format public key blobs */ 306 case CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING: 307 default: 308 badFormat = true; 309 break; 310 } 311 break; 312 default: 313 /* not reached, we already checked */ 314 break; 315 } 316 /* end of case CSSM_ALGID_ECDSA */ 317 break; 318 } 319 if(badFormat) { 320 CssmError::throwMe(hdr->KeyClass == CSSM_KEYCLASS_PRIVATE_KEY ? 321 CSSMERR_CSP_INVALID_ATTR_PRIVATE_KEY_FORMAT : 322 CSSMERR_CSP_INVALID_ATTR_PUBLIC_KEY_FORMAT); 323 } 324 if(frtn) { 325 feePubKeyFree(feeKey); 326 throwCryptKit(frtn, "feePubKeyInitFromKeyBlob"); 327 } 328 return feeKey; 329} 330 331/* 332 * Glue function which allows C code to use AppleCSPSession 333 * as an RNG. A ptr to this function gets passed down to 334 * CryptKit C functions as a feeRandFcn. 335 */ 336feeReturn CryptKit::feeRandCallback( 337 void *ref, // actually an AppleCSPSession * 338 unsigned char *bytes, // must be alloc'd by caller 339 unsigned numBytes) 340{ 341 AppleCSPSession *session = 342 reinterpret_cast<AppleCSPSession *>(ref); 343 try { 344 session->getRandomBytes(numBytes, bytes); 345 } 346 catch(...) { 347 return FR_Internal; 348 } 349 return FR_Success; 350} 351 352#endif /* CRYPTKIT_CSP_ENABLE */ 353