MYCertificateInfo.m
author Jens Alfke <jens@mooseyard.com>
Sun Jun 07 21:53:56 2009 -0700 (2009-06-07)
changeset 23 39fec79de6e8
parent 21 2c300b15b381
child 24 6856e071d25a
permissions -rw-r--r--
A snapshot taken during the long, agonizing crawl toward getting everything running on iPhone.
jens@17
     1
//
jens@21
     2
//  MYCertificateInfo.m
jens@17
     3
//  MYCrypto
jens@17
     4
//
jens@17
     5
//  Created by Jens Alfke on 6/2/09.
jens@17
     6
//  Copyright 2009 Jens Alfke. All rights reserved.
jens@17
     7
//
jens@17
     8
jens@17
     9
// References:
jens@20
    10
// <http://www.columbia.edu/~ariel/ssleay/layman.html> "Layman's Guide To ASN.1/BER/DER"
jens@20
    11
// <http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt> "X.509 Style Guide"
jens@20
    12
// <http://en.wikipedia.org/wiki/X.509> Wikipedia article on X.509
jens@17
    13
jens@17
    14
jens@21
    15
#import "MYCertificateInfo.h"
jens@21
    16
#import "MYCrypto.h"
jens@17
    17
#import "MYASN1Object.h"
jens@17
    18
#import "MYOID.h"
jens@17
    19
#import "MYBERParser.h"
jens@17
    20
#import "MYDEREncoder.h"
jens@17
    21
#import "MYErrorUtils.h"
jens@17
    22
jens@17
    23
jens@19
    24
#define kDefaultExpirationTime (60.0 * 60.0 * 24.0 * 365.0)
jens@19
    25
jens@19
    26
jens@17
    27
static id $atIf(NSArray *array, NSUInteger index) {
jens@17
    28
    return index < array.count ?[array objectAtIndex: index] :nil;
jens@17
    29
}
jens@17
    30
jens@17
    31
jens@20
    32
@interface MYCertificateName ()
jens@20
    33
- (id) _initWithComponents: (NSArray*)components;
jens@20
    34
@end
jens@20
    35
jens@21
    36
@interface MYCertificateInfo ()
jens@21
    37
@property (retain) NSArray *_root;
jens@21
    38
@end
jens@21
    39
jens@20
    40
jens@20
    41
#pragma mark -
jens@21
    42
@implementation MYCertificateInfo
jens@17
    43
jens@17
    44
jens@19
    45
static MYOID *kRSAAlgorithmID, *kRSAWithSHA1AlgorithmID, *kCommonNameOID,
jens@19
    46
            *kGivenNameOID, *kSurnameOID, *kDescriptionOID, *kEmailOID;
jens@17
    47
jens@17
    48
jens@17
    49
+ (void) initialize {
jens@19
    50
    if (!kEmailOID) {
jens@19
    51
        kRSAAlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 1,}
jens@19
    52
                                                      count: 7];
jens@19
    53
        kRSAWithSHA1AlgorithmID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 1, 5}
jens@19
    54
                                                              count: 7];
jens@19
    55
        kCommonNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 3}
jens@19
    56
                                                     count: 4];
jens@19
    57
        kGivenNameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 42}
jens@19
    58
                                                    count: 4];
jens@19
    59
        kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4}
jens@19
    60
                                                  count: 4];
jens@19
    61
        kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13}
jens@19
    62
                                                count: 7];
jens@19
    63
        kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1}
jens@19
    64
                                                count: 7];
jens@17
    65
    }
jens@21
    66
}
jens@21
    67
jens@21
    68
jens@21
    69
- (id) initWithRoot: (NSArray*)root
jens@21
    70
{
jens@21
    71
    self = [super init];
jens@21
    72
    if (self != nil) {
jens@21
    73
        _root = [root retain];
jens@21
    74
    }
jens@21
    75
    return self;
jens@17
    76
}
jens@17
    77
jens@17
    78
