MYKeychain.m
author Jens Alfke <jens@mooseyard.com>
Tue Jul 21 10:13:08 2009 -0700 (2009-07-21)
changeset 27 d0aadddb9c64
parent 16 c409dbc4f068
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.)
snej@0
     1
//
snej@0
     2
//  MYKeychain.m
snej@0
     3
//  MYCrypto
snej@0
     4
//
snej@0
     5
//  Created by Jens Alfke on 3/23/09.
snej@0
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
snej@0
     7
//
snej@0
     8
snej@0
     9
#import "MYKeychain.h"
snej@0
    10
#import "MYCrypto_Private.h"
snej@0
    11
#import "MYDigest.h"
snej@4
    12
#import "MYIdentity.h"
snej@4
    13
snej@0
    14
snej@2
    15
#if !MYCRYPTO_USE_IPHONE_API
snej@0
    16
snej@0
    17
snej@0
    18
@interface MYKeyEnumerator : NSEnumerator
snej@0
    19
{
snej@4
    20
    @private
snej@0
    21
    MYKeychain *_keychain;
snej@0
    22
    SecKeychainSearchRef _search;
snej@0
    23
    SecItemClass _itemClass;
snej@0
    24
}
snej@0
    25
snej@0
    26
- (id) initWithKeychain: (MYKeychain*)keychain
snej@0
    27
              itemClass: (SecItemClass)itemClass
snej@0
    28
             attributes: (SecKeychainAttribute[])attributes 
snej@0
    29
                  count: (unsigned)count;
snej@0
    30
@end
snej@0
    31
snej@0
    32
snej@4
    33
@interface MYIdentityEnumerator : NSEnumerator
snej@4
    34
{
snej@4
    35
    @private
snej@4
    36
    SecIdentitySearchRef _searchRef;
snej@4
    37
}
snej@4
    38
jens@26
    39
- (id) initWithKeychain: (MYKeychain*)keychain keyUsage: (CSSM_KEYUSE)keyUsage;
snej@4
    40
@end
snej@4
    41
snej@4
    42
snej@4
    43
snej@0
    44
snej@0
    45
@implementation MYKeychain
snej@0
    46
snej@0
    47
snej@0
    48
- (id) initWithKeychainRef: (SecKeychainRef)keychainRef
snej@0
    49
{
snej@0
    50
    self = [super init];
snej@0
    51
    if (self != nil) {
snej@0
    52
        if (keychainRef) {
snej@0
    53
            CFRetain(keychainRef);
snej@0
    54
            _keychain = keychainRef;
snej@0
    55
        }
snej@0
    56
    }
snej@0
    57
    return self;
snej@0
    58
}
snej@0
    59
snej@0
    60
+ (MYKeychain*) _readableKeychainWithRef: (SecKeychainRef)keychainRef fromPath: (NSString*)path {
snej@0
    61
    if (!keychainRef)
snej@0
    62
        return nil;
snej@0
    63
    SecKeychainStatus status;
snej@0
    64
    BOOL ok = check(SecKeychainGetStatus(keychainRef, &status), @"SecKeychainGetStatus");
snej@0
    65
    if (ok && !(status & kSecReadPermStatus)) {
snej@0
    66
        Warn(@"Can't open keychain at %@ : not readable (status=%i)", path,status);
snej@0
    67
        ok = NO;
snej@0
    68
    }
snej@0
    69
    MYKeychain *keychain = nil;
snej@0
    70
    if (ok)
snej@0
    71
        keychain = [[[self alloc] initWithKeychainRef: keychainRef] autorelease];
snej@0
    72
    CFRelease(keychainRef);
snej@0
    73
    return keychain;
snej@0
    74
}
snej@0
    75
snej@0
    76
+ (MYKeychain*) openKeychainAtPath: (NSString*)path
snej@0
    77
{
snej@0
    78
    Assert(path);
snej@0
    79
    SecKeychainRef keychainRef = NULL;
snej@0
    80
    if (!check(SecKeychainOpen(path.fileSystemRepresentation, &keychainRef), @"SecKeychainOpen"))
snej@0
    81
        return nil;
snej@0
    82
    return [self _readableKeychainWithRef: keychainRef fromPath: path];
snej@0
    83
}
snej@0
    84
snej@0
    85
