MYKey-iPhone.m
author Jens Alfke <jens@mooseyard.com>
Thu Jun 04 18:36:30 2009 -0700 (2009-06-04)
changeset 19 f6c91b9da05b
parent 3 1dfe820d7ebe
child 23 39fec79de6e8
permissions -rw-r--r--
Whew! MYParsedCertificate can now generate certs from scratch. Also added improvements and fixes to the BER/DER codecs.
     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 [super initWithKeychainItemRef: (SecKeychainItemRef)key];
    24 }
    25 
    26 
    27 - (id) _initWithKeyData: (NSData*)data
    28             forKeychain: (SecKeychainRef)keychain
    29 {
    30     NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
    31                                 {(id)kSecAttrKeyClass, (id)self.keyType},
    32                                 {(id)kSecValueData, data},
    33                                 {(id)kSecAttrIsPermanent, $object(keychain!=nil)},
    34                                 {(id)kSecReturnRef, $true} );
    35     SecKeyRef key;
    36     if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&key), @"SecItemAdd"))
    37         return nil;
    38     else
    39         return [self initWithKeyRef: (SecKeyRef)key];
    40 }
    41 
    42 - (id) initWithKeyData: (NSData*)data {
    43     return [self _initWithKeyData: data forKeychain: nil];
    44 }
    45 
    46 
    47 - (SecExternalItemType) keyType {
    48     AssertAbstractMethod();
    49 }
    50 
    51 
    52 - (NSData*) keyData {
    53     NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
    54                                 {(id)kSecAttrKeyClass, (id)self.keyType},
    55                                 {(id)kSecMatchItemList, $array((id)self.keyRef)},
    56                                 {(id)kSecReturnData, $true} );
    57     CFDataRef data;
    58     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
    59         return nil;
    60     else
    61         return [(id)CFMakeCollectable(data) autorelease];
    62     
    63     // The format of this data is not documented. There's been some reverse-engineering:
    64     // https://devforums.apple.com/message/32089#32089
    65     // Apparently it is a DER-formatted sequence of a modulus followed by an exponent.
    66     // This can be converted to OpenSSL format by wrapping it in some additional DER goop.
    67 }
    68 
    69 
    70 - (SecKeyRef) keyRef {
    71     return (SecKeyRef) self.keychainItemRef;
    72 }
    73 
    74 
    75 - (id) _attribute: (CFTypeRef)attribute {
    76     NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
    77                                 {(id)kSecAttrKeyClass, (id)self.keyType},
    78                                 {(id)kSecMatchItemList, $array((id)self.keyRef)},
    79                                 {(id)kSecReturnAttributes, $true} );
    80     CFDictionaryRef attrs = NULL;
    81     if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
    82         return nil;
    83     CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
    84     id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
    85     CFRelease(attrs);
    86     return value;
    87 }
    88 
    89 - (BOOL) setValue: (NSString*)value ofAttribute: (SecKeychainAttrType)attribute {
    90     if (!value)
    91         value = (id)[NSNull null];
    92     NSDictionary *query = $dict( {(id)kSecClass, (id)kSecClassKey},
    93                                 {(id)kSecAttrKeyClass, (id)self.keyType},
    94                                 {(id)kSecMatchItemList, self._itemList} );
    95     NSDictionary *attrs = $dict( {(id)attribute, value} );
    96     return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
    97 }
    98 
    99 
   100 - (NSString*) name {
   101     return [self _attribute: kSecAttrLabel];
   102 }
   103 
   104 - (void) setName: (NSString*)name {
   105     [self setValue: name ofAttribute: kSecAttrLabel];
   106 }
   107 
   108 - (NSString*) alias {
   109     return [self _attribute: kSecAttrApplicationTag];
   110 }
   111 
   112 - (void) setAlias: (NSString*)alias {
   113     [self setValue: alias ofAttribute: kSecAttrApplicationTag];
   114 }
   115 
   116 
   117 
   118 
   119 /** Asymmetric encryption/decryption; used by MYPublicKey and MYPrivateKey. */
   120 - (NSData*) _crypt: (NSData*)data operation: (BOOL)operation {
   121     CAssert(data);
   122     size_t dataLength = data.length;
   123     SecKeyRef key = self.keyRef;
   124     size_t outputLength = MAX(dataLength, SecKeyGetBlockSize(key));
   125     void *outputBuf = malloc(outputLength);
   126     if (!outputBuf) return nil;
   127     OSStatus err;
   128     if (operation)
   129         err = SecKeyEncrypt(key, kSecPaddingNone,//PKCS1, 
   130                             data.bytes, dataLength,
   131                             outputBuf, &outputLength);
   132     else
   133         err = SecKeyDecrypt(key, kSecPaddingNone,//PKCS1, 
   134                             data.bytes, dataLength,
   135                             outputBuf, &outputLength);
   136     if (err) {
   137         free(outputBuf);
   138         Warn(@"%scrypting failed (%i)", (operation ?"En" :"De"), err);
   139         // Note: One of the errors I've seen is -9809, which is errSSLCrypto (SecureTransport.h)
   140         return nil;
   141     } else
   142         return [NSData dataWithBytesNoCopy: outputBuf length: outputLength freeWhenDone: YES];
   143 }
   144 
   145 
   146 @end
   147 
   148 
   149 #endif MYCRYPTO_USE_IPHONE_API
   150 
   151 
   152 
   153 /*
   154  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   155  
   156  Redistribution and use in source and binary forms, with or without modification, are permitted
   157  provided that the following conditions are met:
   158  
   159  * Redistributions of source code must retain the above copyright notice, this list of conditions
   160  and the following disclaimer.
   161  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   162  and the following disclaimer in the documentation and/or other materials provided with the
   163  distribution.
   164  
   165  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   166  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   167  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   168  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   169  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   170   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   171  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   172  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   173  */