MYKeychain-iPhone.m
author snej@snej.local
Sun Apr 19 21:19:35 2009 -0700 (2009-04-19)
changeset 14 3af1d1c0ceb5
parent 3 1dfe820d7ebe
child 21 2c300b15b381
permissions -rw-r--r--
* Some cleanup. Got the test cases to pass again.
* Added some missing copyright notices.
     1 //
     2 //  MYKeychain-iPhone.m
     3 //  MYCrypto-iPhone
     4 //
     5 //  Created by Jens Alfke on 3/31/09.
     6 //  Copyright 2009 Jens Alfke. All rights reserved.
     7 //
     8 
     9 #import "MYCrypto_Private.h"
    10 #import "MYDigest.h"
    11 #import "MYIdentity.h"
    12 
    13 
    14 #if MYCRYPTO_USE_IPHONE_API
    15 
    16 
    17 @interface MYKeyEnumerator : NSEnumerator
    18 {
    19     CFArrayRef _results;
    20     CFTypeRef _itemClass;
    21     CFIndex _index;
    22 }
    23 
    24 - (id) initWithQuery: (NSMutableDictionary*)query;
    25 + (id) firstItemWithQuery: (NSMutableDictionary*)query;
    26 @end
    27 
    28 
    29 
    30 @implementation MYKeychain
    31 
    32 
    33 + (MYKeychain*) allKeychains
    34 {
    35     // iPhone only has a single keychain.
    36     return [self defaultKeychain];
    37 }
    38 
    39 + (MYKeychain*) defaultKeychain
    40 {
    41     static MYKeychain *sDefaultKeychain;
    42     @synchronized(self) {
    43         if (!sDefaultKeychain) {
    44             sDefaultKeychain = [[self alloc] init];
    45         }
    46     }
    47     return sDefaultKeychain;
    48 }
    49 
    50 
    51 - (id) copyWithZone: (NSZone*)zone {
    52     // It's not necessary to make copies of Keychain objects. This makes it more efficient
    53     // to use instances as NSDictionary keys or store them in NSSets.
    54     return [self retain];
    55 }
    56 
    57 
    58 
    59 #pragma mark -
    60 #pragma mark SEARCHING:
    61 
    62 
    63 - (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
    64     return [MYKeyEnumerator firstItemWithQuery:
    65                 $mdict({(id)kSecClass, (id)kSecClassKey},
    66                       {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
    67                       {(id)kSecReturnRef, $true})];
    68 }   
    69 
    70 - (NSEnumerator*) enumeratePublicKeys {
    71     NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
    72                                 {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic},
    73                                 {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
    74                                 {(id)kSecReturnRef, $true});
    75     return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
    76 }
    77 
    78 
    79 - (MYPrivateKey*) privateKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
    80     return [MYKeyEnumerator firstItemWithQuery:
    81                 $mdict({(id)kSecClass, (id)kSecClassKey},
    82                       {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
    83                       {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
    84                       {(id)kSecReturnRef, $true})];
    85 }
    86 
    87 - (NSEnumerator*) enumeratePrivateKeys {
    88     NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
    89                                 {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
    90                                 {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
    91                                 {(id)kSecReturnRef, $true});
    92     return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
    93 }
    94 
    95 - (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
    96     return [MYKeyEnumerator firstItemWithQuery:
    97                 $mdict({(id)kSecClass, (id)kSecClassCertificate},
    98                       {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
    99                       {(id)kSecReturnRef, $true})];
   100 }
   101 
   102 - (NSEnumerator*) enumerateCertificates {
   103     NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate},
   104                                 {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   105                                 {(id)kSecReturnRef, $true});
   106     return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   107 }
   108 
   109 - (NSEnumerator*) enumerateIdentities {
   110     NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity},
   111                                         {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   112                                         {(id)kSecReturnRef, $true});
   113     return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   114 }
   115 
   116 - (NSEnumerator*) enumerateSymmetricKeys {
   117     NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   118                                 {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   119                                 {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   120                                 {(id)kSecReturnRef, $true});
   121     return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   122 }
   123 
   124 - (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
   125     NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   126                                 {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   127                                 {(id)kSecAttrApplicationTag, alias},
   128                                 {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   129                                 {(id)kSecReturnRef, $true});
   130     return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   131 }
   132 
   133 
   134 #pragma mark -
   135 #pragma mark IMPORT:
   136 
   137 
   138 - (MYPublicKey*) importPublicKey: (NSData*)keyData {
   139     return [[[MYPublicKey alloc] _initWithKeyData: keyData 
   140                                       forKeychain: self]
   141             autorelease];
   142 }
   143 
   144 - (MYCertificate*) importCertificate: (NSData*)data
   145 {
   146     Assert(data);
   147     NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassCertificate},
   148                                 {(id)kSecValueData, data},
   149                                 {(id)kSecReturnRef, $true} );
   150     SecCertificateRef cert;
   151     if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&cert), @"SecItemAdd"))
   152         return nil;
   153     return [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
   154 }
   155 
   156 
   157 #pragma mark -
   158 #pragma mark GENERATION:
   159 
   160 
   161 - (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
   162                                      algorithm: (CCAlgorithm)algorithm
   163 {
   164     return [MYSymmetricKey _generateSymmetricKeyOfSize: keySizeInBits
   165                                              algorithm: algorithm inKeychain: self];
   166 }
   167 
   168 - (MYPrivateKey*) generateRSAKeyPairOfSize: (unsigned)keySize {
   169     return [MYPrivateKey _generateRSAKeyPairOfSize: keySize inKeychain: self];
   170 }
   171 
   172 
   173 @end
   174 
   175 
   176 
   177 #pragma mark -
   178 @implementation MYKeyEnumerator
   179 
   180 - (id) initWithQuery: (NSMutableDictionary*)query {
   181     self = [super init];
   182     if (self) {
   183         if (![query objectForKey: (id)kSecMatchLimit])
   184             [query setObject: (id)kSecMatchLimitAll forKey: (id)kSecMatchLimit];
   185         OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&_results);
   186         if (err && err != errSecItemNotFound) {
   187             check(err,@"SecItemCopyMatching");
   188             [self release];
   189             return nil;
   190         }
   191         if (_results) CFRetain(_results);
   192         _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass];
   193         if (_itemClass == kSecClassKey)
   194             _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass];
   195         if (_itemClass) CFRetain(_itemClass);
   196     }
   197     return self;
   198 }
   199 
   200 + (id) firstItemWithQuery: (NSMutableDictionary*)query {
   201     MYKeyEnumerator *e = [[self alloc] initWithQuery: query];
   202     MYKeychainItem *item = e.nextObject;
   203     [e release];
   204     return item;
   205 }    
   206 
   207 - (void) dealloc
   208 {
   209     if (_itemClass) CFRelease(_itemClass);
   210     if (_results) CFRelease(_results);
   211     [super dealloc];
   212 }
   213 
   214 
   215 - (id) nextObject {
   216     if (!_results)
   217         return nil;
   218     MYKeychainItem *next = nil;
   219     while (next==nil && _index < CFArrayGetCount(_results)) {
   220         CFTypeRef found = CFArrayGetValueAtIndex(_results, _index++); 
   221         if (_itemClass == kSecAttrKeyClassPrivate) {
   222             next = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
   223         } else if (_itemClass == kSecAttrKeyClassPublic) {
   224             next = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
   225         } else if (_itemClass == kSecAttrKeyClassSymmetric) {
   226             next = [[[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
   227         } else if (_itemClass == kSecClassCertificate) {
   228             next = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
   229         } else if (_itemClass == kSecClassIdentity) {
   230             next = [[[MYIdentity alloc] initWithIdentityRef: (SecIdentityRef)found] autorelease];
   231         }
   232         CFRelease(found);
   233     }
   234     return next;
   235 }
   236 
   237 
   238 @end
   239 
   240 #endif MYCRYPTO_USE_IPHONE_API
   241 
   242 
   243 /*
   244  Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   245  
   246  Redistribution and use in source and binary forms, with or without modification, are permitted
   247  provided that the following conditions are met:
   248  
   249  * Redistributions of source code must retain the above copyright notice, this list of conditions
   250  and the following disclaimer.
   251  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   252  and the following disclaimer in the documentation and/or other materials provided with the
   253  distribution.
   254  
   255  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   256  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   257  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   258  BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   259  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   260   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   261  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   262  THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   263  */