+ (MYKeychain*) createKeychainAtPath: (NSString*)path
snej@0
    86
                        withPassword: (NSString*)password
snej@0
    87
{
snej@0
    88
    Assert(path);
snej@0
    89
    const char *passwordStr = [password UTF8String];
snej@0
    90
    SecKeychainRef keychainRef = NULL;
snej@0
    91
    if (!check(SecKeychainCreate(path.fileSystemRepresentation,
snej@0
    92
                                 passwordStr ?strlen(passwordStr) :0,
snej@0
    93
                                 passwordStr, 
snej@0
    94
                                 (password==nil), 
snej@0
    95
                                 NULL, 
snej@0
    96
                                 &keychainRef),
snej@0
    97
               @"SecKeychainCreate"))
snej@0
    98
        return nil;
snej@0
    99
    return [self _readableKeychainWithRef: keychainRef fromPath: path];
snej@0
   100
}
snej@0
   101
snej@0
   102
- (BOOL) deleteKeychainFile {
snej@0
   103
    Assert(_keychain);
snej@0
   104
    return check(SecKeychainDelete(_keychain), @"SecKeychainDelete");
snej@0
   105
}
snej@0
   106
snej@0
   107
snej@0
   108
- (void) dealloc
snej@0
   109
{
snej@0
   110
    if (_keychain) CFRelease(_keychain);
snej@0
   111
    [super dealloc];
snej@0
   112
}
snej@0
   113
snej@2
   114
- (void) finalize
snej@2
   115
{
snej@2
   116
    if (_keychain) CFRelease(_keychain);
snej@2
   117
    [super finalize];
snej@2
   118
}
snej@2
   119
snej@0
   120
snej@0
   121
+ (MYKeychain*) allKeychains
snej@0
   122
{
snej@0
   123
    static MYKeychain *sAllKeychains;
snej@0
   124
    @synchronized(self) {
snej@0
   125
        if (!sAllKeychains)
snej@0
   126
            sAllKeychains = [[self alloc] initWithKeychainRef: nil];
snej@0
   127
    }
snej@0
   128
    return sAllKeychains;
snej@0
   129
}
snej@0
   130
snej@0
   131
snej@0
   132
+ (MYKeychain*) defaultKeychain
snej@0
   133
{
snej@0
   134
    static MYKeychain *sDefaultKeychain;
snej@0
   135
    @synchronized(self) {
snej@0
   136
        if (!sDefaultKeychain) {
snej@0
   137
            SecKeychainRef kc = NULL;
snej@0
   138
            OSStatus err = SecKeychainCopyDomainDefault(kSecPreferencesDomainUser,&kc);
snej@0
   139
#if TARGET_OS_IPHONE
snej@0
   140
            // In the simulator, an app is run in a sandbox that has no keychain by default.
snej@0
   141
            // As a convenience, create one if necessary:
snej@0
   142
            if (err == errSecNoDefaultKeychain) {
snej@0
   143
                Log(@"No default keychain in simulator; creating one...");
snej@0
   144
                NSString *path = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
snej@0
   145
                                                                      NSUserDomainMask, YES) objectAtIndex: 0];
snej@0
   146
                path = [path stringByAppendingPathComponent: @"MYCrypto.keychain"];
snej@0
   147
                sDefaultKeychain = [[self createKeychainAtPath: path withPassword: nil] retain];
snej@0
   148
                Assert(sDefaultKeychain, @"Couldn't create default keychain");
snej@0
   149
                SecKeychainSetDomainDefault(kSecPreferencesDomainUser, sDefaultKeychain.keychainRef);
snej@0
   150
                Log(@"...created %@", sDefaultKeychain);
snej@0
   151
                return sDefaultKeychain;
snej@0
   152
            }
snej@0
   153
#endif
snej@0
   154
            if (!check(err, @"SecKeychainCopyDefault"))
snej@0
   155
                kc = NULL;
snej@0
   156
snej@0
   157
            Assert(kc, @"No default keychain");
snej@0
   158
            sDefaultKeychain = [[self alloc] initWithKeychainRef: kc];
snej@0
   159
            CFRelease(kc);
snej@0
   160
        }
snej@0
   161
    }
snej@0
   162
    return sDefaultKeychain;
snej@0
   163
}
snej@0
   164
snej@0
   165
snej@0
   166