+ (NSString*) validate: (id)root {
jens@17
    79
    NSArray *top = $castIf(NSArray,root);
jens@17
    80
    if (top.count < 3)
jens@17
    81
        return @"Too few top-level components";
jens@17
    82
    NSArray *info = $castIf(NSArray, [top objectAtIndex: 0]);
jens@17
    83
    if (info.count < 7)
jens@17
    84
        return @"Too few identity components";
jens@17
    85
    MYASN1Object *version = $castIf(MYASN1Object, [info objectAtIndex: 0]);
jens@17
    86
    if (!version || version.tag != 0)
jens@17
    87
        return @"Missing or invalid version";
jens@17
    88
    NSArray *versionComps = $castIf(NSArray, version.components);
jens@17
    89
    if (!versionComps || versionComps.count != 1)
jens@17
    90
        return @"Invalid version";
jens@17
    91
    NSNumber *versionNum = $castIf(NSNumber, [versionComps objectAtIndex: 0]);
jens@17
    92
    if (!versionNum || versionNum.intValue < 0 || versionNum.intValue > 2)
jens@17
    93
        return @"Unrecognized version number";
jens@17
    94
    return nil;
jens@17
    95
}
jens@17
    96
jens@17
    97
jens@17
    98
- (id) initWithCertificateData: (NSData*)data error: (NSError**)outError;
jens@17
    99
{
jens@21
   100
    if (outError) *outError = nil;
jens@21
   101
    id root = MYBERParse(data,outError);
jens@21
   102
    NSString *errorMsg = [[self class] validate: root];
jens@21
   103
    if (errorMsg) {
jens@21
   104
        if (outError && !*outError)
jens@21
   105
            *outError = MYError(2, MYASN1ErrorDomain, @"Invalid certificate: %@", errorMsg);
jens@21
   106
        [self release];
jens@21
   107
        return nil;
jens@17
   108
    }
jens@21
   109
jens@21
   110
    return [self initWithRoot: root];
jens@17
   111
}
jens@17
   112
jens@17
   113
- (void) dealloc
jens@17
   114
{
jens@17
   115
    [_root release];
jens@17
   116
    [super dealloc];
jens@17
   117
}
jens@17
   118
jens@21
   119
- (BOOL) isEqual: (id)object {
jens@21
   120
    return [object isKindOfClass: [MYCertificateInfo class]]
jens@21
   121
        && [_root isEqual: ((MYCertificateInfo*)object)->_root];
jens@21
   122
}
jens@17
   123
jens@19
   124
- (NSArray*) _info       {return $castIf(NSArray,$atIf(_root,0));}
jens@17
   125
jens@19
   126
- (NSArray*) _validDates {return $castIf(NSArray, [self._info objectAtIndex: 4]);}
jens@17
   127
jens@21
   128
@synthesize _root;
jens@19
   129
jens@19
   130
jens@19
   131
- (NSDate*) validFrom       {return $castIf(NSDate, $atIf(self._validDates, 0));}
jens@19
   132
- (NSDate*) validTo         {return $castIf(NSDate, $atIf(self._validDates, 1));}
jens@20
   133
jens@20
   134
- (MYCertificateName*) subject {
jens@20
   135
    return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 5]] autorelease];
jens@20
   136
}
jens@20
   137
jens@20
   138
- (MYCertificateName*) issuer {
jens@20
   139
    return [[[MYCertificateName alloc] _initWithComponents: [self._info objectAtIndex: 3]] autorelease];
jens@20
   140
}
jens@19
   141
jens@19
   142
- (BOOL) isSigned           {return [_root count] >= 3;}
jens@19
   143
jens@19
   144
- (BOOL) isRoot {
jens@19
   145
    id issuer = $atIf(self._info,3);
jens@19
   146
    return $equal(issuer, $atIf(self._info,5)) || $equal(issuer, $array());
jens@19
   147
}
jens@19
   148
jens@19
   149
jens@17
   150
- (MYPublicKey*) subjectPublicKey {
jens@19
   151
    NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6));
jens@17
   152
    MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0));
jens@17
   153
    if (!$equal(keyAlgorithmID, kRSAAlgorithmID))
jens@17
   154
        return nil;
jens@17
   155
    MYBitString *keyData = $cast(MYBitString, $atIf(keyInfo, 1));
jens@17
   156
    if (!keyData) return nil;
jens@17
   157
    return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease];
