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