- (id) copyWithZone: (NSZone*)zone {
snej@0
   167
    // It's not necessary to make copies of Keychain objects. This makes it more efficient
snej@0
   168
    // to use instances as NSDictionary keys or store them in NSSets.
snej@0
   169
    return [self retain];
snej@0
   170
}
snej@0
   171
snej@0
   172
- (BOOL) isEqual: (id)obj {
snej@0
   173
    return (obj == self) || 
snej@0
   174
            ([obj isKindOfClass: [MYKeychain class]] && CFEqual(_keychain, [obj keychainRef]));
snej@0
   175
}
snej@0
   176
snej@0
   177
snej@0
   178
- (SecKeychainRef) keychainRef {
snej@0
   179
    return _keychain;
snej@0
   180
}
snej@0
   181
snej@0
   182
snej@0
   183
- (SecKeychainRef) keychainRefOrDefault {
snej@0
   184
    if (_keychain)
snej@0
   185
        return _keychain;
snej@0
   186
    else
snej@0
   187
        return [[[self class] defaultKeychain] keychainRef];
snej@0
   188
}
snej@0
   189
    
snej@0
   190
    
snej@0
   191
- (NSString*) path {
snej@0
   192
    if (!_keychain)
snej@0
   193
        return nil;
snej@0
   194
    char pathBuf[PATH_MAX];
snej@0
   195
    UInt32 pathLen = sizeof(pathBuf);
snej@0
   196
    if (!check(SecKeychainGetPath(_keychain, &pathLen, pathBuf), @"SecKeychainGetPath"))
snej@0
   197
        return nil;
snej@0
   198
    return [[NSFileManager defaultManager] stringWithFileSystemRepresentation: pathBuf length: pathLen];
snej@0
   199
}
snej@0
   200
snej@0
   201
- (NSString*) description {
snej@0
   202
    if (_keychain)
snej@0
   203
        return $sprintf(@"%@[%p, %@]", [self class], _keychain, self.path);
snej@0
   204
    else
snej@0
   205
        return $sprintf(@"%@[all]", [self class]);
snej@0
   206
}
snej@0
   207
snej@0
   208
jens@16
   209
+ (void) setUserInteractionAllowed: (BOOL)allowed {
jens@16
   210
    SecKeychainSetUserInteractionAllowed(allowed);
jens@16
   211
}
jens@16
   212
jens@16
   213
snej@0
   214
#pragma mark -
snej@0
   215
#pragma mark SEARCHING:
snej@0
   216
snej@0
   217
snej@0
   218
- (MYKeychainItem*) itemOfClass: (SecItemClass)itemClass 
snej@0
   219
                     withDigest: (MYSHA1Digest*)pubKeyDigest 
snej@0
   220
{
snej@0
   221
    SecKeychainAttribute attr = {.tag= (itemClass==kSecCertificateItemClass ?kSecPublicKeyHashItemAttr :kSecKeyLabel), 
snej@0
   222
                                 .length= pubKeyDigest.length, 
snej@0
   223
                                 .data= (void*) pubKeyDigest.bytes};
snej@0
   224
    MYKeyEnumerator *e = [[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   225
                                                         itemClass: itemClass
snej@0
   226
                                                        attributes: &attr count: 1];
snej@0
   227
    MYKeychainItem *item = e.nextObject;
snej@0
   228
    [e release];
snej@0
   229
    return item;
snej@0
   230
}
snej@0
   231
snej@0
   232
- (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@0
   233
    return (MYPublicKey*) [self itemOfClass: kSecPublicKeyItemClass withDigest: pubKeyDigest];
snej@0
   234
}   
snej@0
   235
snej@0
   236
- (NSEnumerator*) enumeratePublicKeys {
snej@0
   237
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   238
                                            itemClass: kSecPublicKeyItemClass
snej@0
   239
                                           attributes: NULL count: 0] autorelease];
snej@0
   240
}
snej@0
   241
snej@0
   242
- (NSEnumerator*) publicKeysWithAlias: (NSString*)alias {
snej@0
   243
    NSData *utf8 = [alias dataUsingEncoding: NSUTF8StringEncoding];
snej@0
   244
    SecKeychainAttribute attr = {.tag=kSecKeyAlias, .length=utf8.length, .data=(void*)utf8.bytes};
snej@0
   245
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   246
                                            itemClass: kSecPublicKeyItemClass
snej@0
   247
                                           attributes: &attr count: 1] autorelease];
