MYKey-iPhone.m
author Jens Alfke <jens@mooseyard.com>
Tue Jul 21 10:13:08 2009 -0700 (2009-07-21)
changeset 27 d0aadddb9c64
parent 24 6856e071d25a
child 28 54b373aa65ab
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 //  MYKey-iPhone.m
     3 //  MYCrypto-iPhone
     4 //
     5 //  Created by Jens Alfke on 4/4/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 
    10 #import "MYCrypto_Private.h"
    11 
    12 #if MYCRYPTO_USE_IPHONE_API
    13 
    14 #import "MYDigest.h"
    15 #import "MYErrorUtils.h"
    16 
    17 
    18 #pragma mark -
    19 @implementation MYKey
    20 
    21 
    22 - (id) initWithKeyRef: (SecKeyRef)key {
    23     return [self initWithKeychainItemRef: (SecKeychainItemRef)key];
    24 }
    25 
    26 
    27 - (id) _initWithKeyData: (NSData*)data
    28             forKeychain: (SecKeychainRef)keychain
    29 {
    30     NSMutableDictionary *info = $mdict({(id)kSecClass, (id)kSecClassKey},
    31                                         {(id)kSecAttrKeyType, (id)self.keyType},
    32                                         {(id)kSecValueData, data},
    33                                         {(id)kSecAttrIsPermanent, (keychain ?$true :$false)},
    34                                         {(id)kSecReturnPersistentRef, (keychain ?$true :$false)} );
    35     SecKeyRef key = (SecKeyRef)[MYKeychain _addItemWithInfo: info];
    36     if (!key) {
    37         [self release];
    38         return nil;
    39     }
    40     self = [self initWithKeyRef: (SecKeyRef)key];
    41     if (self) {
    42         if (!keychain)
    43             _keyData = [data copy];
    44         
    45         //TEMP For debugging:
    46         AssertEqual(self.keyData, data);
    47     }
    48     return self;
    49 }
    50 
    51 - (id) initWithKeyData: (NSData*)data {
    52     return [self _initWithKeyData: data forKeychain: nil];
    53 }
    54 
    55 - (void) dealloc
    56 {
    57     [_keyData release];
    58     [super dealloc];
    59 }
    60 
    61 
    62 /*- (NSData*) persistentRef {
    63     NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
    64                               //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
    65                                 {(id)kSecReturnPersistentRef, $true} );
    66     CFDataRef data;
    67     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
    68         return nil;
    69     if (!data)
    70         Warn(@"MYKey persistentRef couldn't get ref");
    71     return [NSMakeCollectable(data) autorelease];
    72 }*/
    73 
    74 
    75 - (SecExternalItemType) keyClass {
    76     AssertAbstractMethod();
    77 }
    78 
    79 - (SecExternalItemType) keyType {
    80     return NULL;
    81 }
    82 
    83 - (NSData*) keyData {
    84     if (_keyData)
    85         return _keyData;
    86     
    87     NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
    88                               //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
    89                                 {(id)kSecReturnData, $true} );
    90     CFDataRef data;
    91     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching")) {
    92         Log(@"SecItemCopyMatching failed; input = %@", info);
    93         return nil;
    94     } else {
    95         Assert(data!=NULL);
    96         _keyData = NSMakeCollectable(data);
    97         return _keyData;
    98     }
    99     // The format of this data is not documented. There's been some reverse-engineering:
   100     // https://devforums.apple.com/message/32089#32089
   101     // Apparently it is a DER-formatted sequence of a modulus followed by an exponent.
   102     // This can be converted to OpenSSL format by wrapping it in some additional DER goop.
   103 }
   104 
   105 - (MYSHA1Digest*) _keyDigest {
   106     return [self.keyData my_SHA1Digest];
   107 }
   108 
   109 - (SecKeyRef) keyRef {
   110     return (SecKeyRef) self.keychainItemRef;
   111 }
   112 
   113 
   114 - (id) _attribute: (CFTypeRef)attribute {
   115     NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef},
   116             {(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
   117                                {(id)kSecReturnAttributes, $true});
   118     CFDictionaryRef attrs = NULL;
   119     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
   120         return nil;
   121     CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
   122     id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
   123     CFRelease(attrs);
   124     return value;
   125 }
   126 
   127 - (BOOL) setValue: (NSString*)value ofAttribute: (SecKeychainAttrType)attribute {
   128     if (!value)
   129         value = (id)[NSNull null];
   130     NSDictionary *query = $dict( {(id)kSecValueRef, (id)self.keyRef} );
   131     NSDictionary *attrs = $dict( {(id)attribute, value} );
   132     return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
   133 }
   134 
   135 
   136 - (NSString*) name {
   137     return [self _attribute: kSecAttrLabel];
   138 }
   139 
   140 - (void) setName: (NSString*)name {
   141     [self setValue: name ofAttribute: kSecAttrLabel];
   142 }
   143 
   144 - (NSString*) alias {
   145     return [self _attribute: kSecAttrApplicationTag];
   146 }
   147 
   148 - (void) setAlias: (NSString*)alias {
   149     [self setValue: alias ofAttribute: kSecAttrApplicationTag];
   150 }
   151 
   152 
   153 
   154 
   155 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
   156 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
   157     CAssert(data);
   158     size_t dataLength = data.length;
   159     SecKeyRef key = self.keyRef;
   160     size_t outputLength = MAX(dataLength, SecKeyGetBlockSize(key));
   161     void *outputBuf = malloc(outputLength);
   162     if (!outputBuf) return nil;
   163     OSStatus err;
   164     if (operation)
   165         err = SecKeyEncrypt(key, kSecPaddingNone,//PKCS1, 
   166                             data.bytes, dataLength,
   167                             outputBuf, &outputLength);
   168     else
   169         err = SecKeyDecrypt(key, kSecPaddingNone,//PKCS1, 
   170                             data.bytes, dataLength,
   171                             outputBuf, &outputLength);
   172     if (err) {
   173         free(outputBuf);
   174         Warn(@"%scrypting failed (%i)", (operation ?"En" :"De"), err);
   175         // Note: One of the errors I've seen is -9809, which is errSSLCrypto (SecureTransport.h)
   176         return nil;
   177     } else
   178         return [NSData dataWithBytesNoCopy: outputBuf length: outputLength freeWhenDone: YES];
   179 }
   180 
   181 
   182 @end
   183 
   184 
   185 #endif MYCRYPTO_USE_IPHONE_API
   186 
   187 
   188 
   189 /*
   190  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   191  
   192  Redistribution and use in source and binary forms, with or without modification, are permitted
   193  provided that the following conditions are met:
   194  
   195  * Redistributions of source code must retain the above copyright notice, this list of conditions
   196  and the following disclaimer.
   197  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   198  and the following disclaimer in the documentation and/or other materials provided with the
   199  distribution.
   200  
   201  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   202  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   203  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   204  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   205  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   206   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   207  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   208  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   209  */