MYKey.m
author snej@snej-mbp.mtv.corp.google.com
Wed Apr 08 16:30:52 2009 -0700 (2009-04-08)
changeset 3 1dfe820d7ebe
parent 2 8982b8fada63
child 8 4c0eafa7b233
permissions -rw-r--r--
* Replaced MYKeyPair with MYPrivateKey.
* Changed config files.
     1 //
     2 //  MYKey.m
     3 //  MYCrypto
     4 //
     5 //  Created by Jens Alfke on 3/21/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYKey.h"
    10 #import "MYCrypto_Private.h"
    11 #import "MYDigest.h"
    12 #import "MYErrorUtils.h"
    13 
    14 #if !MYCRYPTO_USE_IPHONE_API
    15 
    16 
    17 #pragma mark -
    18 @implementation MYKey
    19 
    20 
    21 - (id) initWithKeyRef: (SecKeyRef)key {
    22     return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
    23 }
    24 
    25 - (id) _initWithKeyData: (NSData*)data
    26             forKeychain: (SecKeychainRef)keychain {
    27     SecKeyImportExportParameters params = {};
    28     SecKeyRef key = importKey(data, self.keyType, keychain, &params);
    29     if (!key) {
    30         [self release];
    31         return nil;
    32     }
    33     self = [self initWithKeyRef: key];
    34     CFRelease(key);
    35     return self;
    36 }
    37 
    38 - (id) initWithKeyData: (NSData*)data {
    39     return [self _initWithKeyData: data forKeychain: nil];
    40 }
    41 
    42 
    43 - (SecExternalItemType) keyType {
    44     AssertAbstractMethod();
    45 }
    46 
    47 
    48 - (SecKeyRef) keyRef {
    49     return (SecKeyRef) self.keychainItemRef;
    50 }
    51 
    52 - (const CSSM_KEY*) cssmKey {
    53     const CSSM_KEY *cssmKey = NULL;
    54     Assert(check(SecKeyGetCSSMKey(self.keyRef, &cssmKey), @"SecKeyGetCSSMKey"), 
    55            @"Failed to get CSSM_KEY");
    56     return cssmKey;
    57 }
    58 
    59 - (const CSSM_CSP_HANDLE) cssmCSPHandle {
    60     CSSM_CSP_HANDLE cspHandle = 0;
    61     Assert(check(SecKeyGetCSPHandle(self.keyRef, &cspHandle), @"SecKeyGetCSPHandle"),
    62            @"Failed to get CSSM_CSP_HANDLE");
    63     return cspHandle;
    64 }
    65 
    66 - (const CSSM_ACCESS_CREDENTIALS*) cssmCredentialsForOperation: (CSSM_ACL_AUTHORIZATION_TAG)operation
    67                                                           type: (SecCredentialType)type
    68                                                          error: (NSError**)outError
    69 {
    70     const CSSM_ACCESS_CREDENTIALS *credentials = NULL;
    71     OSStatus err = SecKeyGetCredentials(self.keyRef,
    72                                         operation,
    73                                         type,
    74                                         &credentials);
    75     if (!MYReturnError(outError, err,NSOSStatusErrorDomain, @"Couldn't get credentials for key"))
    76         return NULL;
    77     return credentials;
    78 }
    79 
    80 - (NSData*) exportKeyInFormat: (SecExternalFormat)format withPEM: (BOOL)withPEM {
    81     CFDataRef data = NULL;
    82     if (check(SecKeychainItemExport(self.keyRef, format, (withPEM ?kSecItemPemArmour :0), NULL, &data),
    83               @"SecKeychainItemExport"))
    84         return [(id)CFMakeCollectable(data) autorelease];
    85     else
    86         return nil;
    87 }
    88 
    89 - (NSData*) keyData {
    90     return [self exportKeyInFormat: kSecFormatRawKey withPEM: NO];
    91 }
    92 
    93 - (NSString*) name {
    94     return [self stringValueOfAttribute: kSecKeyPrintName];
    95 }
    96 
    97 - (void) setName: (NSString*)name {
    98     [self setValue: name ofAttribute: kSecKeyPrintName];
    99 }
   100 
   101 - (NSString*) comment {
   102     return [self stringValueOfAttribute: kSecKeyApplicationTag];
   103 }
   104 
   105 - (void) setComment: (NSString*)comment {
   106     [self setValue: comment ofAttribute: kSecKeyApplicationTag];
   107 }
   108 
   109 - (NSString*) alias {
   110     return [self stringValueOfAttribute: kSecKeyAlias];
   111 }
   112 
   113 - (void) setAlias: (NSString*)alias {
   114     [self setValue: alias ofAttribute: kSecKeyAlias];
   115 }
   116 
   117 
   118 #pragma mark -
   119 #pragma mark UTILITY FUNCTIONS:
   120 
   121 
   122 SecKeyRef importKey(NSData *data, 
   123                     SecExternalItemType type,
   124                     SecKeychainRef keychain,
   125                     SecKeyImportExportParameters *params) {
   126     SecExternalFormat inputFormat = (type==kSecItemTypeSessionKey) ?kSecFormatRawKey :kSecFormatOpenSSL;
   127     CFArrayRef items = NULL;
   128     
   129     params->version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
   130     params->flags |= kSecKeyImportOnlyOne;
   131     params->keyAttributes |= CSSM_KEYATTR_EXTRACTABLE;
   132     if (keychain) {
   133         params->keyAttributes |= CSSM_KEYATTR_PERMANENT;
   134         if (type==kSecItemTypeSessionKey)
   135             params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_DECRYPT;
   136         else if (type==kSecItemTypePublicKey)
   137             params->keyUsage = CSSM_KEYUSE_ENCRYPT | CSSM_KEYUSE_VERIFY;
   138         else if (type==kSecItemTypePrivateKey)
   139             params->keyUsage = CSSM_KEYUSE_DECRYPT | CSSM_KEYUSE_SIGN;
   140     }
   141     if (!check(SecKeychainItemImport((CFDataRef)data, NULL, &inputFormat, &type,
   142                                      0, params, keychain, &items),
   143                @"SecKeychainItemImport"))
   144         return nil;
   145     if (!items || CFArrayGetCount(items) != 1)
   146         return nil;
   147     SecKeyRef key = (SecKeyRef)CFRetain(CFArrayGetValueAtIndex(items,0));
   148     CFRelease(items);
   149     return key; // caller must CFRelease
   150 }
   151 
   152 
   153 - (MYSHA1Digest*) _keyDigest {
   154     MYSHA1Digest *digest = nil;
   155     CSSM_DATA *keyDigest = NULL;
   156     CSSM_CC_HANDLE context = [self _createPassThroughContext];
   157     if (context) {
   158         if (checkcssm(CSSM_CSP_PassThrough(context, CSSM_APPLECSP_KEYDIGEST, NULL, (void**)&keyDigest),
   159                       @"CSSM_CSP_PassThrough")) {
   160             if (keyDigest && keyDigest->Data) {
   161                 digest = [[[MYSHA1Digest alloc] initWithRawDigest: keyDigest->Data
   162                                                            length: keyDigest->Length] autorelease];
   163             }
   164         } else {
   165             SecKeyRef keyRef = self.keyRef;
   166             // Note - CSSM_CSP_PassThrough fails on a couple of private keys I've seen; it seems to
   167             // be ones that are either expired or don't have a matching public key at all (?)
   168             Warn(@"Failed to get digest of SecKeyRef %p (name='%@' appTag='%@')", 
   169                  keyRef,
   170                  self.name,
   171                  self.comment);
   172             NSData *digestData = [[self class] _getAttribute: kSecKeyLabel 
   173                                                       ofItem: (SecKeychainItemRef)keyRef];
   174             if (digestData) {
   175                 digest = (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: digestData];
   176                 if (!digest)
   177                     Warn(@"Digest property of key %p was invalid SHA-1: %@", keyRef,digestData);
   178             }
   179         }
   180         CSSM_DeleteContext(context);
   181     }
   182     return digest;
   183 }
   184 
   185 
   186 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
   187 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
   188     CAssert(data);
   189     const CSSM_ACCESS_CREDENTIALS *credentials;
   190     credentials = [self cssmCredentialsForOperation: (operation ?CSSM_ACL_AUTHORIZATION_ENCRYPT 
   191                                                                 :CSSM_ACL_AUTHORIZATION_DECRYPT) 
   192                                                type: kSecCredentialTypeDefault
   193                                               error: nil];
   194     if (!credentials)
   195         return nil;
   196     
   197     CSSM_CC_HANDLE ccHandle;
   198     if (!checkcssm(CSSM_CSP_CreateAsymmetricContext(self.cssmCSPHandle,
   199                                                     CSSM_ALGID_RSA,
   200                                                     credentials,
   201                                                     self.cssmKey,
   202                                                     CSSM_PADDING_PKCS1,
   203                                                     &ccHandle),
   204                    @"CSSM_CSP_CreateAsymmetricContext"))
   205         return nil;
   206     
   207     CSSM_DATA original = {data.length, (void*)data.bytes};
   208     CSSM_DATA result = {};
   209     size_t outputLength;
   210     BOOL ok;
   211     if (operation)
   212         ok = checkcssm(CSSM_EncryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
   213                        @"CSSM_EncryptData");
   214     else
   215         ok = checkcssm(CSSM_DecryptData(ccHandle, &original, 1, &result, 1, &outputLength, &result),
   216                        @"CSSM_DecryptData");
   217     CSSM_DeleteContext(ccHandle);
   218     return ok ?[NSData dataWithBytesNoCopy: result.Data length: outputLength freeWhenDone: YES] :nil;
   219 }
   220 
   221 
   222 - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm {
   223     const CSSM_ACCESS_CREDENTIALS *credentials;
   224     credentials = [self cssmCredentialsForOperation: CSSM_ACL_AUTHORIZATION_SIGN 
   225                                                type: kSecCredentialTypeDefault
   226                                               error: nil];
   227     if (credentials) {
   228         CSSM_CC_HANDLE ccHandle = 0;
   229         if (checkcssm(CSSM_CSP_CreateSignatureContext(self.cssmCSPHandle, 
   230                                                       algorithm, 
   231                                                       credentials,
   232                                                       self.cssmKey,
   233                                                       &ccHandle),
   234                              @"CSSM_CSP_CreateSignatureContext") )
   235             return ccHandle;
   236     }
   237     return 0;
   238 }
   239 
   240 - (CSSM_CC_HANDLE) _createPassThroughContext
   241 {
   242     CSSM_CC_HANDLE ccHandle = 0;
   243     if (checkcssm(CSSM_CSP_CreatePassThroughContext(self.cssmCSPHandle, self.cssmKey, &ccHandle), 
   244                           @"CSSM_CSP_CreatePassThroughContext") )
   245         return ccHandle;
   246     else
   247         return 0;
   248 }
   249 
   250 
   251 @end
   252 
   253 #endif MYCRYPTO_USE_IPHONE_API
   254 
   255 
   256 
   257 /*
   258  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   259  
   260  Redistribution and use in source and binary forms, with or without modification, are permitted
   261  provided that the following conditions are met:
   262  
   263  * Redistributions of source code must retain the above copyright notice, this list of conditions
   264  and the following disclaimer.
   265  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   266  and the following disclaimer in the documentation and/or other materials provided with the
   267  distribution.
   268  
   269  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   270  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   271  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   272  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   273  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   274   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   275  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   276  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   277  */