jens@17
   158
}
jens@17
   159
jens@21
   160
@end
jens@17
   161
jens@17
   162
jens@17
   163
jens@17
   164
jens@19
   165
#pragma mark -
jens@21
   166
@implementation MYCertificateRequest
jens@19
   167
jens@21
   168
- (id) initWithPublicKey: (MYPublicKey*)publicKey {
jens@21
   169
    Assert(publicKey);
jens@21
   170
    id empty = [NSNull null];
jens@21
   171
    id version = [[MYASN1Object alloc] initWithTag: 0 ofClass: 2 components: $array($object(0))];
jens@21
   172
    NSArray *root = $array( $marray(version,
jens@21
   173
                                    empty,       // serial #
jens@21
   174
                                    $array(kRSAAlgorithmID),
jens@21
   175
                                    $marray(),
jens@21
   176
                                    $marray(empty, empty),
jens@21
   177
                                    $marray(),
jens@21
   178
                                    $array( $array(kRSAAlgorithmID, empty),
jens@21
   179
                                           [MYBitString bitStringWithData: publicKey.keyData] ) ) );
jens@21
   180
    self = [super initWithRoot: root];
jens@21
   181
    [version release];
jens@23
   182
    if (self) {
jens@23
   183
        _publicKey = publicKey.retain;
jens@23
   184
    }
jens@19
   185
    return self;
jens@19
   186
}
jens@23
   187
    
jens@23
   188
- (void) dealloc
jens@23
   189
{
jens@23
   190
    [_publicKey release];
jens@23
   191
    [super dealloc];
jens@23
   192
}
jens@23
   193
jens@19
   194
jens@21
   195
- (NSDate*) validFrom       {return [super validFrom];}
jens@21
   196
- (NSDate*) validTo         {return [super validTo];}
jens@19
   197
jens@19
   198
- (void) setValidFrom: (NSDate*)validFrom {
jens@19
   199
    [(NSMutableArray*)self._validDates replaceObjectAtIndex: 0 withObject: validFrom];
jens@19
   200
}
jens@19
   201
jens@19
   202
- (void) setValidTo: (NSDate*)validTo {
jens@19
   203
    [(NSMutableArray*)self._validDates replaceObjectAtIndex: 1 withObject: validTo];
jens@19
   204
}
jens@19
   205
jens@19
   206
jens@21
   207
- (void) fillInValues {
jens@19
   208
    NSMutableArray *info = (NSMutableArray*)self._info;
jens@19
   209
    // Set serial number if there isn't one yet:
jens@19
   210
    if (!$castIf(NSNumber, [info objectAtIndex: 1])) {
jens@19
   211
        UInt64 serial = floor(CFAbsoluteTimeGetCurrent() * 1000);
jens@19
   212
        [info replaceObjectAtIndex: 1 withObject: $object(serial)];
jens@19
   213
    }
jens@19
   214
    
jens@19
   215
    // Set up valid date range if there isn't one yet:
jens@19
   216
    NSDate *validFrom = self.validFrom;
jens@19
   217
    if (!validFrom)
jens@19
   218
        validFrom = self.validFrom = [NSDate date];
jens@19
   219
    NSDate *validTo = self.validTo;
jens@19
   220
    if (!validTo)
jens@19
   221
        self.validTo = [validFrom addTimeInterval: kDefaultExpirationTime]; 
jens@21
   222
}
jens@21
   223
jens@21
   224
jens@21
   225
- (NSData*) requestData: (NSError**)outError {
jens@21
   226
    [self fillInValues];
jens@21
   227
    return [MYDEREncoder encodeRootObject: self._info error: outError];
jens@21
   228
}
jens@21
   229
jens@21
   230
jens@21
   231
- (NSData*) selfSignWithPrivateKey: (MYPrivateKey*)privateKey 
jens@21
   232
                             error: (NSError**)outError 
