Changed the X.509 version number in generated certs from 1 to 3, so that SecCertificateCreateFromData on iPhone will accept them. :-/
5 // Created by Jens Alfke on 3/31/09.
6 // Copyright 2009 Jens Alfke. All rights reserved.
9 #import "MYCrypto_Private.h"
11 #import "MYIdentity.h"
14 #if MYCRYPTO_USE_IPHONE_API
17 @interface MYKeyEnumerator : NSEnumerator
22 MYKeychainItem *_currentObject;
25 - (id) initWithQuery: (NSMutableDictionary*)query;
26 + (id) firstItemWithQuery: (NSMutableDictionary*)query;
31 @implementation MYKeychain
34 + (MYKeychain*) allKeychains
36 // iPhone only has a single keychain.
37 return [self defaultKeychain];
40 + (MYKeychain*) defaultKeychain
42 static MYKeychain *sDefaultKeychain;
44 if (!sDefaultKeychain) {
45 sDefaultKeychain = [[self alloc] init];
48 return sDefaultKeychain;
52 - (id) copyWithZone: (NSZone*)zone {
53 // It's not necessary to make copies of Keychain objects. This makes it more efficient
54 // to use instances as NSDictionary keys or store them in NSSets.
61 #pragma mark SEARCHING:
64 - (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
65 return [MYKeyEnumerator firstItemWithQuery:
66 $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic},
67 {(id)kSecAttrApplicationLabel, pubKeyDigest.asData})];
70 - (NSEnumerator*) enumeratePublicKeys {
71 NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic});
72 return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
76 - (MYPrivateKey*) privateKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
77 return [MYKeyEnumerator firstItemWithQuery:
78 $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
79 {(id)kSecAttrApplicationLabel, pubKeyDigest.asData})];
82 - (NSEnumerator*) enumeratePrivateKeys {
83 NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate});
84 return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
87 - (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
88 return [MYKeyEnumerator firstItemWithQuery:
89 $mdict({(id)kSecClass, (id)kSecClassCertificate},
90 {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})];
93 - (NSEnumerator*) enumerateCertificates {
94 NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate});
95 return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
98 - (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest {
99 return [MYKeyEnumerator firstItemWithQuery:
100 $mdict({(id)kSecClass, (id)kSecClassIdentity},
101 {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})];
104 - (NSEnumerator*) enumerateIdentities {
105 NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity});
106 return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
109 - (NSEnumerator*) enumerateSymmetricKeys {
110 NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric});
111 return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
114 - (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
115 NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
116 {(id)kSecAttrApplicationTag, alias});
117 return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
125 - (MYPublicKey*) importPublicKey: (NSData*)keyData {
126 return [[[MYPublicKey alloc] _initWithKeyData: keyData
131 - (MYCertificate*) importCertificate: (NSData*)data
134 NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassCertificate},
135 {(id)kSecValueData, data},
136 {(id)kSecReturnRef, $true} );
137 SecCertificateRef cert;
138 if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&cert), @"SecItemAdd"))
140 return [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
145 #pragma mark GENERATION:
148 - (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
149 algorithm: (CCAlgorithm)algorithm
151 return [MYSymmetricKey _generateSymmetricKeyOfSize: keySizeInBits
152 algorithm: algorithm inKeychain: self];
155 - (MYPrivateKey*) generateRSAKeyPairOfSize: (unsigned)keySize {
156 return [MYPrivateKey _generateRSAKeyPairOfSize: keySize inKeychain: self];
165 @implementation MYKeyEnumerator
167 - (id) initWithQuery: (NSMutableDictionary*)query {
170 _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass];
172 [query setObject: (id)kSecClassKey forKey: (id)kSecClass];
174 _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass];
176 CFRetain(_itemClass);
178 // Ask for all results unless caller specified fewer:
179 CFTypeRef limit = [query objectForKey: (id)kSecMatchLimit];
181 limit = kSecMatchLimitAll;
182 [query setObject: (id)limit forKey: (id)kSecMatchLimit];
185 [query setObject: $true forKey: (id)kSecReturnRef];
187 OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&_results);
188 if (err && err != errSecItemNotFound) {
189 check(err,@"SecItemCopyMatching");
193 Log(@"Enumerator results = %@", _results);//TEMP
195 if (_results && CFEqual(limit,kSecMatchLimitOne)) {
196 // If you ask for only one, it gives you the object back instead of an array:
197 CFArrayRef resultsArray = CFArrayCreate(NULL, (const void**)&_results, 1,
198 &kCFTypeArrayCallBacks);
200 _results = resultsArray;
206 + (id) firstItemWithQuery: (NSMutableDictionary*)query {
207 [query setObject: (id)kSecMatchLimitOne forKey: (id)kSecMatchLimit];
208 MYKeyEnumerator *e = [[self alloc] initWithQuery: query];
209 MYKeychainItem *item = [e.nextObject retain];
211 return [item autorelease];
216 [_currentObject release];
217 CFRelease(_itemClass);
218 if (_results) CFRelease(_results);
223 - (BOOL) _verifyPublicKeyRef: (MYKeychainItemRef)itemRef {
224 // Enumerating the keychain sometimes returns public-key refs that give not-found errors
225 // when you try to use them for anything. As a workaround, detect these early on before
226 // even creating a MYPublicKey:
227 NSDictionary *info = $dict({(id)kSecValueRef, (id)itemRef},
228 {(id)kSecReturnAttributes, $true});
229 CFDictionaryRef attrs = NULL;
230 OSStatus err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs);
231 if (attrs) CFRelease(attrs);
232 if (err == errSecItemNotFound) {
233 Log(@"MYKeyEnumerator: Ignoring bogus(?) key with ref %p", itemRef);
242 setObj(&_currentObject,nil);
243 while (_currentObject==nil && _index < CFArrayGetCount(_results)) {
244 CFTypeRef found = CFArrayGetValueAtIndex(_results, _index++);
245 if (_itemClass == kSecAttrKeyClassPrivate) {
246 _currentObject = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
247 } else if (_itemClass == kSecAttrKeyClassPublic) {
248 if ([self _verifyPublicKeyRef: found])
249 _currentObject = [[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found];
250 } else if (_itemClass == kSecAttrKeyClassSymmetric) {
251 _currentObject = [[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found];
252 } else if (_itemClass == kSecClassCertificate) {
253 _currentObject = [[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found];
254 } else if (_itemClass == kSecClassIdentity) {
255 _currentObject = [[MYIdentity alloc] initWithIdentityRef: (SecIdentityRef)found];
257 Assert(NO,@"Unknown _itemClass: %@",_itemClass);
260 return _currentObject;
266 #endif MYCRYPTO_USE_IPHONE_API
270 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
272 Redistribution and use in source and binary forms, with or without modification, are permitted
273 provided that the following conditions are met:
275 * Redistributions of source code must retain the above copyright notice, this list of conditions
276 and the following disclaimer.
277 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
278 and the following disclaimer in the documentation and/or other materials provided with the
281 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
282 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
283 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
284 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
285 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
286 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
287 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
288 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.