snej@0
   248
}
snej@0
   249
snej@0
   250
snej@3
   251
- (MYPrivateKey*) privateKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@3
   252
    return (MYPrivateKey*) [self itemOfClass: kSecPrivateKeyItemClass withDigest: pubKeyDigest];
snej@0
   253
}
snej@0
   254
snej@3
   255
- (NSEnumerator*) enumeratePrivateKeys {
snej@0
   256
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   257
                                            itemClass: kSecPrivateKeyItemClass
snej@0
   258
                                           attributes: NULL count: 0] autorelease];
snej@0
   259
}
snej@0
   260
snej@0
   261
- (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
snej@0
   262
    return (MYCertificate*) [self itemOfClass: kSecCertificateItemClass withDigest: pubKeyDigest];
snej@0
   263
}
snej@0
   264
snej@0
   265
- (NSEnumerator*) enumerateCertificates {
snej@0
   266
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   267
                                            itemClass: kSecCertificateItemClass
snej@0
   268
                                           attributes: NULL count: 0] autorelease];
snej@0
   269
}
snej@0
   270
snej@4
   271
- (NSEnumerator*) enumerateIdentities {
jens@26
   272
    return [self enumerateIdentitiesWithKeyUsage: 0];
jens@26
   273
}
jens@26
   274
jens@26
   275
- (NSEnumerator*) enumerateIdentitiesWithKeyUsage: (CSSM_KEYUSE)keyUsage {
jens@26
   276
    return [[[MYIdentityEnumerator alloc] initWithKeychain: self keyUsage: keyUsage] autorelease];
snej@4
   277
}
snej@4
   278
snej@0
   279
- (NSEnumerator*) enumerateSymmetricKeys {
snej@0
   280
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   281
                                            itemClass: kSecSymmetricKeyItemClass
snej@0
   282
                                           attributes: NULL count: 0] autorelease];
snej@0
   283
}
snej@0
   284
snej@0
   285
- (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
snej@0
   286
    NSData *utf8 = [alias dataUsingEncoding: NSUTF8StringEncoding];
snej@0
   287
    SecKeychainAttribute attr = {.tag=kSecKeyAlias, .length=utf8.length, .data=(void*)utf8.bytes};
snej@0
   288
    return [[[MYKeyEnumerator alloc] initWithKeychain: self
snej@0
   289
                                            itemClass: kSecSymmetricKeyItemClass
snej@0
   290
                                           attributes: &attr count: 1] autorelease];
snej@0
   291
}
snej@0
   292
snej@0
   293
snej@0
   294
snej@0
   295
#pragma mark -
snej@0
   296
#pragma mark IMPORT:
snej@0
   297
snej@0
   298
snej@0
   299
- (MYPublicKey*) importPublicKey: (NSData*)keyData {
snej@0
   300
    return [[[MYPublicKey alloc] _initWithKeyData: keyData 
snej@0
   301
                                      forKeychain: self.keychainRefOrDefault]
snej@0
   302
            autorelease];
snej@0
   303
}
snej@0
   304
snej@3
   305
- (MYPrivateKey*) importPublicKey: (NSData*)pubKeyData 
snej@0
   306
                    privateKey: (NSData*)privKeyData 
snej@0
   307
                    alertTitle: (NSString*)title
snej@0
   308
                   alertPrompt: (NSString*)prompt {
snej@3
   309
    return [[[MYPrivateKey alloc] _initWithKeyData: privKeyData
snej@3
   310
                                     publicKeyData: pubKeyData
snej@3
   311
                                       forKeychain: self.keychainRefOrDefault
snej@3
   312
                                        alertTitle: (NSString*)title
snej@3
   313
                                       alertPrompt: (NSString*)prompt]
snej@0
   314
            autorelease];
snej@0
   315
}
snej@0
   316
snej@3
   317
- (MYPrivateKey*) importPublicKey: (NSData*)pubKeyData 
snej@0
   318
                    privateKey: (NSData*)privKeyData 