jens@21
   233
{
jens@21
   234
    AssertEqual(privateKey.publicKey, _publicKey);  // Keys must form a pair
jens@19
   235
    
jens@21
   236
    // Copy subject to issuer:
jens@21
   237
    NSMutableArray *info = (NSMutableArray*)self._info;
jens@21
   238
    [info replaceObjectAtIndex: 3 withObject: [info objectAtIndex: 5]];
jens@21
   239
    
jens@21
   240
    // Sign the request:
jens@21
   241
    NSData *dataToSign = [self requestData: outError];
jens@19
   242
    if (!dataToSign)
jens@21
   243
        return nil;
jens@21
   244
    MYBitString *signature = [MYBitString bitStringWithData: [privateKey signData: dataToSign]];
jens@19
   245
    
jens@21
   246
    // Generate and encode the certificate:
jens@21
   247
    NSArray *root = $array(info, 
jens@21
   248
                           $array(kRSAWithSHA1AlgorithmID, [NSNull null]),
jens@21
   249
                           signature);
jens@21
   250
    return [MYDEREncoder encodeRootObject: root error: outError];
jens@21
   251
}
jens@21
   252
jens@21
   253
jens@21
   254
- (MYIdentity*) createSelfSignedIdentityWithPrivateKey: (MYPrivateKey*)privateKey
jens@21
   255
                                                 error: (NSError**)outError
jens@21
   256
{
jens@23
   257
    Assert(privateKey.keychain!=nil);
jens@21
   258
    NSData *certData = [self selfSignWithPrivateKey: privateKey error: outError];
jens@21
   259
    if (!certData)
jens@21
   260
        return nil;
jens@21
   261
    MYCertificate *cert = [privateKey.keychain importCertificate: certData];
jens@21
   262
    Assert(cert!=nil);
jens@23
   263
    Assert(cert.keychain!=nil);
jens@23
   264
    AssertEqual(cert.publicKey.keyData, _publicKey.keyData);
jens@21
   265
    MYIdentity *identity = cert.identity;
jens@21
   266
    Assert(identity!=nil);
jens@21
   267
    return identity;
jens@19
   268
}
jens@19
   269
jens@19
   270
jens@17
   271
@end
jens@17
   272
jens@17
   273
jens@17
   274
jens@20
   275
#pragma mark -
jens@20
   276
@implementation MYCertificateName
jens@20
   277
jens@20
   278
- (id) _initWithComponents: (NSArray*)components
jens@20
   279
{
jens@20
   280
    self = [super init];
jens@20
   281
    if (self != nil) {
jens@20
   282
        _components = [components retain];
jens@20
   283
    }
jens@20
   284
    return self;
jens@20
   285
}
jens@20
   286
jens@20
   287
- (void) dealloc
jens@20
   288
{
jens@20
   289
    [_components release];
jens@20
   290
    [super dealloc];
jens@20
   291
}
jens@20
   292
jens@20
   293
- (BOOL) isEqual: (id)object {
jens@20
   294
    return [object isKindOfClass: [MYCertificateName class]]
jens@20
   295
        && [_components isEqual: ((MYCertificateName*)object)->_components];
jens@20
   296
}
jens@20
   297
jens@20
   298
- (NSArray*) _pairForOID: (MYOID*)oid {
jens@20
   299
    for (id nameEntry in _components) {
jens@20
   300
        for (id pair in $castIf(NSSet,nameEntry)) {
jens@20
   301
            if ([pair isKindOfClass: [NSArray class]] && [pair count] == 2) {
jens@20
   302
                if ($equal(oid, [pair objectAtIndex: 0]))
jens@20
   303
                    return pair;
jens@20
   304
            }
jens@20
   305
        }
jens@20
   306
    }
jens@20
   307
    return nil;
jens@20
   308
}
jens@20
   309
jens@20
   310
- (NSString*) stringForOID: (MYOID*)oid {
jens@20
   311
    return [[self _pairForOID: oid] objectAtIndex: 1];
jens@20
   312
}
jens@20
   313
jens@20
   314
- (void) setString: (NSString*)value forOID: (MYOID*)oid {
jens@20
   315
    NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid];
jens@20
   316
    if (pair)
jens@20
   317
        [pair replaceObjectAtIndex: 1 withObject: value];
jens@20
   318
    else
jens@20
   319
        [(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]];
jens@20
   320
}
jens@20
   321
jens@20
   322
- (NSString*) commonName    {return [self stringForOID: kCommonNameOID];}
jens@20
   323
