MYSymmetricKey.m
author Jens Alfke <jens@mooseyard.com>
Tue Jul 21 10:13:08 2009 -0700 (2009-07-21)
changeset 27 d0aadddb9c64
parent 23 39fec79de6e8
permissions -rw-r--r--
MYCertificate now checks validity of self-signed certs loaded from the keychain (because the Security framework doesn't validate self-signed certs.)
     1 //
     2 //  MYSymmetricKey.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 4/2/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYSymmetricKey.h"
    10 #import "MYCryptor.h"
    11 #import "MYCrypto_Private.h"
    12 
    13 #if !MYCRYPTO_USE_IPHONE_API
    14 
    15 #import <Security/cssmtype.h>
    16 
    17 
    18 CSSM_ALGORITHMS CSSMFromCCAlgorithm( CCAlgorithm ccAlgorithm ) {
    19     static const CSSM_ALGORITHMS kCSSMAlgorithms[] = {
    20         CSSM_ALGID_AES, CSSM_ALGID_DES, CSSM_ALGID_3DES_3KEY, CSSM_ALGID_CAST, CSSM_ALGID_RC4
    21     };
    22     if (ccAlgorithm >=0 && ccAlgorithm <= kCCAlgorithmRC4)
    23         return kCSSMAlgorithms[ccAlgorithm];
    24     else
    25         return CSSM_ALGID_NONE;
    26 }
    27 
    28 static const char *kCCAlgorithmNames[] = {"AES", "DES", "DES^3", "CAST", "RC4"};
    29 
    30 
    31 /** Undocumented Security function. Unfortunately this is the only way I can find to create
    32     a SecKeyRef from a CSSM_KEY. */
    33 extern OSStatus SecKeyCreate(const CSSM_KEY *key, SecKeyRef* keyRef) WEAK_IMPORT_ATTRIBUTE;
    34 
    35 static CSSM_KEY* cssmKeyFromData( NSData *keyData, CSSM_ALGORITHMS algorithm,
    36                                  MYKeychain *keychain);
    37 
    38 #if !TARGET_OS_IPHONE
    39 static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData,
    40                                        CSSM_ALGORITHMS algorithm,
    41                                        unsigned sizeInBits);
    42 static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm);
    43 static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm);
    44 #endif
    45 
    46 static CSSM_DATA makeSalt( id salty, size_t length );
    47 static CSSM_RETURN impExpCreatePassKey(
    48 	const SecKeyImportExportParameters *keyParams,  // required
    49 	CSSM_CSP_HANDLE		cspHand,		// MUST be CSPDL
    50 	BOOL                verifyPhrase,   // use 2nd passphrase textfield for verification?
    51 	CSSM_KEY_PTR		*passKey);	// mallocd and RETURNED
    52 
    53 
    54 #pragma mark -
    55 @implementation MYSymmetricKey
    56 
    57 
    58 - (id) _initWithCSSMKey: (CSSM_KEY*)cssmKey {
    59     if (!cssmKey) {
    60         [self release];
    61         return nil;
    62     }
    63     SecKeyRef keyRef = NULL;
    64     if (SecKeyCreate == NULL) {
    65         // If weak-linked SPI fn no longer exists
    66         Warn(@"Unable to call SecKeyCreate SPI -- not available");
    67         [self release];
    68         return nil;
    69     }
    70     if (!check(SecKeyCreate(cssmKey,&keyRef), @"SecKeyCreate")) {
    71         [self release];
    72         return nil;
    73     }
    74     self = [self initWithKeyRef: keyRef];
    75     if (self) {
    76         _ownedCSSMKey = cssmKey;            // (so I'll remember to free it)
    77     }
    78     return self;
    79 }
    80 
    81 
    82 - (id) _initWithKeyData: (NSData*)keyData
    83               algorithm: (CCAlgorithm)algorithm
    84              inKeychain: (MYKeychain*)keychain
    85 {
    86     Assert(algorithm <= kCCAlgorithmRC4);
    87     Assert(keyData);
    88     CSSM_KEY *key = cssmKeyFromData(keyData, CSSMFromCCAlgorithm(algorithm), keychain);
    89     return [self _initWithCSSMKey: key];
    90 }
    91 
    92 - (id) initWithKeyData: (NSData*)keyData
    93              algorithm: (CCAlgorithm)algorithm
    94 {
    95     return [self _initWithKeyData: keyData algorithm: algorithm inKeychain: nil];
    96 }
    97 
    98 + (MYSymmetricKey*) _generateSymmetricKeyOfSize: (unsigned)keySizeInBits
    99                                       algorithm: (CCAlgorithm)algorithm
   100                                      inKeychain: (MYKeychain*)keychain
   101 {
   102     Assert(algorithm <= kCCAlgorithmRC4);
   103     CSSM_KEYATTR_FLAGS flags = CSSM_KEYATTR_EXTRACTABLE;
   104     if (keychain)
   105         flags |= CSSM_KEYATTR_PERMANENT; // | CSSM_KEYATTR_SENSITIVE;   //FIX: Re-enable this bit
   106     else {
   107         flags |= CSSM_KEYATTR_RETURN_REF;
   108         keychain = [MYKeychain defaultKeychain]; // establish a context for the key
   109     }
   110     CSSM_KEYUSE usage = CSSM_KEYUSE_ANY;
   111     SecKeyRef keyRef = NULL;
   112     if (!check(SecKeyGenerate(keychain.keychainRefOrDefault,
   113                               CSSMFromCCAlgorithm(algorithm),
   114                               keySizeInBits, 
   115                               0, usage, flags, NULL, &keyRef),
   116                @"SecKeyGenerate")) {
   117         return nil;
   118     }
   119     return [[[self alloc] initWithKeyRef: keyRef] autorelease];
   120 }
   121 
   122 + (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   123                                      algorithm: (CCAlgorithm)algorithm {
   124     return [self _generateSymmetricKeyOfSize: keySizeInBits
   125                                    algorithm: algorithm
   126                                   inKeychain: nil];
   127 }
   128 
   129 + (NSString*) promptForPassphraseWithAlertTitle: (NSString*)alertTitle
   130                                     alertPrompt: (NSString*)prompt
   131                                         creating: (BOOL)creating
   132 {
   133     // Ask the user for a passphrase:
   134     SecKeyImportExportParameters params = {
   135         .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
   136         .flags = kSecKeySecurePassphrase,
   137         .alertTitle = (CFStringRef)alertTitle,
   138         .alertPrompt = (CFStringRef)prompt,
   139         .keyUsage = CSSM_KEYUSE_ANY,
   140         .keyAttributes = CSSM_KEYATTR_EXTRACTABLE
   141     };
   142     CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle];
   143     CSSM_KEY *passphraseKey = NULL;
   144     if (impExpCreatePassKey(&params, 
   145                             cspHandle, 
   146                             creating,
   147                             &passphraseKey) != CSSM_OK)
   148         return nil;
   149     
   150     MYSymmetricKey *key = [[self alloc] _initWithCSSMKey: passphraseKey];
   151     NSData *keyData = key.keyData;
   152     Assert(keyData);
   153     NSString *passphrase = [[NSString alloc] initWithData: keyData
   154                                                  encoding: NSUTF8StringEncoding];
   155     [key release];
   156     return [passphrase autorelease];
   157 }
   158 
   159 
   160 #define PKCS5_V2_SALT_LEN		8
   161 #define PKCS5_V2_ITERATIONS		2048
   162 #define PKCS5_V2_DES_IV_SIZE	8
   163 
   164 + (MYSymmetricKey*) generateFromUserPassphraseWithAlertTitle: (NSString*)alertTitle
   165                                                  alertPrompt: (NSString*)prompt
   166                                                      creating: (BOOL)creating
   167                                                         salt: (id)saltObj
   168 {
   169     MYSymmetricKey *generatedKey = nil;
   170 
   171     // Ask the user for a passphrase:
   172     SecKeyImportExportParameters params = {
   173         .version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION,
   174         .flags = kSecKeySecurePassphrase,
   175         .alertTitle = (CFStringRef)alertTitle,
   176         .alertPrompt = (CFStringRef)prompt,
   177         .keyUsage = CSSM_KEYUSE_ANY,
   178         .keyAttributes = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_SENSITIVE
   179     };
   180     CSSM_CSP_HANDLE cspHandle = [[MYKeychain defaultKeychain] CSPHandle];
   181     CSSM_KEY *passphraseKey = NULL;
   182     if (impExpCreatePassKey(&params, 
   183                             cspHandle, 
   184                             creating,
   185                             &passphraseKey) != CSSM_OK)
   186         return nil;
   187 
   188     CSSM_DATA saltData = makeSalt(saltObj,PKCS5_V2_SALT_LEN);
   189     CSSM_CRYPTO_DATA seed = {};
   190     
   191     // Now use the secure passphrase to generate a symmetric key:
   192     CSSM_CC_HANDLE ctx = 0;
   193     CSSM_ACCESS_CREDENTIALS credentials = {};
   194     if (checkcssm(CSSM_CSP_CreateDeriveKeyContext(cspHandle,
   195                                                   CSSM_ALGID_PKCS5_PBKDF2,
   196                                                   CSSM_ALGID_AES, 128,
   197                                                   &credentials,
   198                                                   passphraseKey, 
   199                                                   PKCS5_V2_ITERATIONS,
   200                                                   &saltData,
   201                                                   &seed,
   202                                                   &ctx),
   203                   @"CSSM_CSP_CreateDeriveKeyContext")) {
   204         CSSM_PKCS5_PBKDF2_PARAMS params = {.PseudoRandomFunction=CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1};
   205         CSSM_DATA paramData = {.Data=(void*)&params, .Length=sizeof(params)};
   206         CSSM_KEY *cssmKey = calloc(1,sizeof(CSSM_KEY));
   207         if (checkcssm(CSSM_DeriveKey(ctx,
   208                                      &paramData,
   209                                      CSSM_KEYUSE_ANY,
   210                                      CSSM_KEYATTR_EXTRACTABLE, //| CSSM_KEYATTR_SENSITIVE, 
   211                                      NULL, 
   212                                      NULL, 
   213                                      cssmKey),
   214                       @"CSSM_DeriveKey")) {
   215             generatedKey = [[[self alloc] _initWithCSSMKey: cssmKey] autorelease];
   216         }
   217     }
   218     CSSM_DeleteContext(ctx);
   219     CSSM_FreeKey(cspHandle, &credentials, passphraseKey, YES);
   220     return generatedKey;        
   221 }
   222 
   223 
   224 - (void) dealloc
   225 {
   226     if(_ownedCSSMKey) 
   227         CSSM_FreeKey(self.cssmCSPHandle, NULL, _ownedCSSMKey, YES);
   228     [super dealloc];
   229 }
   230 
   231 
   232 #if !TARGET_OS_IPHONE
   233 - (id) initWithWrappedKeyData: (NSData*)wrappedKeyData {
   234     return [self _initWithCSSMKey: unwrapCssmKeyFromData(wrappedKeyData,
   235                                                          CSSM_ALGID_AES,128)];
   236 }
   237 
   238 
   239 - (NSData*) exportWrappedKeyWithPassphrasePrompt: (NSString*)prompt
   240 {
   241     // Prompt user for a passphrase to use for the wrapping key:
   242     MYSymmetricKey *wrappingKey = [MYSymmetricKey 
   243                                    generateFromUserPassphraseWithAlertTitle: @"Export Key" 
   244                                    alertPrompt: prompt 
   245                                    creating: YES
   246                                    salt: [MYCryptor randomKeyOfLength: PKCS5_V2_SALT_LEN*8]];
   247     if (!wrappingKey)
   248         return nil;
   249     Log(@"Wrapping using %@",wrappingKey);
   250     
   251     // Create the context:
   252     CSSM_ACCESS_CREDENTIALS credentials = {};
   253     CSSM_CSP_HANDLE cspHandle = self.cssmCSPHandle;
   254     CSSM_ALGORITHMS algorithm = wrappingKey.cssmAlgorithm;
   255     uint8 iv[16] = {0}; // Right size for AES. Are zeros OK? //FIX: Support other algorithms
   256     CSSM_DATA ivData = {.Data=(void*)&iv, .Length=sizeof(iv)};
   257     CSSM_CC_HANDLE ctx;
   258     if (!checkcssm(CSSM_CSP_CreateSymmetricContext(cspHandle,
   259                                                    algorithm, //CSSM_ALGID_3DES_3KEY_EDE
   260                                                    defaultModeForAlgorithm(algorithm),
   261                                                    &credentials, 
   262                                                    wrappingKey.cssmKey,
   263                                                    &ivData,
   264                                                    defaultPaddingForAlgorithm(algorithm),
   265                                                    NULL,
   266                                                    &ctx), 
   267                    @"CSSM_CSP_CreateSymmetricContext"))
   268         return nil;
   269     
   270     // Now wrap the key:
   271     NSData *result = nil;
   272     CSSM_WRAP_KEY wrappedKey = {};
   273     if (checkcssm(CSSM_WrapKey(ctx, &credentials, self.cssmKey, NULL, &wrappedKey),
   274                   @"CSSM_WrapKey")) {
   275         // ...and copy the wrapped key data to the result NSData:
   276         result = [NSData dataWithBytes: wrappedKey.KeyData.Data length: wrappedKey.KeyData.Length];
   277         CSSM_FreeKey(cspHandle, &credentials, &wrappedKey, NO);
   278     }
   279     // Finally, delete the context
   280     CSSM_DeleteContext(ctx);
   281     return result;
   282 }
   283 #endif
   284 
   285 
   286 - (SecExternalItemType) keyClass {
   287     return kSecItemTypeSessionKey;
   288 }
   289 
   290 - (CCAlgorithm) algorithm {
   291     CSSM_ALGORITHMS cssmAlg;
   292     cssmAlg = self.cssmKey->KeyHeader.AlgorithmId;
   293     switch(cssmAlg) {
   294         case CSSM_ALGID_AES:
   295             return kCCAlgorithmAES128;
   296         case CSSM_ALGID_DES:
   297             return kCCAlgorithmDES;	
   298         case CSSM_ALGID_3DES_3KEY:
   299             return kCCAlgorithm3DES;
   300         case CSSM_ALGID_CAST:
   301             return kCCAlgorithmCAST;
   302         case CSSM_ALGID_RC4:
   303             return kCCAlgorithmRC4;	
   304         default:
   305             Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
   306             return (CCAlgorithm)-1;
   307     }
   308 }
   309 
   310 - (const char*) algorithmName {
   311     CCAlgorithm a = self.algorithm;
   312     if (a >= 0 && a <= kCCAlgorithmRC4)
   313         return kCCAlgorithmNames[a];
   314     else
   315         return "???";
   316 }
   317 
   318 
   319 - (NSString*) description {
   320     return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
   321 }
   322 
   323 
   324 - (NSData*) _cryptData: (NSData*)data operation: (CCOperation)op options: (CCOptions)options
   325 {
   326     NSData *keyData = self.keyData;
   327     Assert(keyData, @"Couldn't get key data");
   328     NSMutableData *output = [NSMutableData dataWithLength: data.length + 256];
   329     size_t bytesWritten = 0;
   330     CCCryptorStatus status = CCCrypt(op, self.algorithm, options, 
   331                                      keyData.bytes, keyData.length, NULL,
   332                                      data.bytes, data.length, output.mutableBytes, output.length,
   333                                      &bytesWritten);
   334     if (status) {
   335         Warn(@"MYSymmetricKey: CCCrypt returned error %i",status);
   336         return nil;
   337     }
   338     output.length = bytesWritten;
   339     return output;
   340 }
   341 
   342 - (NSData*) encryptData: (NSData*)data {
   343     return [self _cryptData: data operation: kCCEncrypt options: kCCOptionPKCS7Padding];
   344 }
   345 
   346 
   347 - (NSData*) decryptData: (NSData*)data {
   348     return [self _cryptData: data operation: kCCDecrypt options: kCCOptionPKCS7Padding];
   349 }
   350 
   351 
   352 @end
   353 
   354 
   355 #pragma mark -
   356 
   357 
   358 static CSSM_KEY* cssmKeyFromData( NSData *keyData, 
   359                                  CSSM_ALGORITHMS algorithm,
   360                                  MYKeychain *keychain ) {
   361     // Thanks to Jim Murphy for showing the way!
   362     if (!keychain) keychain = [MYKeychain defaultKeychain];
   363     CSSM_CC_HANDLE ccHandle;
   364     if (!checkcssm(CSSM_CSP_CreateSymmetricContext([keychain CSPHandle],
   365                                                    CSSM_ALGID_NONE, CSSM_ALGMODE_WRAP,
   366                                                    NULL, NULL, NULL,
   367                                                    CSSM_PADDING_NONE, NULL,
   368                                                    &ccHandle), 
   369                    @"CSSM_CSP_CreateSymmetricContext"))
   370         return NO;
   371     
   372     CSSM_KEY wrappedKey = {
   373         .KeyHeader = {
   374             .BlobType = CSSM_KEYBLOB_RAW,
   375             .Format = CSSM_KEYBLOB_RAW_FORMAT_NONE,
   376             .AlgorithmId = algorithm,
   377             .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
   378             .LogicalKeySizeInBits = keyData.length*8,
   379             .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
   380             .KeyUsage = CSSM_KEYUSE_ANY
   381         },
   382         .KeyData = {
   383             .Data = (void*)keyData.bytes,
   384             .Length = keyData.length
   385         }
   386     };
   387     
   388     CSSM_KEY *outKey = calloc(sizeof(CSSM_KEY),1);
   389     CSSM_DATA desc = {};
   390     if (!checkcssm(CSSM_UnwrapKey(ccHandle,
   391                                   NULL,
   392                                   &wrappedKey,
   393                                   CSSM_KEYUSE_ANY,
   394                                   CSSM_KEYATTR_EXTRACTABLE,
   395                                   NULL,
   396                                   NULL,
   397                                   outKey,
   398                                   &desc),
   399                    @"CSSM_UnwrapKey")) {
   400         free(outKey);
   401         outKey = NULL;
   402     }
   403     CSSM_DeleteContext(ccHandle);
   404     return outKey;
   405 }
   406 
   407 
   408 #if !TARGET_OS_IPHONE
   409 static CSSM_KEY* unwrapCssmKeyFromData(NSData *wrappedData,
   410                                        CSSM_ALGORITHMS algorithm,
   411                                        unsigned sizeInBits) {
   412     Warn(@"MYSymmetricKey: unwrapping is unimplemented; sorry");
   413     return nil;
   414 #if 0 //not finished yet
   415     // First create a wrapped-key structure from the data:
   416     CSSM_WRAP_KEY wrappedKey = {
   417         .KeyHeader = {
   418             .BlobType = CSSM_KEYBLOB_WRAPPED,
   419             .Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS3,
   420             .AlgorithmId = algorithm,
   421             .KeyClass = CSSM_KEYCLASS_SESSION_KEY,
   422             .LogicalKeySizeInBits = sizeInBits,
   423             .KeyAttr = CSSM_KEYATTR_EXTRACTABLE,
   424             .KeyUsage = CSSM_KEYUSE_ANY,
   425             .WrapAlgorithmId = CSSM_ALGID_AES,
   426         },
   427         .KeyData = {
   428             .Data = (void*)wrappedData.bytes,
   429             .Length = wrappedData.length
   430         }
   431     };
   432 #endif
   433 }    
   434 #endif
   435 
   436 
   437 // Create salt data of a specific length from an arbitrary NSObject. */
   438 static CSSM_DATA makeSalt( id salty, size_t length ) {
   439     // Convert to NSData if necessary:
   440     CAssert(salty!=nil);
   441     if (![salty isKindOfClass: [NSData class]])
   442         salty = [[salty description] dataUsingEncoding: NSUTF8StringEncoding];
   443     // Repeat enough times to fill the desired length:
   444     NSMutableData *salt = [[salty mutableCopy] autorelease];
   445     CAssert(salt.length>0);
   446     while (salt.length < length) {
   447         [salt appendData: salt];
   448     }
   449     // Truncate to length and return it:
   450     salt.length = length;
   451     return (CSSM_DATA){.Data=(void*)salt.bytes, .Length=salt.length};
   452 }
   453 
   454 
   455 #pragma mark -
   456 // Code from Keychain.framework:
   457 
   458 #if !TARGET_OS_IPHONE
   459 #if 1
   460 static CSSM_ENCRYPT_MODE defaultModeForAlgorithm(CSSM_ALGORITHMS algorithm) {
   461     switch(algorithm) {
   462         // 8-byte block ciphers
   463         case CSSM_ALGID_DES:
   464         case CSSM_ALGID_3DES_3KEY_EDE:
   465         case CSSM_ALGID_RC5:
   466         case CSSM_ALGID_RC2:
   467             return CSSM_ALGMODE_CBCPadIV8; break;
   468         // 16-byte block ciphers
   469         case CSSM_ALGID_AES:
   470             return CSSM_ALGMODE_CBCPadIV8; break;
   471         // stream ciphers
   472         case CSSM_ALGID_ASC:
   473         case CSSM_ALGID_RC4:
   474             return CSSM_ALGMODE_NONE; break;
   475         // Unknown
   476         default:
   477         	Warn(@"Asked for the default mode for algorithm %d, but don't know that algorithm.\n", algorithm);
   478             return CSSM_ALGMODE_NONE;
   479     }
   480 }
   481 #endif
   482 
   483 #if 1
   484 static CSSM_PADDING defaultPaddingForAlgorithm(CSSM_ALGORITHMS algorithm) {
   485     switch(algorithm) {
   486         /* 8-byte block ciphers */
   487         case CSSM_ALGID_DES:
   488         case CSSM_ALGID_3DES_3KEY_EDE:
   489         case CSSM_ALGID_RC5:
   490         case CSSM_ALGID_RC2:
   491             return CSSM_PADDING_PKCS5; break;
   492             /* 16-byte block ciphers */
   493         case CSSM_ALGID_AES:
   494             return CSSM_PADDING_PKCS7; break;
   495             /* stream ciphers */
   496         case CSSM_ALGID_ASC:
   497         case CSSM_ALGID_RC4:
   498             return CSSM_PADDING_NONE; break;
   499             /* RSA/DSA asymmetric */
   500         case CSSM_ALGID_DSA:
   501         case CSSM_ALGID_RSA:
   502             return CSSM_PADDING_PKCS1; break;
   503             /* Unknown */
   504         default:
   505         	Warn(@"Asked for the default padding mode for %d, but don't know that algorithm.\n", algorithm);
   506             return CSSM_PADDING_NONE;
   507     }
   508 }
   509 #endif
   510 #endif
   511 
   512 #pragma mark -
   513 // Code below was copied from SecImportExportUtils.cpp in Apple's libsecurity_keychain project
   514 
   515 
   516 /*
   517  * Given a context specified via a CSSM_CC_HANDLE, add a new
   518  * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
   519  * AttributeLength, and an untyped pointer.
   520  */
   521 static CSSM_RETURN impExpAddContextAttribute(CSSM_CC_HANDLE CCHandle,
   522 	uint32 AttributeType,
   523 	uint32 AttributeLength,
   524 	const void *AttributePtr)
   525 {
   526 	CSSM_CONTEXT_ATTRIBUTE		newAttr;	
   527 	
   528 	newAttr.AttributeType     = AttributeType;
   529 	newAttr.AttributeLength   = AttributeLength;
   530 	newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
   531 	return CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
   532 }
   533 
   534 /* 
   535 * Add a CFString to a crypto context handle. 
   536 */
   537 static CSSM_RETURN impExpAddStringAttr(
   538 	CSSM_CC_HANDLE ccHand, 
   539 	CFStringRef str,
   540 	CSSM_ATTRIBUTE_TYPE attrType)
   541 {
   542 	/* CFStrings are passed as external rep in UTF8 encoding by convention */
   543 	CFDataRef outData;
   544 	outData = CFStringCreateExternalRepresentation(NULL,
   545 		str, kCFStringEncodingUTF8,	0);		// lossByte 0 ==> no loss allowed 
   546 	if(outData == NULL) {
   547 		Warn(@"impExpAddStringAttr: bad string format");
   548 		return paramErr;
   549 	}
   550 	
   551 	CSSM_DATA attrData;
   552 	attrData.Data = (uint8 *)CFDataGetBytePtr(outData);
   553 	attrData.Length = CFDataGetLength(outData);
   554 	CSSM_RETURN crtn = impExpAddContextAttribute(ccHand, attrType, sizeof(CSSM_DATA),
   555 		&attrData);
   556 	CFRelease(outData);
   557 	if(crtn) {
   558 		Warn(@"impExpAddStringAttr: CSSM_UpdateContextAttributes error");
   559 	}
   560 	return crtn;
   561 }
   562 
   563 /*
   564  * Generate a secure passphrase key. Caller must eventually CSSM_FreeKey the result. 
   565  */
   566 static CSSM_RETURN impExpCreatePassKey(
   567 	const SecKeyImportExportParameters *keyParams,  // required
   568 	CSSM_CSP_HANDLE		cspHand,		// MUST be CSPDL
   569 	BOOL                verifyPhrase,   // use 2nd passphrase textfield for verification?
   570 	CSSM_KEY_PTR		*passKey)		// mallocd and RETURNED
   571 {
   572 	CSSM_RETURN crtn;
   573 	CSSM_CC_HANDLE ccHand;
   574 	uint32 verifyAttr;
   575 	CSSM_DATA dummyLabel;
   576 	CSSM_KEY_PTR ourKey = NULL;
   577 	
   578 	Log(@"Generating secure passphrase key");
   579 	ourKey = (CSSM_KEY_PTR)malloc(sizeof(CSSM_KEY));
   580 	if(ourKey == NULL) {
   581 		return memFullErr;
   582 	}
   583 	memset(ourKey, 0, sizeof(CSSM_KEY));
   584 	
   585 	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
   586 		CSSM_ALGID_SECURE_PASSPHRASE,
   587 		4,				// keySizeInBits must be non zero
   588 		NULL,			// Seed
   589 		NULL,			// Salt
   590 		NULL,			// StartDate
   591 		NULL,			// EndDate
   592 		NULL,			// Params
   593 		&ccHand);
   594 	if(crtn) {
   595 		checkcssm(crtn,@"CSSM_CSP_CreateKeyGenContext");
   596 		return crtn;
   597 	}
   598 	/* subsequent errors to errOut: */
   599 	
   600 	/* additional context attributes specific to this type of key gen */
   601 	CAssert(keyParams != NULL);			// or we wouldn't be here
   602 	if(keyParams->alertTitle != NULL) {
   603 		crtn = impExpAddStringAttr(ccHand, keyParams->alertTitle, 
   604 			CSSM_ATTRIBUTE_ALERT_TITLE);
   605 		if(crtn) {
   606 			goto errOut;
   607 		}
   608 	}
   609 	if(keyParams->alertPrompt != NULL) {
   610 		crtn = impExpAddStringAttr(ccHand, keyParams->alertPrompt, 
   611 			CSSM_ATTRIBUTE_PROMPT);
   612 		if(crtn) {
   613 			goto errOut;
   614 		}
   615 	}
   616 	verifyAttr = verifyPhrase ? 1 : 0;
   617 	crtn = impExpAddContextAttribute(ccHand, CSSM_ATTRIBUTE_VERIFY_PASSPHRASE,
   618 		sizeof(uint32), (const void *)verifyAttr);
   619 	if(crtn) {
   620 		checkcssm(crtn,@"impExpAddContextAttribute");
   621 		goto errOut;
   622 	}
   623 
   624 	dummyLabel.Data = (uint8 *)"Secure Passphrase";
   625 	dummyLabel.Length = strlen((char *)dummyLabel.Data);
   626     
   627     uint32 keyAttr = keyParams->keyAttributes;
   628     if (keyAttr & CSSM_KEYATTR_SENSITIVE)
   629         keyAttr |= CSSM_KEYATTR_RETURN_REF;
   630     else
   631         keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
   632 
   633 	crtn = CSSM_GenerateKey(ccHand,
   634         keyParams->keyUsage ?: CSSM_KEYUSE_ANY,
   635 		keyAttr,
   636 		&dummyLabel,
   637 		NULL,			// ACL
   638 		ourKey);
   639 	if(crtn) {
   640 		checkcssm(crtn,@"CSSM_GenerateKey");
   641 	}
   642 errOut:
   643 	CSSM_DeleteContext(ccHand);
   644 	if(crtn == CSSM_OK) {
   645 		*passKey = ourKey;
   646 	}
   647 	else if(ourKey != NULL) {
   648 		free(ourKey);
   649 	}
   650 	return crtn;
   651 }
   652 	
   653 
   654 #endif !MYCRYPTO_USE_IPHONE_API
   655 
   656 
   657 
   658 /*
   659  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   660  
   661  Redistribution and use in source and binary forms, with or without modification, are permitted
   662  provided that the following conditions are met:
   663  
   664  * Redistributions of source code must retain the above copyright notice, this list of conditions
   665  and the following disclaimer.
   666  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   667  and the following disclaimer in the documentation and/or other materials provided with the
   668  distribution.
   669  
   670  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   671  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   672  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   673  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   674  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   675   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   676  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   677  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   678  */