snej@0
   319
{
snej@0
   320
    return [self importPublicKey: pubKeyData privateKey: privKeyData
snej@0
   321
                      alertTitle: @"Import Private Key"
snej@0
   322
                     alertPrompt: @"To import your saved private key, please re-enter the "
snej@0
   323
                                   "passphrase you used when you exported it."];
snej@0
   324
}
snej@0
   325
snej@0
   326
- (MYCertificate*) importCertificate: (NSData*)data
snej@0
   327
                                type: (CSSM_CERT_TYPE) type
snej@0
   328
                            encoding: (CSSM_CERT_ENCODING) encoding;
snej@0
   329
{
snej@0
   330
    MYCertificate *cert = [[[MYCertificate alloc] initWithCertificateData: data 
snej@0
   331
                                                                    type: type
snej@0
   332
                                                                encoding: encoding]
snej@0
   333
                           autorelease];
snej@0
   334
    if (cert) {
snej@0
   335
        if (!check(SecCertificateAddToKeychain(cert.certificateRef, self.keychainRefOrDefault),
snej@0
   336
                   @"SecCertificateAddToKeychain"))
snej@0
   337
            cert = nil;
snej@0
   338
    }
snej@0
   339
    return cert;
snej@0
   340
}
snej@0
   341
snej@0
   342
- (MYCertificate*) importCertificate: (NSData*)data {
snej@0
   343
    return [self importCertificate: data 
snej@0
   344
                              type: CSSM_CERT_X_509v3 
snej@0
   345
                          encoding: CSSM_CERT_ENCODING_BER];
snej@0
   346
}
snej@0
   347
snej@4
   348
- (BOOL) addCertificate: (MYCertificate*)certificate {
snej@4
   349
    Assert(certificate);
snej@4
   350
    return check(SecCertificateAddToKeychain(certificate.certificateRef, self.keychainRefOrDefault),
snej@4
   351
                 @"SecCertificateAddToKeychain");
snej@4
   352
}
snej@4
   353
snej@0
   354
snej@0
   355
- (MYSymmetricKey*) generateSymmetricKeyOfSize: (unsigned)keySizeInBits
snej@0
   356
                                     algorithm: (CCAlgorithm)algorithm
snej@0
   357
{
snej@0
   358
    return [MYSymmetricKey _generateSymmetricKeyOfSize: keySizeInBits
snej@0
   359
                                             algorithm: algorithm inKeychain: self];
snej@0
   360
}
snej@0
   361
snej@3
   362
- (MYPrivateKey*) generateRSAKeyPairOfSize: (unsigned)keySize {
snej@3
   363
    return [MYPrivateKey _generateRSAKeyPairOfSize: keySize inKeychain: self];
snej@0
   364
}
snej@0
   365
snej@0
   366
snej@0
   367
- (CSSM_CSP_HANDLE) CSPHandle {
snej@0
   368
    CSSM_CSP_HANDLE cspHandle = 0;
snej@0
   369
    Assert(check(SecKeychainGetCSPHandle(self.keychainRefOrDefault, &cspHandle), @"SecKeychainGetCSPHandle"));
snej@0
   370
    return cspHandle;
snej@0
   371
}
snej@0
   372
snej@0
   373
snej@0
   374
@end
snej@0
   375
snej@0
   376
snej@0
   377
snej@0
   378
#pragma mark -
snej@0
   379
@implementation MYKeyEnumerator
snej@0
   380
snej@0
   381
- (id) initWithKeychain: (MYKeychain*)keychain
snej@0
   382
              itemClass: (SecItemClass)itemClass
snej@0
   383
             attributes: (SecKeychainAttribute[])attributes 
snej@0
   384
                  count: (unsigned)count {
snej@0
   385
    self = [super init];
snej@0
   386
    if (self) {
snej@0
   387
        _keychain = [keychain retain];
snej@0
   388
        _itemClass = itemClass;
snej@0
   389
        SecKeychainAttributeList list = {.count=count, .attr=attributes};
snej@0
   390
        if (!check(SecKeychainSearchCreateFromAttributes(keychain.keychainRef,
snej@0
   391
                                                         itemClass,
snej@0
   392
                                                         &list,
snej@0
   393
                                                         &_search),
snej@0
   394
                   @"SecKeychainSearchCreateFromAttributes")) {
snej@0
   395
            [self release];
snej@0
   396
            return nil;
snej@0
   397
        }
snej@0
   398
    }
snej@0
   399
    return self;
snej@0
   400
}
snej@0
   401
