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