- (NSString*) givenName     {return [self stringForOID: kGivenNameOID];}
jens@20
   324
- (NSString*) surname       {return [self stringForOID: kSurnameOID];}
jens@20
   325
- (NSString*) nameDescription {return [self stringForOID: kDescriptionOID];}
jens@20
   326
- (NSString*) emailAddress  {return [self stringForOID: kEmailOID];}
jens@20
   327
jens@20
   328
- (void) setCommonName: (NSString*)commonName   {[self setString: commonName forOID: kCommonNameOID];}
jens@20
   329
- (void) setGivenName: (NSString*)givenName     {[self setString: givenName forOID: kGivenNameOID];}
jens@20
   330
- (void) setSurname: (NSString*)surname         {[self setString: surname forOID: kSurnameOID];}
jens@20
   331
- (void) setNameDescription: (NSString*)desc    {[self setString: desc forOID: kDescriptionOID];}
jens@20
   332
- (void) setEmailAddress: (NSString*)email      {[self setString: email forOID: kEmailOID];}
jens@20
   333
jens@20
   334
jens@20
   335
@end
jens@20
   336
jens@20
   337
jens@20
   338
jens@20
   339
#pragma mark -
jens@20
   340
#pragma mark TEST CASES:
jens@17
   341
jens@19
   342
#if DEBUG
jens@19
   343
jens@19
   344
jens@23
   345
static MYCertificateInfo* testCertData(NSData *certData, BOOL selfSigned) {
jens@19
   346
    //Log(@"Cert Data =\n%@", certData);
jens@23
   347
    CAssert(certData!=nil);
jens@19
   348
    NSError *error = nil;
jens@21
   349
    MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData 
jens@21
   350
                                                                            error: &error];
jens@19
   351
    CAssertNil(error);
jens@19
   352
    CAssert(pcert != nil);
jens@19
   353
    
jens@19
   354
    CAssertEq(pcert.isRoot, selfSigned);
jens@21
   355
        
jens@19
   356
    Log(@"Subject Public Key = %@", pcert.subjectPublicKey);
jens@19
   357
    CAssert(pcert.subjectPublicKey);
jens@20
   358
    MYCertificateName *subject = pcert.subject;
jens@20
   359
    Log(@"Common Name = %@", subject.commonName);
jens@20
   360
    Log(@"Given Name  = %@", subject.givenName);
jens@20
   361
    Log(@"Surname     = %@", subject.surname);
jens@20
   362
    Log(@"Desc        = %@", subject.nameDescription);
jens@20
   363
    Log(@"Email       = %@", subject.emailAddress);
jens@21
   364
    CAssert(subject.commonName);
jens@21
   365
    
jens@21
   366
    // Now go through MYCertificate:
jens@21
   367
    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
jens@21
   368
    CAssert(cert);
jens@21
   369
    CAssertEqual(cert.info, pcert);
jens@21
   370
    
jens@19
   371
    return pcert;
jens@19
   372
}
jens@19
   373
jens@23
   374
static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
jens@23
   375
#if TARGET_OS_IPHONE
jens@23
   376
    filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"];
jens@23
   377
#else
jens@23
   378
    filename = [[@"../../Tests/" stringByAppendingPathComponent: filename]
jens@23
   379
                stringByAppendingPathExtension: @"cer"];
jens@23
   380
#endif
jens@23
   381
    Log(@"--- Creating MYCertificateInfo from %@", filename);
jens@23
   382
    return testCertData([NSData dataWithContentsOfFile: filename], selfSigned);
jens@23
   383
}
jens@23
   384
jens@19
   385
jens@17
   386
TestCase(ParsedCert) {
jens@23
   387
    testCert(@"selfsigned", YES);
jens@23
   388
    testCert(@"iphonedev", NO);
jens@19
   389
}
jens@19
   390
jens@19
   391
jens@21
   392
#import "MYCrypto_Private.h"
jens@19
   393
jens@19
   394