snej@0
   402
- (void) dealloc
snej@0
   403
{
snej@0
   404
    [_keychain release];
snej@0
   405
    if (_search) CFRelease(_search);
snej@0
   406
    [super dealloc];
snej@0
   407
}
snej@0
   408
snej@2
   409
- (void) finalize
snej@2
   410
{
snej@2
   411
    [_keychain release];
snej@2
   412
    if (_search) CFRelease(_search);
snej@2
   413
    [super finalize];
snej@2
   414
}
snej@2
   415
snej@0
   416
snej@0
   417
- (id) nextObject {
snej@0
   418
    if (!_search)
snej@0
   419
        return nil;
snej@0
   420
    MYPublicKey *key = nil;
snej@0
   421
    do{
snej@0
   422
        SecKeychainItemRef found = NULL;
snej@0
   423
        OSStatus err = SecKeychainSearchCopyNext(_search, &found);
snej@0
   424
        if (err || !found) {
snej@0
   425
            if (err != errSecItemNotFound)
snej@0
   426
                check(err,@"SecKeychainSearchCopyNext");
snej@0
   427
            CFRelease(_search);
snej@0
   428
            _search = NULL;
snej@0
   429
            return nil;
snej@0
   430
        }
snej@0
   431
        
snej@0
   432
        switch (_itemClass) {
snej@0
   433
            case kSecPrivateKeyItemClass: {
snej@3
   434
                key = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
snej@0
   435
                break;
snej@0
   436
            }
snej@0
   437
            case kSecCertificateItemClass:
snej@0
   438
                key = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
snej@0
   439
                break;
snej@0
   440
            case kSecPublicKeyItemClass:
snej@0
   441
                key = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
snej@0
   442
                break;
snej@0
   443
        }
snej@0
   444
        CFRelease(found);
snej@0
   445
    } while (key==nil);
snej@0
   446
    return key;
snej@0
   447
}
snej@0
   448
snej@4
   449
@end
snej@4
   450
snej@4
   451
snej@4
   452
snej@4
   453
@implementation MYIdentityEnumerator
snej@4
   454
jens@26
   455
- (id) initWithKeychain: (MYKeychain*)keychain keyUsage: (CSSM_KEYUSE)keyUsage {
snej@4
   456
    self = [super init];
snej@4
   457
    if (self) {
jens@26
   458
        if (!check(SecIdentitySearchCreate(keychain.keychainRef, keyUsage, &_searchRef),
snej@4
   459
                   @"SecIdentitySearchCreate")) {
snej@4
   460
            [self release];
snej@4
   461
            return nil;
snej@4
   462
        }
snej@4
   463
    }
snej@4
   464
    return self;
snej@4
   465
}
snej@4
   466
snej@4
   467
- (id) nextObject {
snej@4
   468
    SecIdentityRef identityRef = NULL;
snej@4
   469
    OSStatus err = SecIdentitySearchCopyNext(_searchRef, &identityRef);
snej@4
   470
    if (err==errKCItemNotFound || !check(err, @"SecIdentitySearchCopyNext"))
snej@4
   471
        return nil;
snej@4
   472
    return [[[MYIdentity alloc] initWithIdentityRef: identityRef] autorelease];
snej@4
   473
}
snej@0
   474
snej@0
   475
@end
snej@0
   476
snej@0
   477
snej@2
   478
#endif !MYCRYPTO_USE_IPHONE_API
snej@0
   479
snej@0
   480
snej@0
   481
snej@0
   482
/*
snej@0
   483
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
snej@0
   484
 
snej@0
   485
 Redistribution and use in source and binary forms, with or without modification, are permitted
snej@0
   486
 provided that the following conditions are met:
snej@0
   487
 
snej@0
   488
 * Redistributions of source code must retain the above copyright notice, this list of conditions
snej@0
   489
 and the following disclaimer.
snej@0
   490
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
snej@0
   491
 and the following disclaimer in the documentation and/or other materials provided with the
snej@0
   492
 distribution.
snej@0
   493
 
snej@0
   494
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
snej@0
   495
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
snej@0
   496
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
snej@0
   497
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
snej@0
   498
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
snej@0
   499
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
snej@0
   500
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
snej@0
   501
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
snej@0
   502
 */