TestCase(CreateCert) {
jens@19
   395
    MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
jens@21
   396
    CAssert(privateKey);
jens@21
   397
    MYIdentity *identity = nil;
jens@21
   398
    @try{
jens@21
   399
        MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey];
jens@21
   400
        MYCertificateName *subject = pcert.subject;
jens@21
   401
        subject.commonName = @"testcase";
jens@21
   402
        subject.givenName = @"Test";
jens@21
   403
        subject.surname = @"Case";
jens@21
   404
        subject.nameDescription = @"Just a test certificate created by MYCrypto";
jens@21
   405
        subject.emailAddress = @"testcase@example.com";
jens@19
   406
jens@21
   407
        subject = pcert.subject;
jens@21
   408
        CAssertEqual(subject.commonName, @"testcase");
jens@21
   409
        CAssertEqual(subject.givenName, @"Test");
jens@21
   410
        CAssertEqual(subject.surname, @"Case");
jens@21
   411
        CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto");
jens@21
   412
        CAssertEqual(subject.emailAddress, @"testcase@example.com");
jens@21
   413
        
jens@21
   414
        Log(@"Signing...");
jens@21
   415
        NSError *error;
jens@21
   416
        NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error];
jens@21
   417
        Log(@"Generated cert = \n%@", certData);
jens@21
   418
        CAssert(certData);
jens@21
   419
        CAssertNil(error);
jens@21
   420
        CAssert(certData);
jens@23
   421
#if !TARGET_OS_IPHONE
jens@21
   422
        [certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
jens@23
   423
#endif
jens@23
   424
        MYCertificateInfo *pcert2 = testCertData(certData, YES);
jens@21
   425
        
jens@21
   426
        Log(@"Verifying Info...");
jens@21
   427
        MYCertificateName *subject2 = pcert2.subject;
jens@21
   428
        CAssertEqual(subject2,subject);
jens@21
   429
        CAssertEqual(subject2.commonName, @"testcase");
jens@21
   430
        CAssertEqual(subject2.givenName, @"Test");
jens@21
   431
        CAssertEqual(subject2.surname, @"Case");
jens@21
   432
        CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto");
jens@21
   433
        CAssertEqual(subject2.emailAddress, @"testcase@example.com");
jens@21
   434
        
jens@21
   435
        Log(@"Verifying Signature...");
jens@21
   436
        MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
jens@21
   437
        Log(@"Loaded %@", cert);
jens@21
   438
        CAssert(cert);
jens@21
   439
        MYPublicKey *certKey = cert.publicKey;
jens@21
   440
        Log(@"Its public key = %@", certKey);
jens@21
   441
        CAssertEqual(certKey.keyData, privateKey.publicKey.keyData);
jens@21
   442
        
jens@21
   443
        Log(@"Creating Identity...");
jens@21
   444
        identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error];
jens@21
   445
        Log(@"Identity = %@", identity);
jens@21
   446
        CAssert(identity);
jens@21
   447
        CAssertNil(error);
jens@21
   448
        CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]);
jens@21
   449
        CAssertEqual(identity.privateKey, privateKey);
jens@21
   450
        CAssert([identity isEqualToCertificate: cert]);
jens@21
   451
        
jens@21
   452
        [pcert release];
jens@21
   453
        
jens@21
   454
    } @finally {
jens@21
   455
        [privateKey removeFromKeychain];
jens@21
   456
        [identity removeFromKeychain];
jens@21
   457
    }
jens@19
   458
}
jens@19
   459
jens@19
   460
#endif
jens@19
   461
jens@17
   462
jens@21
   463
/*
jens@21
   464
 Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
jens@17
   465
 
jens@21
   466
 Redistribution and use in source and binary forms, with or without modification, are permitted
jens@21
   467
 provided that the following conditions are met:
jens@21
   468
 
jens@21
   469
 * Redistributions of source code must retain the above copyright notice, this list of conditions
jens@21
   470
 and the following disclaimer.
jens@21
   471
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
jens@21
   472
 and the following disclaimer in the documentation and/or other materials provided with the
jens@21
   473
 distribution.
jens@21
   474
 
jens@21
   475
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
jens@21
   476
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
jens@21
   477
 FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
jens@21
   478
 BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
jens@21
   479
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
jens@21
   480
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
jens@21
   481
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
jens@21
   482
 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
jens@21
   483
 */