Whew, lots and lots of changes accumulated over the past few weeks. Mostly fixes for bugs I discovered while retrofitting Cloudy to use MYCrypto.
authorJens Alfke <jens@mooseyard.com>
Wed Jul 01 14:19:13 2009 -0700 (2009-07-01)
changeset 26d9c2a06d4e4e
parent 25 38c3c3923e1f
child 27 d0aadddb9c64
Whew, lots and lots of changes accumulated over the past few weeks. Mostly fixes for bugs I discovered while retrofitting Cloudy to use MYCrypto.
MYBERParser.h
MYCertificate.h
MYCertificate.m
MYCertificateInfo.m
MYCertificateTest.m
MYCrypto-iPhone.xcodeproj/project.pbxproj
MYCrypto.xcodeproj/project.pbxproj
MYCryptoTest.m
MYCrypto_Prefix.pch
MYCrypto_Private.h
MYDigest.h
MYIdentity.m
MYKey-iPhone.m
MYKey.h
MYKey.m
MYKeychain-iPhone.m
MYKeychain.h
MYKeychain.m
MYKeychainItem.h
MYKeychainItem.m
MYOID.h
MYOID.m
MYPublicKey.h
MYPublicKey.m
MYSymmetricKey-iPhone.m
MYSymmetricKey.h
MYSymmetricKey.m
Tests/generated.cer
Tests/iphonedev.pem
Tests/selfsigned.pem
Tests/selfsigned_altered.pem
     1.1 --- a/MYBERParser.h	Wed Jun 10 09:02:18 2009 -0700
     1.2 +++ b/MYBERParser.h	Wed Jul 01 14:19:13 2009 -0700
     1.3 @@ -19,5 +19,6 @@
     1.4  size_t MYBERGetLength (NSData *ber, NSError **outError);
     1.5  const void* MYBERGetContents (NSData *ber, NSError **outError);
     1.6  
     1.7 +/** A date formatter with the format string "yyyyMMddHHmmss'Z'" */
     1.8  NSDateFormatter* MYBERGeneralizedTimeFormatter();
     1.9  NSDateFormatter* MYBERUTCTimeFormatter();
     2.1 --- a/MYCertificate.h	Wed Jun 10 09:02:18 2009 -0700
     2.2 +++ b/MYCertificate.h	Wed Jul 01 14:19:13 2009 -0700
     2.3 @@ -12,7 +12,7 @@
     2.4  #import <Security/cssmtype.h>
     2.5  #endif
     2.6  
     2.7 -@class MYPublicKey, MYIdentity, MYCertificateInfo;
     2.8 +@class MYPublicKey, MYIdentity, MYCertificateInfo, MYSHA1Digest;
     2.9  
    2.10  
    2.11  /** An X.509 certificate. */
    2.12 @@ -43,6 +43,9 @@
    2.13  /** The certificate's public key. */
    2.14  @property (readonly) MYPublicKey *publicKey;
    2.15  
    2.16 +/** The certificate's public key's SHA-1 digest. */
    2.17 +@property (readonly) MYSHA1Digest *publicKeyDigest;
    2.18 +
    2.19  /** The Identity (if any) that this Certificate is part of. */
    2.20  @property (readonly) MYIdentity *identity;
    2.21  
     3.1 --- a/MYCertificate.m	Wed Jun 10 09:02:18 2009 -0700
     3.2 +++ b/MYCertificate.m	Wed Jul 01 14:19:13 2009 -0700
     3.3 @@ -157,9 +157,17 @@
     3.4          return nil;
     3.5      MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
     3.6      CFRelease(keyRef);
     3.7 +#if MYCRYPTO_USE_IPHONE_API
     3.8 +    key.certificate = self;
     3.9 +    key.isPersistent = NO;
    3.10 +#endif
    3.11      return key;
    3.12  }
    3.13  
    3.14 +- (MYSHA1Digest*) publicKeyDigest {
    3.15 +    return self.publicKey.publicKeyDigest;
    3.16 +}
    3.17 +
    3.18  - (MYIdentity*) identity {
    3.19      return [[[MYIdentity alloc] initWithCertificateRef: _certificateRef] autorelease];
    3.20  }
    3.21 @@ -214,7 +222,7 @@
    3.22      if (!check(SecTrustEvaluate(trust, &result), @"SecTrustEvaluate"))
    3.23          result = kSecTrustResultOtherError;
    3.24      
    3.25 -#if 0
    3.26 +#if !MYCRYPTO_USE_IPHONE_API
    3.27      // This is just to log details:
    3.28      CSSM_TP_APPLE_EVIDENCE_INFO *status;
    3.29      CFArrayRef certChain;
     4.1 --- a/MYCertificateInfo.m	Wed Jun 10 09:02:18 2009 -0700
     4.2 +++ b/MYCertificateInfo.m	Wed Jul 01 14:19:13 2009 -0700
     4.3 @@ -7,6 +7,7 @@
     4.4  //
     4.5  
     4.6  // References:
     4.7 +// <http://tools.ietf.org/html/rfc3280> "RFC 3280: Internet X.509 Certificate Profile"
     4.8  // <http://www.columbia.edu/~ariel/ssleay/layman.html> "Layman's Guide To ASN.1/BER/DER"
     4.9  // <http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt> "X.509 Style Guide"
    4.10  // <http://en.wikipedia.org/wiki/X.509> Wikipedia article on X.509
    4.11 @@ -67,7 +68,7 @@
    4.12          kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4}
    4.13                                                    count: 4];
    4.14          kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13}
    4.15 -                                                count: 7];
    4.16 +                                                count: 4];
    4.17          kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1}
    4.18                                                  count: 7];
    4.19      }
    4.20 @@ -160,14 +161,18 @@
    4.21  }
    4.22  
    4.23  
    4.24 -- (MYPublicKey*) subjectPublicKey {
    4.25 +- (NSData*) subjectPublicKeyData {
    4.26      NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6));
    4.27      MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0));
    4.28      if (!$equal(keyAlgorithmID, kRSAAlgorithmID))
    4.29          return nil;
    4.30 -    MYBitString *keyData = $cast(MYBitString, $atIf(keyInfo, 1));
    4.31 +    return $cast(MYBitString, $atIf(keyInfo, 1)).bits;
    4.32 +}
    4.33 +
    4.34 +- (MYPublicKey*) subjectPublicKey {
    4.35 +    NSData *keyData = self.subjectPublicKeyData;
    4.36      if (!keyData) return nil;
    4.37 -    return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease];
    4.38 +    return [[[MYPublicKey alloc] initWithKeyData: keyData] autorelease];
    4.39  }
    4.40  
    4.41  - (NSData*) signedData {
    4.42 @@ -364,10 +369,15 @@
    4.43  
    4.44  - (void) setString: (NSString*)value forOID: (MYOID*)oid {
    4.45      NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid];
    4.46 -    if (pair)
    4.47 -        [pair replaceObjectAtIndex: 1 withObject: value];
    4.48 -    else
    4.49 -        [(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]];
    4.50 +    if (pair) {
    4.51 +        if (value)
    4.52 +            [pair replaceObjectAtIndex: 1 withObject: value];
    4.53 +        else
    4.54 +            Assert(NO,@"-setString:forOID: removing strings is unimplemented");//FIX
    4.55 +    } else {
    4.56 +        if (value)
    4.57 +            [(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]];
    4.58 +    }
    4.59  }
    4.60  
    4.61  - (NSString*) commonName    {return [self stringForOID: kCommonNameOID];}
    4.62 @@ -386,152 +396,6 @@
    4.63  @end
    4.64  
    4.65  
    4.66 -
    4.67 -#pragma mark -
    4.68 -#pragma mark TEST CASES:
    4.69 -
    4.70 -#if DEBUG
    4.71 -
    4.72 -
    4.73 -static MYCertificateInfo* testCertData(NSData *certData, BOOL selfSigned) {
    4.74 -    //Log(@"Cert Data =\n%@", certData);
    4.75 -    CAssert(certData!=nil);
    4.76 -    NSError *error = nil;
    4.77 -    MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData 
    4.78 -                                                                            error: &error];
    4.79 -    CAssertNil(error);
    4.80 -    CAssert(pcert != nil);
    4.81 -    
    4.82 -    CAssertEq(pcert.isRoot, selfSigned);
    4.83 -        
    4.84 -    Log(@"Subject Public Key = %@", pcert.subjectPublicKey);
    4.85 -    CAssert(pcert.subjectPublicKey);
    4.86 -    MYCertificateName *subject = pcert.subject;
    4.87 -    Log(@"Common Name = %@", subject.commonName);
    4.88 -    Log(@"Given Name  = %@", subject.givenName);
    4.89 -    Log(@"Surname     = %@", subject.surname);
    4.90 -    Log(@"Desc        = %@", subject.nameDescription);
    4.91 -    Log(@"Email       = %@", subject.emailAddress);
    4.92 -    CAssert(subject.commonName);
    4.93 -    
    4.94 -    // Now go through MYCertificate:
    4.95 -    Log(@"Creating a MYCertificate from the data...");
    4.96 -    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
    4.97 -    Log(@"MYCertificate = %@", cert);
    4.98 -    CAssert(cert);
    4.99 -    CAssertEqual(cert.info, pcert);
   4.100 -    Log(@"Trust = %@", MYTrustResultDescribe([cert evaluateTrust]));
   4.101 -    
   4.102 -    return pcert;
   4.103 -}
   4.104 -
   4.105 -static NSData* readTestFile(NSString *filename) {
   4.106 -#if TARGET_OS_IPHONE
   4.107 -    filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"];
   4.108 -#else
   4.109 -    filename = [[@"../../Tests/" stringByAppendingPathComponent: filename]
   4.110 -                stringByAppendingPathExtension: @"cer"];
   4.111 -#endif
   4.112 -    Log(@"--- Testing certificate file %@", filename);
   4.113 -    NSData *data = [NSData dataWithContentsOfFile: filename];
   4.114 -    CAssert(data, @"Couldn't read file %@", filename);
   4.115 -    return data;
   4.116 -}
   4.117 -
   4.118 -static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
   4.119 -    return testCertData(readTestFile(filename), selfSigned);
   4.120 -}
   4.121 -
   4.122 -
   4.123 -TestCase(ParsedCert) {
   4.124 -    testCert(@"selfsigned", YES);
   4.125 -    testCert(@"iphonedev", NO);
   4.126 -    
   4.127 -    // Now test a self-signed cert with a bad signature:
   4.128 -    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: readTestFile(@"selfsigned_altered")];
   4.129 -    Log(@"MYCertificate = %@", cert);
   4.130 -    CAssertNil(cert);
   4.131 -
   4.132 -    Log(@"Checking /tmp/generated.cer");
   4.133 -    testCertData([NSData dataWithContentsOfFile: @"/tmp/generated.cer"], YES);//TEMP
   4.134 -}
   4.135 -
   4.136 -
   4.137 -#import "MYCrypto_Private.h"
   4.138 -
   4.139 -TestCase(CreateCert) {
   4.140 -    MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
   4.141 -    CAssert(privateKey);
   4.142 -    MYIdentity *identity = nil;
   4.143 -    @try{
   4.144 -        MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey];
   4.145 -        MYCertificateName *subject = pcert.subject;
   4.146 -        subject.commonName = @"testcase";
   4.147 -        subject.givenName = @"Test";
   4.148 -        subject.surname = @"Case";
   4.149 -        subject.nameDescription = @"Just a test certificate created by MYCrypto";
   4.150 -        subject.emailAddress = @"testcase@example.com";
   4.151 -
   4.152 -        subject = pcert.subject;
   4.153 -        CAssertEqual(subject.commonName, @"testcase");
   4.154 -        CAssertEqual(subject.givenName, @"Test");
   4.155 -        CAssertEqual(subject.surname, @"Case");
   4.156 -        CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto");
   4.157 -        CAssertEqual(subject.emailAddress, @"testcase@example.com");
   4.158 -        
   4.159 -        Log(@"Signing...");
   4.160 -        NSError *error;
   4.161 -        NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error];
   4.162 -        Log(@"Generated cert = \n%@", certData);
   4.163 -        CAssert(certData);
   4.164 -        CAssertNil(error);
   4.165 -        CAssert(certData);
   4.166 -#if TARGET_OS_IPHONE
   4.167 -        NSString *path = [@"/tmp/generated.cer" stringByStandardizingPath]; //TEMP
   4.168 -        CAssert([certData writeToFile: path atomically: YES]);
   4.169 -        Log(@"Wrote generated cert to %@",path);
   4.170 -#else
   4.171 -        [certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
   4.172 -#endif
   4.173 -        MYCertificateInfo *pcert2 = testCertData(certData, YES);
   4.174 -        
   4.175 -        Log(@"Verifying Info...");
   4.176 -        MYCertificateName *subject2 = pcert2.subject;
   4.177 -        CAssertEqual(subject2,subject);
   4.178 -        CAssertEqual(subject2.commonName, @"testcase");
   4.179 -        CAssertEqual(subject2.givenName, @"Test");
   4.180 -        CAssertEqual(subject2.surname, @"Case");
   4.181 -        CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto");
   4.182 -        CAssertEqual(subject2.emailAddress, @"testcase@example.com");
   4.183 -                
   4.184 -        Log(@"Creating MYCertificate object...");
   4.185 -        MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
   4.186 -        Log(@"Loaded %@", cert);
   4.187 -        CAssert(cert);
   4.188 -        MYPublicKey *certKey = cert.publicKey;
   4.189 -        Log(@"Its public key = %@", certKey);
   4.190 -        CAssertEqual(certKey.keyData, privateKey.publicKey.keyData);
   4.191 -        
   4.192 -        Log(@"Creating Identity...");
   4.193 -        identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error];
   4.194 -        Log(@"Identity = %@", identity);
   4.195 -        CAssert(identity);
   4.196 -        CAssertNil(error);
   4.197 -        CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]);
   4.198 -        CAssertEqual(identity.privateKey, privateKey);
   4.199 -        CAssert([identity isEqualToCertificate: cert]);
   4.200 -        
   4.201 -        [pcert release];
   4.202 -        
   4.203 -    } @finally {
   4.204 -        [privateKey removeFromKeychain];
   4.205 -        [identity removeFromKeychain];
   4.206 -    }
   4.207 -}
   4.208 -
   4.209 -#endif
   4.210 -
   4.211 -
   4.212  /*
   4.213   Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   4.214   
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/MYCertificateTest.m	Wed Jul 01 14:19:13 2009 -0700
     5.3 @@ -0,0 +1,196 @@
     5.4 +//
     5.5 +//  MYCertificateTest.m
     5.6 +//  MYCrypto-iPhone
     5.7 +//
     5.8 +//  Created by Jens Alfke on 6/15/09.
     5.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    5.10 +//
    5.11 +
    5.12 +#import "MYCertificateInfo.h"
    5.13 +#import "MYCrypto.h"
    5.14 +#import "MYCrypto_Private.h"
    5.15 +
    5.16 +
    5.17 +#if DEBUG
    5.18 +
    5.19 +
    5.20 +static MYCertificateInfo* testCertData(NSData *certData, BOOL selfSigned) {
    5.21 +    //Log(@"Cert Data =\n%@", certData);
    5.22 +    CAssert(certData!=nil);
    5.23 +    NSError *error = nil;
    5.24 +    MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData 
    5.25 +                                                                            error: &error];
    5.26 +    CAssertNil(error);
    5.27 +    CAssert(pcert != nil);
    5.28 +    
    5.29 +    CAssertEq(pcert.isRoot, selfSigned);
    5.30 +        
    5.31 +    MYCertificateName *subject = pcert.subject;
    5.32 +    Log(@"Common Name = %@", subject.commonName);
    5.33 +    Log(@"Given Name  = %@", subject.givenName);
    5.34 +    Log(@"Surname     = %@", subject.surname);
    5.35 +    Log(@"Desc        = %@", subject.nameDescription);
    5.36 +    Log(@"Email       = %@", subject.emailAddress);
    5.37 +    CAssert(subject.commonName);
    5.38 +    
    5.39 +    MYPublicKey *pcertKey = pcert.subjectPublicKey;
    5.40 +    Log(@"Subject Public Key = %@", pcertKey);
    5.41 +    CAssert(pcertKey);
    5.42 +    
    5.43 +    // Now go through MYCertificate:
    5.44 +    Log(@"Creating a MYCertificate from the data...");
    5.45 +    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
    5.46 +    Log(@"MYCertificate = %@", cert);
    5.47 +    CAssert(cert);
    5.48 +    CAssertEqual(cert.info, pcert);
    5.49 +    Log(@"Trust = %@", MYTrustResultDescribe([cert evaluateTrust]));
    5.50 +    
    5.51 +    MYPublicKey *certKey = cert.publicKey;
    5.52 +    Log(@"MYCertificate public key = ", certKey);
    5.53 +    CAssertEqual(certKey.keyData, pcert.subjectPublicKey.keyData);
    5.54 +    [cert release];
    5.55 +    /*TEMP
    5.56 +    Log(@"Adding to keychain...");
    5.57 +    cert = [[MYKeychain defaultKeychain] importCertificate: certData];
    5.58 +    Log(@"Imported as %@", cert);
    5.59 +    //CAssert(cert);
    5.60 +    if (cert) {
    5.61 +        Log(@"Removing from keychain...");
    5.62 +        CAssert([cert removeFromKeychain]);
    5.63 +    }
    5.64 +    */
    5.65 +    return pcert;
    5.66 +}
    5.67 +
    5.68 +static NSData* readTestFile(NSString *filename) {
    5.69 +#if TARGET_OS_IPHONE
    5.70 +    filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"];
    5.71 +#else
    5.72 +    filename = [[@"../../Tests/" stringByAppendingPathComponent: filename]
    5.73 +                stringByAppendingPathExtension: @"cer"];
    5.74 +#endif
    5.75 +    Log(@"--- Testing certificate file %@", filename);
    5.76 +    NSData *data = [NSData dataWithContentsOfFile: filename];
    5.77 +    CAssert(data, @"Couldn't read file %@", filename);
    5.78 +    return data;
    5.79 +}
    5.80 +
    5.81 +static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
    5.82 +    return testCertData(readTestFile(filename), selfSigned);
    5.83 +}
    5.84 +
    5.85 +
    5.86 +TestCase(ParsedCert) {
    5.87 +    testCert(@"selfsigned", YES);
    5.88 +    testCert(@"iphonedev", NO);
    5.89 +    
    5.90 +    // Now test a self-signed cert with a bad signature:
    5.91 +    MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: readTestFile(@"selfsigned_altered")];
    5.92 +    Log(@"MYCertificate = %@", cert);
    5.93 +    CAssertNil(cert);
    5.94 +}
    5.95 +
    5.96 +
    5.97 +#import "MYCrypto_Private.h"
    5.98 +
    5.99 +TestCase(CreateCert) {
   5.100 +    MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512];
   5.101 +    CAssert(privateKey);
   5.102 +    Log(@"---- Generated key-pair with %@, %@", privateKey.publicKey, privateKey);
   5.103 +    MYIdentity *identity = nil;
   5.104 +    @try{
   5.105 +        MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey];
   5.106 +        MYCertificateName *subject = pcert.subject;
   5.107 +        subject.commonName = @"testcase";
   5.108 +        subject.givenName = @"Test";
   5.109 +        subject.surname = @"Case";
   5.110 +        subject.nameDescription = @"Just a test certificate created by MYCrypto";
   5.111 +        subject.emailAddress = @"testcase@example.com";
   5.112 +
   5.113 +        subject = pcert.subject;
   5.114 +        CAssertEqual(subject.commonName, @"testcase");
   5.115 +        CAssertEqual(subject.givenName, @"Test");
   5.116 +        CAssertEqual(subject.surname, @"Case");
   5.117 +        CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto");
   5.118 +        CAssertEqual(subject.emailAddress, @"testcase@example.com");
   5.119 +        
   5.120 +        CAssertEqual(pcert.subjectPublicKey.keyData, privateKey.publicKey.keyData);
   5.121 +        
   5.122 +        Log(@"---- Signing...");
   5.123 +        NSError *error;
   5.124 +        NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error];
   5.125 +        Log(@"Generated cert = \n%@", certData);
   5.126 +        CAssert(certData);
   5.127 +        CAssertNil(error);
   5.128 +        CAssert(certData);
   5.129 +        MYCertificateInfo *pcert2 = testCertData(certData, YES);
   5.130 +        
   5.131 +        Log(@"---- Verifying Info...");
   5.132 +        MYCertificateName *subject2 = pcert2.subject;
   5.133 +        CAssertEqual(subject2,subject);
   5.134 +        CAssertEqual(subject2.commonName, @"testcase");
   5.135 +        CAssertEqual(subject2.givenName, @"Test");
   5.136 +        CAssertEqual(subject2.surname, @"Case");
   5.137 +        CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto");
   5.138 +        CAssertEqual(subject2.emailAddress, @"testcase@example.com");
   5.139 +                
   5.140 +        Log(@"---- Creating MYCertificate object...");
   5.141 +        MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
   5.142 +        Log(@"Loaded %@", cert);
   5.143 +        CAssert(cert);
   5.144 +        MYPublicKey *certKey = cert.publicKey;
   5.145 +        Log(@"Its public key has name %@", certKey.name);//TEMP
   5.146 +        Log(@"Its public key = %@", certKey);
   5.147 +        CAssertEqual(certKey.keyData, privateKey.publicKey.keyData);
   5.148 +        Log(@"X.509 trust = %@", MYTrustResultDescribe([cert evaluateTrust]));
   5.149 +        Log(@"SSL trust = %@", MYTrustResultDescribe([cert evaluateTrustWithPolicy: [MYCertificate SSLPolicy]]));
   5.150 +        
   5.151 +        Log(@"---- Adding cert to keychain...");
   5.152 +        MYCertificate *addedCert = [[MYKeychain defaultKeychain] importCertificate: certData];
   5.153 +        Log(@"Imported as %@", addedCert);
   5.154 +        //CAssert(addedCert);
   5.155 +        if (addedCert)
   5.156 +            CAssert([addedCert removeFromKeychain]);
   5.157 +        
   5.158 +        Log(@"---- Creating Identity...");
   5.159 +        identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error];
   5.160 +        Log(@"Identity = %@", identity);
   5.161 +        CAssert(identity);
   5.162 +        CAssertNil(error);
   5.163 +        CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]);
   5.164 +        CAssertEqual(identity.privateKey.publicKeyDigest, privateKey.publicKeyDigest);
   5.165 +        CAssert([identity isEqualToCertificate: cert]);
   5.166 +        
   5.167 +        [pcert release];
   5.168 +        
   5.169 +    } @finally {
   5.170 +        // [privateKey removeFromKeychain];
   5.171 +        // [identity removeFromKeychain];
   5.172 +        // Currently I'm leaving them in, so the EnumerateXXX tests can chew on them later.
   5.173 +    }
   5.174 +}
   5.175 +
   5.176 +#endif
   5.177 +
   5.178 +
   5.179 +/*
   5.180 + Copyright (c) 2009, Jens Alfke <jens@mooseyard.com>. All rights reserved.
   5.181 + 
   5.182 + Redistribution and use in source and binary forms, with or without modification, are permitted
   5.183 + provided that the following conditions are met:
   5.184 + 
   5.185 + * Redistributions of source code must retain the above copyright notice, this list of conditions
   5.186 + and the following disclaimer.
   5.187 + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
   5.188 + and the following disclaimer in the documentation and/or other materials provided with the
   5.189 + distribution.
   5.190 + 
   5.191 + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
   5.192 + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 
   5.193 + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI-
   5.194 + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   5.195 + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
   5.196 +  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
   5.197 + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
   5.198 + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   5.199 + */
     6.1 --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj	Wed Jun 10 09:02:18 2009 -0700
     6.2 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj	Wed Jul 01 14:19:13 2009 -0700
     6.3 @@ -25,6 +25,7 @@
     6.4  		276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB3180F856AA700CB326E /* MYPublicKey.m */; };
     6.5  		276FB33B0F856ACB00CB326E /* MYKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB33A0F856ACB00CB326E /* MYKeychain.m */; };
     6.6  		276FB34B0F856CA400CB326E /* MYCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB34A0F856CA400CB326E /* MYCertificate.m */; };
     6.7 +		278CA5320FE6A5D600296E91 /* MYCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278CA5310FE6A5D600296E91 /* MYCertificateTest.m */; };
     6.8  		27958CA30FDB5F8F00095275 /* iphonedev.cer in Resources */ = {isa = PBXBuildFile; fileRef = 27958CA10FDB5F8F00095275 /* iphonedev.cer */; };
     6.9  		27958CA40FDB5F8F00095275 /* selfsigned.cer in Resources */ = {isa = PBXBuildFile; fileRef = 27958CA20FDB5F8F00095275 /* selfsigned.cer */; };
    6.10  		27A430120F87C6C10063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823110F81D56E0019BE60 /* MYKey.m */; };
    6.11 @@ -54,6 +55,8 @@
    6.12  		1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
    6.13  		27059CF10F8F0F8E00A8422F /* MYIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYIdentity.h; sourceTree = "<group>"; };
    6.14  		27059CF20F8F0F9200A8422F /* MYIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYIdentity.m; sourceTree = "<group>"; };
    6.15 +		2726AF890FE19BE8006C55F7 /* MYCrypto_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCrypto_Prefix.pch; sourceTree = "<group>"; };
    6.16 +		2726AF910FE19C5A006C55F7 /* MYUtilities_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MYUtilities_Prefix.pch; path = ../MYUtilities/MYUtilities_Prefix.pch; sourceTree = SOURCE_ROOT; };
    6.17  		273392110F8283B8009414D9 /* MYKeychain-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYKeychain-iPhone.m"; sourceTree = "<group>"; };
    6.18  		274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYSymmetricKey-iPhone.m"; sourceTree = "<group>"; };
    6.19  		2748607D0F8D5DF200FE617B /* MYPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPrivateKey.h; sourceTree = "<group>"; };
    6.20 @@ -72,6 +75,7 @@
    6.21  		276FB3180F856AA700CB326E /* MYPublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPublicKey.m; sourceTree = "<group>"; };
    6.22  		276FB33A0F856ACB00CB326E /* MYKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeychain.m; sourceTree = "<group>"; };
    6.23  		276FB34A0F856CA400CB326E /* MYCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificate.m; sourceTree = "<group>"; };
    6.24 +		278CA5310FE6A5D600296E91 /* MYCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificateTest.m; sourceTree = "<group>"; };
    6.25  		27958CA10FDB5F8F00095275 /* iphonedev.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = iphonedev.cer; path = Tests/iphonedev.cer; sourceTree = "<group>"; };
    6.26  		27958CA20FDB5F8F00095275 /* selfsigned.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = selfsigned.cer; path = Tests/selfsigned.cer; sourceTree = "<group>"; };
    6.27  		27A430130F87C6D50063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
    6.28 @@ -151,6 +155,7 @@
    6.29  			children = (
    6.30  				27CD85DB0FDB1A7D006BCB47 /* MYCertificateInfo.h */,
    6.31  				27CD85DC0FDB1A82006BCB47 /* MYCertificateInfo.m */,
    6.32 +				278CA5310FE6A5D600296E91 /* MYCertificateTest.m */,
    6.33  				275D9FE50FD8795300D85A86 /* MYASN1Object.h */,
    6.34  				275D9FE60FD8795300D85A86 /* MYASN1Object.m */,
    6.35  				275D9FE70FD8795300D85A86 /* MYBERParser.h */,
    6.36 @@ -202,6 +207,8 @@
    6.37  				27E8231C0F81D56E0019BE60 /* MYDigest.m */,
    6.38  				27E8231A0F81D56E0019BE60 /* MYCrypto_Private.h */,
    6.39  				276FB16D0F84152B00CB326E /* MYCryptoTest.m */,
    6.40 +				2726AF890FE19BE8006C55F7 /* MYCrypto_Prefix.pch */,
    6.41 +				2726AF910FE19C5A006C55F7 /* MYUtilities_Prefix.pch */,
    6.42  				27E8231E0F81D56E0019BE60 /* MYCrypto.xcconfig */,
    6.43  				27E8231F0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig */,
    6.44  			);
    6.45 @@ -336,6 +343,7 @@
    6.46  				275D9FF10FD8795300D85A86 /* MYDEREncoder.m in Sources */,
    6.47  				275D9FF20FD8795300D85A86 /* MYOID.m in Sources */,
    6.48  				27CD85DD0FDB1A82006BCB47 /* MYCertificateInfo.m in Sources */,
    6.49 +				278CA5320FE6A5D600296E91 /* MYCertificateTest.m in Sources */,
    6.50  			);
    6.51  			runOnlyForDeploymentPostprocessing = 0;
    6.52  		};
    6.53 @@ -351,7 +359,7 @@
    6.54  				GCC_DYNAMIC_NO_PIC = NO;
    6.55  				GCC_OPTIMIZATION_LEVEL = 0;
    6.56  				GCC_PRECOMPILE_PREFIX_HEADER = YES;
    6.57 -				GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch;
    6.58 +				GCC_PREFIX_HEADER = MYCrypto_Prefix.pch;
    6.59  				INFOPLIST_FILE = "iPhone/MYCrypto_iPhone-Info.plist";
    6.60  				PRODUCT_NAME = "MYCrypto-iPhone";
    6.61  			};
    6.62 @@ -364,7 +372,7 @@
    6.63  				ALWAYS_SEARCH_USER_PATHS = NO;
    6.64  				COPY_PHASE_STRIP = YES;
    6.65  				GCC_PRECOMPILE_PREFIX_HEADER = YES;
    6.66 -				GCC_PREFIX_HEADER = MYCrypto_iPhone_Prefix.pch;
    6.67 +				GCC_PREFIX_HEADER = MYCrypto_Prefix.pch;
    6.68  				INFOPLIST_FILE = "MYCrypto_iPhone-Info.plist";
    6.69  				PRODUCT_NAME = "MYCrypto-iPhone";
    6.70  			};
     7.1 --- a/MYCrypto.xcodeproj/project.pbxproj	Wed Jun 10 09:02:18 2009 -0700
     7.2 +++ b/MYCrypto.xcodeproj/project.pbxproj	Wed Jul 01 14:19:13 2009 -0700
     7.3 @@ -43,6 +43,8 @@
     7.4  		270A7A740FD58FF200770C4D /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 270A7A720FD58FF200770C4D /* MYBERParser.m */; };
     7.5  		270A7A750FD58FF200770C4D /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 270A7A720FD58FF200770C4D /* MYBERParser.m */; };
     7.6  		270B879F0F8C565000C56781 /* MYPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 270B879E0F8C565000C56781 /* MYPrivateKey.m */; };
     7.7 +		27205C440FF2D88200C5E25B /* MYCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27205C430FF2D88200C5E25B /* MYCertificateTest.m */; };
     7.8 +		27205C450FF2D88200C5E25B /* MYCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27205C430FF2D88200C5E25B /* MYCertificateTest.m */; };
     7.9  		27410FF00F99200A00AD413F /* MYSymmetricKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 27410FEF0F99200A00AD413F /* MYSymmetricKey-iPhone.m */; };
    7.10  		274863A20F8EF39400FE617B /* MYIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 274863A10F8EF39400FE617B /* MYIdentity.m */; };
    7.11  		275DA1270FD980D400D85A86 /* MYCertificateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 275DA1250FD980D400D85A86 /* MYCertificateInfo.h */; };
    7.12 @@ -104,6 +106,7 @@
    7.13  		270A7A720FD58FF200770C4D /* MYBERParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBERParser.m; sourceTree = "<group>"; };
    7.14  		270B879D0F8C565000C56781 /* MYPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPrivateKey.h; sourceTree = "<group>"; };
    7.15  		270B879E0F8C565000C56781 /* MYPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPrivateKey.m; sourceTree = "<group>"; };
    7.16 +		27205C430FF2D88200C5E25B /* MYCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificateTest.m; sourceTree = "<group>"; };
    7.17  		27410FEF0F99200A00AD413F /* MYSymmetricKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYSymmetricKey-iPhone.m"; sourceTree = "<group>"; };
    7.18  		2748604D0F8D5C4C00FE617B /* MYCrypto_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYCrypto_Release.xcconfig; sourceTree = "<group>"; };
    7.19  		274863A00F8EF39400FE617B /* MYIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYIdentity.h; sourceTree = "<group>"; };
    7.20 @@ -275,6 +278,7 @@
    7.21  			children = (
    7.22  				275DA1250FD980D400D85A86 /* MYCertificateInfo.h */,
    7.23  				275DA1260FD980D400D85A86 /* MYCertificateInfo.m */,
    7.24 +				27205C430FF2D88200C5E25B /* MYCertificateTest.m */,
    7.25  				27B852F30FCF4EB6005631F9 /* MYASN1Object.h */,
    7.26  				27B852F40FCF4EB7005631F9 /* MYASN1Object.m */,
    7.27  				270A7A710FD58FF200770C4D /* MYBERParser.h */,
    7.28 @@ -440,6 +444,7 @@
    7.29  				27B855280FD077A7005631F9 /* MYDEREncoder.m in Sources */,
    7.30  				270A7A740FD58FF200770C4D /* MYBERParser.m in Sources */,
    7.31  				275DA1280FD980D400D85A86 /* MYCertificateInfo.m in Sources */,
    7.32 +				27205C440FF2D88200C5E25B /* MYCertificateTest.m in Sources */,
    7.33  			);
    7.34  			runOnlyForDeploymentPostprocessing = 0;
    7.35  		};
    7.36 @@ -473,6 +478,7 @@
    7.37  				27B855290FD077A7005631F9 /* MYDEREncoder.m in Sources */,
    7.38  				270A7A750FD58FF200770C4D /* MYBERParser.m in Sources */,
    7.39  				275DA1290FD980D400D85A86 /* MYCertificateInfo.m in Sources */,
    7.40 +				27205C450FF2D88200C5E25B /* MYCertificateTest.m in Sources */,
    7.41  			);
    7.42  			runOnlyForDeploymentPostprocessing = 0;
    7.43  		};
     8.1 --- a/MYCryptoTest.m	Wed Jun 10 09:02:18 2009 -0700
     8.2 +++ b/MYCryptoTest.m	Wed Jul 01 14:19:13 2009 -0700
     8.3 @@ -43,6 +43,16 @@
     8.4  }
     8.5  
     8.6  
     8.7 +#if MYCRYPTO_USE_IPHONE_API
     8.8 +TestCase(RemoveAll) {
     8.9 +    RequireTestCase(MYKeychain);
    8.10 +    MYKeychain *kc = [MYKeychain defaultKeychain];
    8.11 +    CAssert([kc removeAllCertificates]);
    8.12 +    CAssert([kc removeAllKeys]);
    8.13 +}
    8.14 +#endif
    8.15 +
    8.16 +
    8.17  TestCase(Enumerate) {
    8.18      RequireTestCase(EnumeratePublicKeys);
    8.19      RequireTestCase(EnumeratePrivateKeys);
    8.20 @@ -95,8 +105,26 @@
    8.21      Log(@"Enumerator = %@", e);
    8.22      CAssert(e);
    8.23      for (MYCertificate *cert in e) {
    8.24 -        Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses);
    8.25 +        Log(@"Found %@ -- key=%@, name=%@, email=%@", cert,
    8.26 +            cert.publicKey, cert.commonName, cert.emailAddresses);
    8.27          CAssert(cert.publicKey);
    8.28 +        
    8.29 +#if MYCRYPTO_USE_IPHONE_API
    8.30 +        // Verify that cert has public-key-hash attribute:
    8.31 +        NSData *digestData = [MYKeychainItem _getAttribute: kSecAttrPublicKeyHash 
    8.32 +                                                    ofItem: cert.certificateRef];
    8.33 +        CAssert(digestData, @"SecCertificateRef missing kSecAttrPublicKeyHash");
    8.34 +        MYSHA1Digest *digest = [MYSHA1Digest digestFromDigestData: digestData];
    8.35 +        CAssertEqual(digest, cert.publicKey.publicKeyDigest);
    8.36 +        Log(@"kSecAttrPublicKeyHash matches: %@", digest);
    8.37 +#else
    8.38 +        MYSHA1Digest *digest = cert.publicKey.publicKeyDigest;
    8.39 +#endif
    8.40 +        // Verify that certificateWithDigest will find it:
    8.41 +        MYCertificate *cert2 = [[MYKeychain allKeychains] certificateWithDigest: digest];
    8.42 +        Log(@"certificateWithDigest(%@) returned %@", digest,cert2);
    8.43 +        CAssert(cert2);
    8.44 +        CAssertEqual(cert2.certificateData, cert.certificateData);
    8.45      }
    8.46  }
    8.47  
    8.48 @@ -108,12 +136,15 @@
    8.49      for (MYIdentity *ident in e) {
    8.50          Log(@"Found %@\n\tcommonName=%@\n\temails=(%@)\n\tkey=%@",
    8.51              ident, ident.commonName, 
    8.52 -#if TARGET_OS_IPHONE
    8.53 -            nil,
    8.54 -#else
    8.55              [ident.emailAddresses componentsJoinedByString: @", "],
    8.56 -#endif
    8.57              ident.privateKey);
    8.58 +        
    8.59 +        // Verify that identityWithDigest will find it:
    8.60 +        MYSHA1Digest *digest = ident.publicKey.publicKeyDigest;
    8.61 +        MYIdentity *ident2 = [[MYKeychain allKeychains] identityWithDigest:digest];
    8.62 +        Log(@"identityWithDigest(%@) returned %@", digest,ident2);
    8.63 +        CAssert(ident2);
    8.64 +        CAssertEqual(ident2.certificateData, ident.certificateData);
    8.65      }
    8.66  }
    8.67  
    8.68 @@ -177,7 +208,6 @@
    8.69      #endif
    8.70  
    8.71      #if !TARGET_OS_IPHONE
    8.72 -#if 1 // TEMP-ORARILY OUT OF ORDER
    8.73          // Try exporting and importing a wrapped key:
    8.74          Log(@"Testing export/import...");
    8.75          NSData *exported = [key exportWrappedKeyWithPassphrasePrompt: @"Export symmetric key with passphrase:"];
    8.76 @@ -197,7 +227,6 @@
    8.77              decrypted = [key2 decryptData: encrypted];
    8.78              CAssertEqual(decrypted, cleartext);
    8.79          }
    8.80 -#endif 0
    8.81      #endif
    8.82      }@finally{
    8.83          [key removeFromKeychain];
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/MYCrypto_Prefix.pch	Wed Jul 01 14:19:13 2009 -0700
     9.3 @@ -0,0 +1,11 @@
     9.4 +//
     9.5 +//  MYCrypto_Prefix.h
     9.6 +//  MYCrypto-iPhone
     9.7 +//
     9.8 +//  Created by Jens Alfke on 6/11/09.
     9.9 +//  Copyright 2009 Jens Alfke. All rights reserved.
    9.10 +//
    9.11 +
    9.12 +#define USE_SECURITY_API 1      /* tells MYErrorUtils it can call Security to look up error names */
    9.13 +
    9.14 +#import "MYUtilities_Prefix.pch"
    10.1 --- a/MYCrypto_Private.h	Wed Jun 10 09:02:18 2009 -0700
    10.2 +++ b/MYCrypto_Private.h	Wed Jul 01 14:19:13 2009 -0700
    10.3 @@ -13,6 +13,8 @@
    10.4  #import "MYPublicKey.h"
    10.5  #import "MYPrivateKey.h"
    10.6  #import "MYCertificate.h"
    10.7 +#import "MYCertificateInfo.h"
    10.8 +
    10.9  #import "Test.h"
   10.10  #import <Security/Security.h>
   10.11  
   10.12 @@ -33,6 +35,9 @@
   10.13  @property (readonly) CSSM_CSP_HANDLE CSPHandle;
   10.14  @property (readonly) NSString* path;
   10.15  #endif
   10.16 +#if MYCRYPTO_USE_IPHONE_API
   10.17 ++ (CFTypeRef) _addItemWithInfo: (NSMutableDictionary*)info;
   10.18 +#endif
   10.19  @end
   10.20  
   10.21  
   10.22 @@ -56,9 +61,7 @@
   10.23  @property (readonly) SecExternalItemType keyClass, keyType;
   10.24  @property (readonly) MYSHA1Digest* _keyDigest;
   10.25  - (NSData*) _crypt: (NSData *)data operation: (BOOL) op;    // YES to encrypt, NO to decrypt
   10.26 -#if MYCRYPTO_USE_IPHONE_API
   10.27 -+ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info;
   10.28 -#else
   10.29 +#if !MYCRYPTO_USE_IPHONE_API
   10.30  @property (readonly) const CSSM_KEY* cssmKey;
   10.31  @property (readonly) const CSSM_CSP_HANDLE cssmCSPHandle;
   10.32  - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm;
   10.33 @@ -79,6 +82,7 @@
   10.34  
   10.35  
   10.36  @interface MYPublicKey (Private)
   10.37 +@property (retain) MYCertificate *certificate;
   10.38  - (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr;
   10.39  #if !TARGET_OS_IPHONE
   10.40  - (CSSM_WRAP_KEY*) _unwrappedCSSMKey;
   10.41 @@ -117,6 +121,15 @@
   10.42  #endif
   10.43  
   10.44  
   10.45 +@interface MYCertificateInfo (Private)
   10.46 +- (NSData*) subjectPublicKeyData;
   10.47 +- (MYPublicKey*) subjectPublicKey;
   10.48 +- (NSData*) signedData;
   10.49 +- (MYOID*) signatureAlgorithmID;
   10.50 +- (NSData*) signature;
   10.51 +@end                    
   10.52 +
   10.53 +
   10.54  #undef check
   10.55  BOOL check(OSStatus err, NSString *what);
   10.56  
    11.1 --- a/MYDigest.h	Wed Jun 10 09:02:18 2009 -0700
    11.2 +++ b/MYDigest.h	Wed Jul 01 14:19:13 2009 -0700
    11.3 @@ -63,6 +63,9 @@
    11.4  /** The length of digests created by this subclass. (Abstract method.) */
    11.5  + (size_t) length;
    11.6  
    11.7 +/** Byte-by-byte lexical comparison of digest data. */
    11.8 +- (NSComparisonResult) compare: (MYDigest*)other;
    11.9 +
   11.10  /** Primitive digest generation method. (Abstract.) */
   11.11  + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length;
   11.12  
    12.1 --- a/MYIdentity.m	Wed Jun 10 09:02:18 2009 -0700
    12.2 +++ b/MYIdentity.m	Wed Jul 01 14:19:13 2009 -0700
    12.3 @@ -8,6 +8,7 @@
    12.4  
    12.5  #import "MYIdentity.h"
    12.6  #import "MYCrypto_Private.h"
    12.7 +#import "MYDigest.h"
    12.8  
    12.9  
   12.10  @implementation MYIdentity
   12.11 @@ -45,7 +46,28 @@
   12.12              return nil;
   12.13          }
   12.14  #else
   12.15 -        Assert(NO,@"-[MYIdentity initWithCertificateRef] isn't implemented for iPhone yet!");//FIX
   12.16 +        MYSHA1Digest *keyDigest = self.publicKey.publicKeyDigest;
   12.17 +        if (!keyDigest) {
   12.18 +            Warn(@"MYIdentity: Couldn't get key digest of cert %@",certificateRef);
   12.19 +            [self release];
   12.20 +            return nil;
   12.21 +        }
   12.22 +        _identityRef = [self.keychain identityWithDigest: keyDigest].identityRef;
   12.23 +        if (!_identityRef) {
   12.24 +            Warn(@"MYIdentity: Couldn't look up identity for cert %@ with %@",certificateRef, keyDigest);
   12.25 +            [self release];
   12.26 +            return nil;
   12.27 +        }
   12.28 +        
   12.29 +        // Debugging: Make sure the cert is correct
   12.30 +        SecCertificateRef identitysCert = NULL;
   12.31 +        SecIdentityCopyCertificate(_identityRef, &identitysCert);
   12.32 +        CFDataRef identitysData = SecCertificateCopyData(identitysCert);
   12.33 +        AssertEqual(self.certificateData, (NSData*)identitysData);
   12.34 +        CFRelease(identitysData);
   12.35 +        CFRelease(identitysCert);
   12.36 +        
   12.37 +        CFRetain(_identityRef);
   12.38  #endif
   12.39      }
   12.40      return self;
   12.41 @@ -77,6 +99,11 @@
   12.42  }
   12.43  
   12.44  
   12.45 +- (BOOL) removeFromKeychain {
   12.46 +    return [self.privateKey removeFromKeychain] && [super removeFromKeychain];
   12.47 +}
   12.48 +
   12.49 +
   12.50  #if !TARGET_OS_IPHONE
   12.51  
   12.52  + (MYIdentity*) preferredIdentityForName: (NSString*)name
    13.1 --- a/MYKey-iPhone.m	Wed Jun 10 09:02:18 2009 -0700
    13.2 +++ b/MYKey-iPhone.m	Wed Jul 01 14:19:13 2009 -0700
    13.3 @@ -19,45 +19,6 @@
    13.4  @implementation MYKey
    13.5  
    13.6  
    13.7 -+ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info {
    13.8 -    if (![info objectForKey: (id)kSecAttrApplicationTag]) {
    13.9 -        // Every keychain item has to have a unique tag, apparently, or you'll get spurious
   13.10 -        // duplicate-item errors. If none was given, make up a random one:
   13.11 -        UInt8 tag[16];
   13.12 -        Assert(check(SecRandomCopyBytes(kSecRandomDefault, sizeof(tag), tag), @"SecRandomCopyBytes"));
   13.13 -        [info setObject: [NSData dataWithBytes: tag length: sizeof(tag)] 
   13.14 -                 forKey: (id)kSecAttrApplicationTag];
   13.15 -    }
   13.16 -    CFDataRef keyPersistentRef;
   13.17 -    SecKeyRef key;
   13.18 -    OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&keyPersistentRef);
   13.19 -    if (err==errSecDuplicateItem) {
   13.20 -        // it's already in the keychain -- get a reference to it:
   13.21 -		[info removeObjectForKey: (id)kSecReturnPersistentRef];
   13.22 -		[info setObject: $true forKey: (id)kSecReturnRef];
   13.23 -		if (check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key), 
   13.24 -                   @"SecItemCopyMatching"))
   13.25 -            return key;
   13.26 -    } else if (check(err, @"SecItemAdd")) {
   13.27 -        // It was added
   13.28 -        if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) {
   13.29 -            // now get its SecKeyRef:
   13.30 -            info = $mdict({(id)kSecValuePersistentRef, (id)keyPersistentRef},
   13.31 -                          {(id)kSecReturnRef, $true});
   13.32 -            err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key);
   13.33 -            CFRelease(keyPersistentRef);
   13.34 -            if (check(err,@"SecItemCopyMatching")) {
   13.35 -                Assert(key!=nil);
   13.36 -                return key;
   13.37 -            }
   13.38 -        } else {
   13.39 -            return (SecKeyRef)keyPersistentRef;
   13.40 -        }
   13.41 -    }
   13.42 -    return NULL;
   13.43 -}
   13.44 -
   13.45 -
   13.46  - (id) initWithKeyRef: (SecKeyRef)key {
   13.47      return [self initWithKeychainItemRef: (SecKeychainItemRef)key];
   13.48  }
   13.49 @@ -70,8 +31,8 @@
   13.50                                          {(id)kSecAttrKeyType, (id)self.keyType},
   13.51                                          {(id)kSecValueData, data},
   13.52                                          {(id)kSecAttrIsPermanent, (keychain ?$true :$false)},
   13.53 -                                        {(id)kSecReturnPersistentRef, $true} );
   13.54 -    SecKeyRef key = [[self class] _addKeyWithInfo: info];
   13.55 +                                        {(id)kSecReturnPersistentRef, (keychain ?$true :$false)} );
   13.56 +    SecKeyRef key = (SecKeyRef)[MYKeychain _addItemWithInfo: info];
   13.57      if (!key) {
   13.58          [self release];
   13.59          return nil;
   13.60 @@ -80,6 +41,9 @@
   13.61      if (self) {
   13.62          if (!keychain)
   13.63              _keyData = [data copy];
   13.64 +        
   13.65 +        //TEMP For debugging:
   13.66 +        AssertEqual(self.keyData, data);
   13.67      }
   13.68      return self;
   13.69  }
   13.70 @@ -95,6 +59,19 @@
   13.71  }
   13.72  
   13.73  
   13.74 +/*- (NSData*) persistentRef {
   13.75 +    NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
   13.76 +                              //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
   13.77 +                                {(id)kSecReturnPersistentRef, $true} );
   13.78 +    CFDataRef data;
   13.79 +    if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
   13.80 +        return nil;
   13.81 +    if (!data)
   13.82 +        Warn(@"MYKey persistentRef couldn't get ref");
   13.83 +    return [NSMakeCollectable(data) autorelease];
   13.84 +}*/
   13.85 +
   13.86 +
   13.87  - (SecExternalItemType) keyClass {
   13.88      AssertAbstractMethod();
   13.89  }
   13.90 @@ -108,11 +85,13 @@
   13.91          return _keyData;
   13.92      
   13.93      NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
   13.94 +                              //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
   13.95                                  {(id)kSecReturnData, $true} );
   13.96      CFDataRef data;
   13.97 -    if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
   13.98 +    if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching")) {
   13.99 +        Log(@"SecItemCopyMatching failed; input = %@", info);
  13.100          return nil;
  13.101 -    else {
  13.102 +    } else {
  13.103          Assert(data!=NULL);
  13.104          _keyData = NSMakeCollectable(data);
  13.105          return _keyData;
  13.106 @@ -134,11 +113,11 @@
  13.107  
  13.108  - (id) _attribute: (CFTypeRef)attribute {
  13.109      NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef},
  13.110 +            {(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)},
  13.111                                 {(id)kSecReturnAttributes, $true});
  13.112      CFDictionaryRef attrs = NULL;
  13.113      if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
  13.114          return nil;
  13.115 -    Log(@"_attribute: %@ of %@ %p", attribute, [self class], self.keyRef);//TEMP
  13.116      CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
  13.117      id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
  13.118      CFRelease(attrs);
    14.1 --- a/MYKey.h	Wed Jun 10 09:02:18 2009 -0700
    14.2 +++ b/MYKey.h	Wed Jul 01 14:19:13 2009 -0700
    14.3 @@ -39,6 +39,9 @@
    14.4  /** The key's raw data. */
    14.5  @property (readonly) NSData *keyData;
    14.6  
    14.7 +/** The key's size/length, in bits. */
    14.8 +@property (readonly) unsigned keySizeInBits;
    14.9 +
   14.10  /** The user-visible name (kSecKeyPrintName) associated with this key in the Keychain.
   14.11      The user can edit this, so don't expect it to be immutable. */
   14.12  @property (copy) NSString *name;
    15.1 --- a/MYKey.m	Wed Jun 10 09:02:18 2009 -0700
    15.2 +++ b/MYKey.m	Wed Jul 01 14:19:13 2009 -0700
    15.3 @@ -33,6 +33,12 @@
    15.4      }
    15.5      self = [self initWithKeyRef: key];
    15.6      CFRelease(key);
    15.7 +    if (self) {
    15.8 +#if MYCRYPTO_USE_IPHONE_API
    15.9 +        if (!keychain)
   15.10 +            self.isPersistent = NO;
   15.11 +#endif
   15.12 +    }
   15.13      return self;
   15.14  }
   15.15  
   15.16 @@ -104,6 +110,12 @@
   15.17          return nil;
   15.18  }
   15.19  
   15.20 +- (unsigned) keySizeInBits {
   15.21 +    const CSSM_KEY *key = self.cssmKey;
   15.22 +    Assert(key);
   15.23 +    return key->KeyHeader.LogicalKeySizeInBits;
   15.24 +}
   15.25 +
   15.26  - (NSString*) name {
   15.27      return [self stringValueOfAttribute: kSecKeyPrintName];
   15.28  }
    16.1 --- a/MYKeychain-iPhone.m	Wed Jun 10 09:02:18 2009 -0700
    16.2 +++ b/MYKeychain-iPhone.m	Wed Jul 01 14:19:13 2009 -0700
    16.3 @@ -14,6 +14,20 @@
    16.4  #if MYCRYPTO_USE_IPHONE_API
    16.5  
    16.6  
    16.7 +// from cssmtype.h:
    16.8 +enum {
    16.9 +    CSSM_CERT_UNKNOWN =					0x00,
   16.10 +    CSSM_CERT_X_509v1 =					0x01,
   16.11 +    CSSM_CERT_X_509v2 =					0x02,
   16.12 +    CSSM_CERT_X_509v3 =					0x03,
   16.13 +
   16.14 +    CSSM_CERT_ENCODING_UNKNOWN =		0x00,
   16.15 +    CSSM_CERT_ENCODING_CUSTOM =			0x01,
   16.16 +    CSSM_CERT_ENCODING_BER =			0x02,
   16.17 +    CSSM_CERT_ENCODING_DER =			0x03,
   16.18 +};
   16.19 +
   16.20 +
   16.21  @interface MYKeyEnumerator : NSEnumerator
   16.22  {
   16.23      CFArrayRef _results;
   16.24 @@ -98,7 +112,7 @@
   16.25  - (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest {
   16.26      return [MYKeyEnumerator firstItemWithQuery:
   16.27                  $mdict({(id)kSecClass, (id)kSecClassIdentity},
   16.28 -                        {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})];
   16.29 +                       {(id)kSecAttrApplicationLabel/*kSecAttrPublicKeyHash*/, pubKeyDigest.asData})];
   16.30  }
   16.31  
   16.32  - (NSEnumerator*) enumerateIdentities {
   16.33 @@ -122,6 +136,50 @@
   16.34  #pragma mark IMPORT:
   16.35  
   16.36  
   16.37 ++ (CFTypeRef) _addItemWithInfo: (NSMutableDictionary*)info {
   16.38 +    // Generally SecItemAdd will fail (return paramErr) if asked to return a regular ref.
   16.39 +    // As a workaround ask for a persistent ref instead, then convert that to regular ref.
   16.40 +    if (![[info objectForKey: (id)kSecReturnRef] boolValue])
   16.41 +        [info setObject: $true forKey: (id)kSecReturnPersistentRef];
   16.42 +    
   16.43 +    CFDataRef itemPersistentRef;
   16.44 +    CFTypeRef item;
   16.45 +    OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&itemPersistentRef);
   16.46 +    if (err==errSecDuplicateItem) {
   16.47 +        Log(@"_addItemWithInfo: Keychain claims it's a dup, so look for existing item");
   16.48 +        // it's already in the keychain -- get a reference to it:
   16.49 +		[info removeObjectForKey: (id)kSecReturnPersistentRef];
   16.50 +		[info setObject: $true forKey: (id)kSecReturnRef];
   16.51 +		if (check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&item), 
   16.52 +                  @"SecItemCopyMatching")) {
   16.53 +            if (!item)
   16.54 +                Warn(@"_addItemWithInfo: Couldn't find supposedly-duplicate item, info=%@",info);
   16.55 +            Log(@"_addItemWithInfo: SecItemAdd found item; ref=%@", item);//TEMP
   16.56 +            return item;
   16.57 +        }
   16.58 +    } else if (check(err, @"SecItemAdd")) {
   16.59 +        // It was added
   16.60 +        if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) {
   16.61 +            // now get its item ref:
   16.62 +            Log(@"SecItemAdd added item; persistenRef=%@", itemPersistentRef);//TEMP
   16.63 +            info = $mdict({(id)kSecValuePersistentRef, (id)itemPersistentRef},
   16.64 +            {(id)kSecReturnRef, $true});
   16.65 +            err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&item);
   16.66 +            CFRelease(itemPersistentRef);
   16.67 +            if (check(err,@"SecItemCopyMatching")) {
   16.68 +                Assert(item!=nil);
   16.69 +                return item;
   16.70 +            }
   16.71 +        } else {
   16.72 +            Log(@"SecItemAdd added item; ref=%@", itemPersistentRef);//TEMP
   16.73 +            return (CFTypeRef)itemPersistentRef;
   16.74 +        }
   16.75 +    }
   16.76 +    Log(@"SecItemAdd failed: info = %@", info); // for help in debugging, dump the input dict
   16.77 +    return NULL;
   16.78 +}
   16.79 +
   16.80 +
   16.81  - (MYPublicKey*) importPublicKey: (NSData*)keyData {
   16.82      return [[[MYPublicKey alloc] _initWithKeyData: keyData 
   16.83                                        forKeychain: self]
   16.84 @@ -131,13 +189,25 @@
   16.85  - (MYCertificate*) importCertificate: (NSData*)data
   16.86  {
   16.87      Assert(data);
   16.88 -    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassCertificate},
   16.89 -                                {(id)kSecValueData, data},
   16.90 -                                {(id)kSecReturnRef, $true} );
   16.91 -    SecCertificateRef cert;
   16.92 -    if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&cert), @"SecItemAdd"))
   16.93 +    
   16.94 +#if 1
   16.95 +    SecCertificateRef cert0 = SecCertificateCreateWithData(NULL, (CFDataRef)data);
   16.96 +    if (!cert0)
   16.97          return nil;
   16.98 -    return [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
   16.99 +    NSMutableDictionary *info = $mdict( {(id)kSecClass, (id)kSecClassCertificate},
  16.100 +                                        {(id)kSecValueRef, (id)cert0});
  16.101 +#else
  16.102 +    NSMutableDictionary *info = $mdict( {(id)kSecClass, (id)kSecClassCertificate},
  16.103 +                                        {(id)kSecAttrCertificateType, $object(CSSM_CERT_X_509v3)},
  16.104 +                                        {(id)kSecAttrCertificateEncoding, $object(CSSM_CERT_ENCODING_BER)},
  16.105 +                                        {(id)kSecValueData, data} );
  16.106 +#endif
  16.107 +    SecCertificateRef cert = (SecCertificateRef) [[self class] _addItemWithInfo: info];
  16.108 +    if (!cert)
  16.109 +        return nil;
  16.110 +    MYCertificate *myCert = [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease];
  16.111 +    AssertEqual(data, myCert.certificateData);  //TEMP for debugging
  16.112 +    return myCert;
  16.113  }
  16.114  
  16.115  
  16.116 @@ -157,6 +227,21 @@
  16.117  }
  16.118  
  16.119  
  16.120 +#pragma mark -
  16.121 +#pragma mark REMOVING:
  16.122 +
  16.123 +
  16.124 +- (BOOL) removeAllCertificates {
  16.125 +    NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassCertificate});
  16.126 +    return check(SecItemDelete((CFDictionaryRef)query),  @"SecItemDelete");
  16.127 +}
  16.128 +
  16.129 +- (BOOL) removeAllKeys {
  16.130 +    NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassKey});
  16.131 +    return check(SecItemDelete((CFDictionaryRef)query), @"SecItemDelete");
  16.132 +}
  16.133 +
  16.134 +
  16.135  @end
  16.136  
  16.137  
  16.138 @@ -190,7 +275,7 @@
  16.139              [self release];
  16.140              return nil;
  16.141          }
  16.142 -        Log(@"Enumerator results = %@", _results);//TEMP
  16.143 +        //Log(@"Enumerator results = %@", _results);
  16.144          
  16.145          if (_results && CFEqual(limit,kSecMatchLimitOne)) {
  16.146              // If you ask for only one, it gives you the object back instead of an array:
  16.147 @@ -225,7 +310,7 @@
  16.148      // when you try to use them for anything. As a workaround, detect these early on before
  16.149      // even creating a MYPublicKey:
  16.150      NSDictionary *info = $dict({(id)kSecValueRef, (id)itemRef},
  16.151 -    {(id)kSecReturnAttributes, $true});
  16.152 +                               {(id)kSecReturnAttributes, $true});
  16.153      CFDictionaryRef attrs = NULL;
  16.154      OSStatus err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs);
  16.155      if (attrs) CFRelease(attrs);
    17.1 --- a/MYKeychain.h	Wed Jun 10 09:02:18 2009 -0700
    17.2 +++ b/MYKeychain.h	Wed Jul 01 14:19:13 2009 -0700
    17.3 @@ -113,6 +113,8 @@
    17.4  /** Enumerates all public keys in the keychain that have the given alias string. */
    17.5  - (NSEnumerator*) publicKeysWithAlias: (NSString*)alias;
    17.6  
    17.7 +- (NSEnumerator*) enumerateIdentitiesWithKeyUsage: (CSSM_KEYUSE)keyUsage;
    17.8 +
    17.9  /** Imports a key-pair into the keychain, given the external representations
   17.10      of both the public and private keys.
   17.11      Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter
   17.12 @@ -138,6 +140,16 @@
   17.13                              encoding: (CSSM_CERT_ENCODING) encoding;
   17.14  
   17.15  //@}
   17.16 +#else
   17.17 +/** @name iPhone-Only
   17.18 + *  Functionality only available on iPhone. 
   17.19 + */
   17.20 +//@{
   17.21 +
   17.22 +- (BOOL) removeAllCertificates;
   17.23 +- (BOOL) removeAllKeys;
   17.24 +
   17.25 +//@}
   17.26  #endif
   17.27  
   17.28  
    18.1 --- a/MYKeychain.m	Wed Jun 10 09:02:18 2009 -0700
    18.2 +++ b/MYKeychain.m	Wed Jul 01 14:19:13 2009 -0700
    18.3 @@ -36,7 +36,7 @@
    18.4      SecIdentitySearchRef _searchRef;
    18.5  }
    18.6  
    18.7 -- (id) initWithKeychain: (MYKeychain*)keychain;
    18.8 +- (id) initWithKeychain: (MYKeychain*)keychain keyUsage: (CSSM_KEYUSE)keyUsage;
    18.9  @end
   18.10  
   18.11  
   18.12 @@ -269,7 +269,11 @@
   18.13  }
   18.14  
   18.15  - (NSEnumerator*) enumerateIdentities {
   18.16 -    return [[[MYIdentityEnumerator alloc] initWithKeychain: self] autorelease];
   18.17 +    return [self enumerateIdentitiesWithKeyUsage: 0];
   18.18 +}
   18.19 +
   18.20 +- (NSEnumerator*) enumerateIdentitiesWithKeyUsage: (CSSM_KEYUSE)keyUsage {
   18.21 +    return [[[MYIdentityEnumerator alloc] initWithKeychain: self keyUsage: keyUsage] autorelease];
   18.22  }
   18.23  
   18.24  - (NSEnumerator*) enumerateSymmetricKeys {
   18.25 @@ -448,10 +452,10 @@
   18.26  
   18.27  @implementation MYIdentityEnumerator
   18.28  
   18.29 -- (id) initWithKeychain: (MYKeychain*)keychain {
   18.30 +- (id) initWithKeychain: (MYKeychain*)keychain keyUsage: (CSSM_KEYUSE)keyUsage {
   18.31      self = [super init];
   18.32      if (self) {
   18.33 -        if (!check(SecIdentitySearchCreate(keychain.keychainRef, 0, &_searchRef),
   18.34 +        if (!check(SecIdentitySearchCreate(keychain.keychainRef, keyUsage, &_searchRef),
   18.35                     @"SecIdentitySearchCreate")) {
   18.36              [self release];
   18.37              return nil;
    19.1 --- a/MYKeychainItem.h	Wed Jun 10 09:02:18 2009 -0700
    19.2 +++ b/MYKeychainItem.h	Wed Jul 01 14:19:13 2009 -0700
    19.3 @@ -29,6 +29,9 @@
    19.4  {
    19.5      @private
    19.6      MYKeychainItemRef _itemRef;
    19.7 +#if MYCRYPTO_USE_IPHONE_API
    19.8 +    BOOL _isPersistent;
    19.9 +#endif
   19.10  }
   19.11  
   19.12  /** The Keychain item reference that this object represents. */
   19.13 @@ -40,4 +43,8 @@
   19.14  /** Removes the item from its keychain, if any. */
   19.15  - (BOOL) removeFromKeychain;
   19.16  
   19.17 +#if MYCRYPTO_USE_IPHONE_API
   19.18 +@property BOOL isPersistent;
   19.19 +#endif
   19.20 +
   19.21  @end
    20.1 --- a/MYKeychainItem.m	Wed Jun 10 09:02:18 2009 -0700
    20.2 +++ b/MYKeychainItem.m	Wed Jul 01 14:19:13 2009 -0700
    20.3 @@ -8,6 +8,7 @@
    20.4  
    20.5  #import "MYKeychainItem.h"
    20.6  #import "MYCrypto_Private.h"
    20.7 +#import "MYBERParser.h"
    20.8  #import "MYErrorUtils.h"
    20.9  
   20.10  
   20.11 @@ -25,6 +26,9 @@
   20.12          _itemRef = itemRef;
   20.13          CFRetain(_itemRef);
   20.14          LogTo(INIT,@"%@, _itemRef=%@", [self class], itemRef);
   20.15 +#if MYCRYPTO_USE_IPHONE_API
   20.16 +        _isPersistent = YES;
   20.17 +#endif
   20.18      }
   20.19      return self;
   20.20  }
   20.21 @@ -32,6 +36,10 @@
   20.22  
   20.23  @synthesize keychainItemRef=_itemRef;
   20.24  
   20.25 +#if MYCRYPTO_USE_IPHONE_API
   20.26 +@synthesize isPersistent = _isPersistent;
   20.27 +#endif
   20.28 +
   20.29  - (void) dealloc
   20.30  {
   20.31      if (_itemRef) CFRelease(_itemRef);
   20.32 @@ -71,7 +79,7 @@
   20.33  
   20.34  - (MYKeychain*) keychain {
   20.35  #if MYCRYPTO_USE_IPHONE_API
   20.36 -    return [MYKeychain defaultKeychain];
   20.37 +    return _isPersistent ? [MYKeychain defaultKeychain] : nil;
   20.38  #else
   20.39      MYKeychain *keychain = nil;
   20.40      SecKeychainRef keychainRef = NULL;
   20.41 @@ -89,6 +97,8 @@
   20.42      OSStatus err;
   20.43  #if MYCRYPTO_USE_IPHONE_API
   20.44      err = SecItemDelete((CFDictionaryRef) $dict( {(id)kSecValueRef, (id)_itemRef} ));
   20.45 +    if (!err)
   20.46 +        _isPersistent = NO;
   20.47  #else
   20.48      err = SecKeychainItemDelete((SecKeychainItemRef)_itemRef);
   20.49      if (err==errSecInvalidItemRef)
   20.50 @@ -98,6 +108,43 @@
   20.51  }
   20.52  
   20.53  
   20.54 +/* (Not useful yet, as only password items have dates.)
   20.55 +- (NSDate*) dateValueOfAttribute: (SecKeychainAttrType)attr {
   20.56 +    NSString *dateStr = [self stringValueOfAttribute: attr];
   20.57 +    if (dateStr.length == 0)
   20.58 +        return nil;
   20.59 +    NSDate *date = [MYBERGeneralizedTimeFormatter() dateFromString: dateStr];
   20.60 +    if (!date)
   20.61 +        Warn(@"MYKeychainItem: unable to parse date '%@'", dateStr);
   20.62 +    return date;
   20.63 +}
   20.64 +
   20.65 +- (void) setDateValue: (NSDate*)date ofAttribute: (SecKeychainAttrType)attr {
   20.66 +    NSString *timeStr = nil;
   20.67 +    if (date)
   20.68 +        timeStr = [MYBERGeneralizedTimeFormatter() stringFromDate: date];
   20.69 +    [self setValue: timeStr ofAttribute: attr];
   20.70 +}
   20.71 +
   20.72 +
   20.73 +- (NSDate*) creationDate {
   20.74 +    return [self dateValueOfAttribute: kSecCreationDateItemAttr];
   20.75 +}
   20.76 +
   20.77 +- (void) setCreationDate: (NSDate*)date {
   20.78 +    [self setDateValue: date ofAttribute: kSecCreationDateItemAttr];
   20.79 +}
   20.80 +
   20.81 +- (NSDate*) modificationDate {
   20.82 +    return [self dateValueOfAttribute: kSecModDateItemAttr];
   20.83 +}
   20.84 +
   20.85 +- (void) setModificationDate: (NSDate*)date {
   20.86 +    [self setDateValue: date ofAttribute: kSecModDateItemAttr];
   20.87 +}
   20.88 +*/
   20.89 +
   20.90 +
   20.91  #pragma mark -
   20.92  #pragma mark DATA / METADATA ACCESSORS:
   20.93  
   20.94 @@ -165,6 +212,10 @@
   20.95  }
   20.96  
   20.97  - (NSString*) stringValueOfAttribute: (SecKeychainAttrType)attr {
   20.98 +#if MYCRYPTO_USE_IPHONE_API
   20.99 +    if (!self.isPersistent)
  20.100 +        return nil;
  20.101 +#endif
  20.102      return [[self class] _getStringAttribute: attr ofItem: _itemRef];
  20.103  }
  20.104  
    21.1 --- a/MYOID.h	Wed Jun 10 09:02:18 2009 -0700
    21.2 +++ b/MYOID.h	Wed Jul 01 14:19:13 2009 -0700
    21.3 @@ -16,6 +16,10 @@
    21.4      NSData *_data;
    21.5  }
    21.6  
    21.7 +#if TARGET_OS_MAC
    21.8 ++ (MYOID*) OIDFromCSSM: (CSSM_OID)cssmOid;
    21.9 +#endif
   21.10 +
   21.11  - (id) initWithComponents: (const UInt32*)components count: (unsigned)componentCount;
   21.12  - (id) initWithBEREncoding: (NSData*)encoding;
   21.13  - (NSData*) DEREncoding;
    22.1 --- a/MYOID.m	Wed Jun 10 09:02:18 2009 -0700
    22.2 +++ b/MYOID.m	Wed Jul 01 14:19:13 2009 -0700
    22.3 @@ -59,6 +59,16 @@
    22.4      return [[[self alloc] initWithBEREncoding: encoding] autorelease];
    22.5  }
    22.6  
    22.7 +#if TARGET_OS_MAC
    22.8 ++ (MYOID*) OIDFromCSSM: (CSSM_OID)cssmOid
    22.9 +{
   22.10 +    NSData *ber = [[NSData alloc] initWithBytesNoCopy: cssmOid.Data length: cssmOid.Length freeWhenDone: NO];
   22.11 +    MYOID *oid = [[[self alloc] initWithBEREncoding: ber] autorelease];
   22.12 +    [ber release];
   22.13 +    return oid;
   22.14 +}
   22.15 +#endif
   22.16 +
   22.17  
   22.18  - (id) copyWithZone: (NSZone*)zone {
   22.19      return [self retain];
    23.1 --- a/MYPublicKey.h	Wed Jun 10 09:02:18 2009 -0700
    23.2 +++ b/MYPublicKey.h	Wed Jul 01 14:19:13 2009 -0700
    23.3 @@ -7,7 +7,7 @@
    23.4  //
    23.5  
    23.6  #import "MYKey.h"
    23.7 -@class MYSHA1Digest, MYSymmetricKey;
    23.8 +@class MYSHA1Digest, MYSymmetricKey, MYCertificate;
    23.9  
   23.10  #if !TARGET_OS_IPHONE
   23.11  #import <Security/SecKey.h>
   23.12 @@ -20,7 +20,8 @@
   23.13  @interface MYPublicKey : MYKey
   23.14  {
   23.15      @private
   23.16 -    MYSHA1Digest *_digest;
   23.17 +    MYSHA1Digest *_digest;              // The key's SHA-1 digest (null if not determined yet)
   23.18 +    MYCertificate *_certificate;        // The cert this key came from (if any)
   23.19  }
   23.20  
   23.21  /** The public key's SHA-1 digest. This is a convenient short (20-byte) identifier for the key. */
    24.1 --- a/MYPublicKey.m	Wed Jun 10 09:02:18 2009 -0700
    24.2 +++ b/MYPublicKey.m	Wed Jul 01 14:19:13 2009 -0700
    24.3 @@ -16,6 +16,11 @@
    24.4  #import <CommonCrypto/CommonDigest.h>
    24.5  
    24.6  
    24.7 +@interface MYPublicKey ()
    24.8 +@property (retain) MYCertificate *certificate;
    24.9 +@end
   24.10 +
   24.11 +
   24.12  #pragma mark -
   24.13  @implementation MYPublicKey
   24.14  
   24.15 @@ -35,6 +40,8 @@
   24.16      [super dealloc];
   24.17  }
   24.18  
   24.19 +@synthesize certificate=_certificate;
   24.20 +
   24.21  - (SecExternalItemType) keyClass {
   24.22  #if MYCRYPTO_USE_IPHONE_API
   24.23      return kSecAttrKeyClassPublic;
   24.24 @@ -63,6 +70,16 @@
   24.25      return _digest;
   24.26  }
   24.27  
   24.28 +#if MYCRYPTO_USE_IPHONE_API
   24.29 +- (NSData*) keyData {
   24.30 +    if (_certificate) {
   24.31 +        return _certificate.info.subjectPublicKeyData;
   24.32 +    } else {
   24.33 +        return [super keyData];
   24.34 +    }
   24.35 +}
   24.36 +#endif
   24.37 +
   24.38  #if !MYCRYPTO_USE_IPHONE_API
   24.39  - (SecExternalFormat) _externalFormat {
   24.40      return kSecFormatBSAFE;
    25.1 --- a/MYSymmetricKey-iPhone.m	Wed Jun 10 09:02:18 2009 -0700
    25.2 +++ b/MYSymmetricKey-iPhone.m	Wed Jul 01 14:19:13 2009 -0700
    25.3 @@ -13,6 +13,9 @@
    25.4  #if MYCRYPTO_USE_IPHONE_API
    25.5  
    25.6  
    25.7 +#define kAlgorithmNone 0xFFFFFFFF
    25.8 +
    25.9 +
   25.10  typedef uint32_t CSSM_ALGORITHMS;
   25.11  enum {
   25.12  // Taken from cssmtype.h in OS X 10.5 SDK:
   25.13 @@ -36,20 +39,27 @@
   25.14  @implementation MYSymmetricKey
   25.15  
   25.16  
   25.17 +- (id) initWithKeyRef: (SecKeyRef)key {
   25.18 +    self = [super initWithKeyRef: key];
   25.19 +    if (self) {
   25.20 +        _algorithm = kAlgorithmNone;
   25.21 +    }
   25.22 +    return self;
   25.23 +}
   25.24 +
   25.25  - (id) _initWithKeyData: (NSData*)keyData
   25.26                algorithm: (CCAlgorithm)algorithm
   25.27               inKeychain: (MYKeychain*)keychain
   25.28  {
   25.29      Assert(algorithm <= kCCAlgorithmRC4);
   25.30      Assert(keyData);
   25.31 -    NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8];
   25.32 -    NSNumber *keyType = [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]];
   25.33 +    unsigned keySizeInBits = keyData.length * 8;
   25.34      NSMutableDictionary *keyAttrs = $mdict( {(id)kSecClass, (id)kSecClassKey},
   25.35                                              {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   25.36 -                                            {(id)kSecAttrKeyType, keyType},
   25.37 +                                            {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])},
   25.38                                              {(id)kSecValueData, keyData},
   25.39 -                                            {(id)kSecAttrKeySizeInBits, keySizeInBits},
   25.40 -                                            {(id)kSecAttrEffectiveKeySize, keySizeInBits},
   25.41 +                                            {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)},
   25.42 +                                            {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)},
   25.43                                              {(id)kSecAttrIsPermanent, keychain ?$true :$false},
   25.44                                              {(id)kSecAttrCanEncrypt, $true},
   25.45                                              {(id)kSecAttrCanDecrypt, $true},
   25.46 @@ -57,14 +67,17 @@
   25.47                                              {(id)kSecAttrCanUnwrap, $false},
   25.48                                              {(id)kSecAttrCanDerive, $false},
   25.49                                              {(id)kSecAttrCanSign, $false},
   25.50 -                                            {(id)kSecAttrCanVerify, $false},
   25.51 -                                            {(id)kSecReturnPersistentRef, $true});
   25.52 -    SecKeyRef keyRef = [[self class] _addKeyWithInfo: keyAttrs];
   25.53 +                                            {(id)kSecAttrCanVerify, $false});
   25.54 +    SecKeyRef keyRef = (SecKeyRef) [MYKeychain _addItemWithInfo: keyAttrs];
   25.55      if (!keyRef) {
   25.56          [self release];
   25.57          return nil;
   25.58      }
   25.59      self = [self initWithKeyRef: keyRef];
   25.60 +    if (self) {
   25.61 +        _algorithm = algorithm;
   25.62 +        _keySizeInBits = keySizeInBits;
   25.63 +    }
   25.64      CFRelease(keyRef);
   25.65      return self;
   25.66  }
   25.67 @@ -98,25 +111,33 @@
   25.68  }
   25.69  
   25.70  - (CCAlgorithm) algorithm {
   25.71 -    CSSM_ALGORITHMS cssmAlg;
   25.72 -    id keyType = [self _attribute: kSecAttrKeyType];
   25.73 -    Assert(keyType!=nil, @"Key has no kSecAttrKeyType");
   25.74 -    cssmAlg = [keyType unsignedIntValue];
   25.75 -    switch(cssmAlg) {
   25.76 -        case CSSM_ALGID_AES:
   25.77 -            return kCCAlgorithmAES128;
   25.78 -        case CSSM_ALGID_DES:
   25.79 -            return kCCAlgorithmDES;	
   25.80 -        case CSSM_ALGID_3DES_3KEY:
   25.81 -            return kCCAlgorithm3DES;
   25.82 -        case CSSM_ALGID_CAST:
   25.83 -            return kCCAlgorithmCAST;
   25.84 -        case CSSM_ALGID_RC4:
   25.85 -            return kCCAlgorithmRC4;	
   25.86 -        default:
   25.87 -            Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
   25.88 -            return (CCAlgorithm)-1;
   25.89 +    if (_algorithm == kAlgorithmNone) {
   25.90 +        CSSM_ALGORITHMS cssmAlg;
   25.91 +        id keyType = [self _attribute: kSecAttrKeyType];
   25.92 +        Assert(keyType!=nil, @"Key has no kSecAttrKeyType");
   25.93 +        cssmAlg = [keyType unsignedIntValue];
   25.94 +        switch(cssmAlg) {
   25.95 +            case CSSM_ALGID_AES:
   25.96 +                _algorithm = kCCAlgorithmAES128;
   25.97 +                break;
   25.98 +            case CSSM_ALGID_DES:
   25.99 +                _algorithm = kCCAlgorithmDES;
  25.100 +                break;
  25.101 +            case CSSM_ALGID_3DES_3KEY:
  25.102 +                _algorithm = kCCAlgorithm3DES;
  25.103 +                break;
  25.104 +            case CSSM_ALGID_CAST:
  25.105 +                _algorithm = kCCAlgorithmCAST;
  25.106 +                break;
  25.107 +            case CSSM_ALGID_RC4:
  25.108 +                _algorithm = kCCAlgorithmRC4;
  25.109 +                break;
  25.110 +            default:
  25.111 +                Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg);
  25.112 +                break;
  25.113 +        }
  25.114      }
  25.115 +    return _algorithm;
  25.116  }
  25.117  
  25.118  - (const char*) algorithmName {
  25.119 @@ -128,9 +149,12 @@
  25.120  }
  25.121  
  25.122  - (unsigned) keySizeInBits {
  25.123 -    id keySize = [self _attribute: kSecAttrKeySizeInBits];
  25.124 -    Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits");
  25.125 -    return [keySize unsignedIntValue];
  25.126 +    if (_keySizeInBits == 0) {
  25.127 +        id keySize = [self _attribute: kSecAttrKeySizeInBits];
  25.128 +        Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits");
  25.129 +        _keySizeInBits = [keySize unsignedIntValue];
  25.130 +    }
  25.131 +    return _keySizeInBits;
  25.132  }
  25.133  
  25.134  
    26.1 --- a/MYSymmetricKey.h	Wed Jun 10 09:02:18 2009 -0700
    26.2 +++ b/MYSymmetricKey.h	Wed Jul 01 14:19:13 2009 -0700
    26.3 @@ -21,7 +21,10 @@
    26.4  @interface MYSymmetricKey : MYKey <MYEncryption, MYDecryption>
    26.5  {
    26.6      @private
    26.7 -#if !MYCRYPTO_USE_IPHONE_API
    26.8 +#if MYCRYPTO_USE_IPHONE_API
    26.9 +    CCAlgorithm _algorithm;
   26.10 +    unsigned _keySizeInBits;
   26.11 +#else
   26.12      CSSM_KEY *_ownedCSSMKey;
   26.13  #endif
   26.14  }
   26.15 @@ -39,9 +42,6 @@
   26.16  /** The key's algorithm. */
   26.17  @property (readonly) CCAlgorithm algorithm;
   26.18  
   26.19 -/** The key's size/length, in bits. */
   26.20 -@property (readonly) unsigned keySizeInBits;
   26.21 -
   26.22  
   26.23  #if !TARGET_OS_IPHONE
   26.24  
    27.1 --- a/MYSymmetricKey.m	Wed Jun 10 09:02:18 2009 -0700
    27.2 +++ b/MYSymmetricKey.m	Wed Jul 01 14:19:13 2009 -0700
    27.3 @@ -315,12 +315,6 @@
    27.4          return "???";
    27.5  }
    27.6  
    27.7 -- (unsigned) keySizeInBits {
    27.8 -    const CSSM_KEY *key = self.cssmKey;
    27.9 -    Assert(key);
   27.10 -    return key->KeyHeader.LogicalKeySizeInBits;
   27.11 -}
   27.12 -
   27.13  
   27.14  - (NSString*) description {
   27.15      return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName);
    28.1 Binary file Tests/generated.cer has changed
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/Tests/iphonedev.pem	Wed Jul 01 14:19:13 2009 -0700
    29.3 @@ -0,0 +1,31 @@
    29.4 +-----BEGIN CERTIFICATE-----
    29.5 +MIIFXDCCBESgAwIBAgIIGobFgVhxq7UwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV
    29.6 +BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js
    29.7 +ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3
    29.8 +aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw
    29.9 +HhcNMDkwMzMxMDUxODMxWhcNMTAwMzMxMDUxODMxWjBQMRowGAYKCZImiZPyLGQB
   29.10 +AQwKWE5YQVlGOU45NzElMCMGA1UEAwwcaVBob25lIERldmVsb3BlcjogSmVucyBB
   29.11 +bGZrZTELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
   29.12 +AQDAnbltHERIUGlrXpuiI7zJq34WuVotTSOhGbquWN9JanqesgwBqEMQLI2rcHgl
   29.13 +jdxwpmIuTS3vYUi8skKnn0M3NZay3/jD9pjJdbvj27B5O/OHF0vQ3wvVgyKaD/DF
   29.14 +qxKtC8NPr3pfTM3qZ1c/ItyyJqLwQEIaqm4DQ24eZW7XP+WDmCW2pKddwSDbhMX4
   29.15 +IYnZYUIofRREpEVqxFM3eOYQ5d2QuOtEOagE+Cmll+mR9izNdUk/rQqtMcM0uW4v
   29.16 +DGQA8eNG9lkQ+NEgDJiamI4R4laR6JoJv8u/+brcKMWB5MzjOwB8H2vDVmbUKQHA
   29.17 +TNdGIT5O1S/QrK1fx6zbUsCjAgMBAAGjggHxMIIB7TAMBgNVHRMBAf8EAjAAMA4G
   29.18 +A1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU
   29.19 +JiwPQTnjJffW28sAv/MUYRR4SIUwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZ
   29.20 +xVJUo7cwggEPBgNVHSAEggEGMIIBAjCB/wYJKoZIhvdjZAUBMIHxMIHDBggrBgEF
   29.21 +BQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBh
   29.22 +cnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0
   29.23 +YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUg
   29.24 +cG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMCkG
   29.25 +CCsGAQUFBwIBFh1odHRwOi8vd3d3LmFwcGxlLmNvbS9hcHBsZWNhLzBNBgNVHR8E
   29.26 +RjBEMEKgQKA+hjxodHRwOi8vZGV2ZWxvcGVyLmFwcGxlLmNvbS9jZXJ0aWZpY2F0
   29.27 +aW9uYXV0aG9yaXR5L3d3ZHJjYS5jcmwwEwYKKoZIhvdjZAYBAgEB/wQCBQAwDQYJ
   29.28 +KoZIhvcNAQEFBQADggEBAHDSLmE7EGuWPZ2p9v79FUzIqE8kWHwD7mCF5JfA9XWW
   29.29 +NAtoBxqg1600RRh1RslH6wn7eDQj/39+V4INwqOjheUkwwvsLqbw3meDAdJI3QQ/
   29.30 +0D1Ig7vdAPSjo+heXauXlmrYGtMkZYr6U0nTYaPZJtj4JlJganatMPRtzHw+r35H
   29.31 +oZe3CtKOfE/GYGsXmTxzhkA21wX0Gd8QorVteI5n6zmU2qNcEOdVPa6hsF9f1BC8
   29.32 +GKVpw5+vGOtBlimYzg7fpw940IaXaLh5Ax2zJ8pUAPjKsPAMqrr24jwVlJwH0vqa
   29.33 +QufMuuUFgFYsW8xPeCQs13/DaA11Hm6srm6yh8sbx58=
   29.34 +-----END CERTIFICATE-----
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/Tests/selfsigned.pem	Wed Jul 01 14:19:13 2009 -0700
    30.3 @@ -0,0 +1,22 @@
    30.4 +-----BEGIN CERTIFICATE-----
    30.5 +MIIDpzCCAo+gAwIBAgIBATALBgkqhkiG9w0BAQEwezEUMBIGA1UEBBMLV2lkZGVy
    30.6 +c2hpbnMxIDAeBgkqhkiG9w0BCQETEXdhbGRvQGV4YW1wbGUuY29tMQ4wDAYDVQQD
    30.7 +EwV3YWxkbzEOMAwGA1UEKhMFV2FsZG8xITAfBgNVBA0TGEp1c3QgYSBmaWN0aXRp
    30.8 +b3VzIHBlcnNvbjAiGA8yMDA5MDQxMzA0NTQzNVoYDzIwMTAwNDE0MDQ1NDM1WjB7
    30.9 +MRQwEgYDVQQEEwtXaWRkZXJzaGluczEgMB4GCSqGSIb3DQEJARMRd2FsZG9AZXhh
   30.10 +bXBsZS5jb20xDjAMBgNVBAMTBXdhbGRvMQ4wDAYDVQQqEwVXYWxkbzEhMB8GA1UE
   30.11 +DRMYSnVzdCBhIGZpY3RpdGlvdXMgcGVyc29uMIIBIjANBgkqhkiG9w0BAQEFAAOC
   30.12 +AQ8AMIIBCgKCAQEAlXE8Ngut8thXXr0nj6JroubQXh6wTqqfpvEb/TQVVgOLMHdS
   30.13 +XHrb9a7fOySbCOZ/d68mf/L+uF9My5ZSadvS8B8ZtlX8TqOoXy7eEf+A+Pwj5mLy
   30.14 +Y/aFBqnsB/fuQkmvGE8hLZJT2H9vfLyW5rpcq8j05zv2EAsG3PPumZ1BcPXdAF2i
   30.15 +SlShPtrd1QZ1QJ1nKKOHX6cYmOv32T1K+HQt+aDprW3CHPr8LRln5pJXW1blN2yM
   30.16 +8AjopELXh2hDqS6VAbFEinWt716AT+xtCXQNHqhELmf6w77F6jr12V2flSxQdxEB
   30.17 +xFlCKK0UECNSUyRihIR22YfTx9ZfkFfa8ehTdwIDAQABozQwMjALBgNVHQ8EBAMC
   30.18 +AvwwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMA0GCSqGSIb3
   30.19 +DQEBBQUAA4IBAQB5yOeJUKEfy3OY9f4M+iWVskdvU2LfvqJwrjqL/a9aVzm+YQH8
   30.20 +Xgkp5XoLK0Hjq1L3jvG17MiEjNp/Qqq1fD3030ElqdtOY4gZfCoc4ybBpVIDtO/a
   30.21 +BXuRSrxDqj7u5qr+QwPDDwABdRa5FrVy+LdPxoKgb5IOO7+hbNrY/OPxhK3Mxh6N
   30.22 +O0Tli9ED8EYxD2qZLyQKspA1TATFGckiJ232MQzLjpQuOPZVXKQLcUguUhRqmYjw
   30.23 +IcLALShdtVnUjq97IFWfBo6hoPB/uu4pKEraKL+DRPQ18w9iY/DJnEkgzqG3xsCc
   30.24 ++ju7r1oP7lsOlOucV9KLG7nJd75T5Lu2df+q
   30.25 +-----END CERTIFICATE-----
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/Tests/selfsigned_altered.pem	Wed Jul 01 14:19:13 2009 -0700
    31.3 @@ -0,0 +1,22 @@
    31.4 +-----BEGIN CERTIFICATE-----
    31.5 +MIIDpzCCAo+gAwIBAgIBATALBgkqhkiG9w0BAQEwezEUMBIGA1UEBBMLUG9vb3B5
    31.6 +c2hpbnMxIDAeBgkqhkiG9w0BCQETEXdhbGRvQGV4YW1wbGUuY29tMQ4wDAYDVQQD
    31.7 +EwV3YWxkbzEOMAwGA1UEKhMFV2FsZG8xITAfBgNVBA0TGEp1c3QgYSBmaWN0aXRp
    31.8 +b3VzIHBlcnNvbjAiGA8yMDA5MDQxMzA0NTQzNVoYDzIwMTAwNDE0MDQ1NDM1WjB7
    31.9 +MRQwEgYDVQQEEwtQb29vcHlzaGluczEgMB4GCSqGSIb3DQEJARMRd2FsZG9AZXhh
   31.10 +bXBsZS5jb20xDjAMBgNVBAMTBXdhbGRvMQ4wDAYDVQQqEwVXYWxkbzEhMB8GA1UE
   31.11 +DRMYSnVzdCBhIGZpY3RpdGlvdXMgcGVyc29uMIIBIjANBgkqhkiG9w0BAQEFAAOC
   31.12 +AQ8AMIIBCgKCAQEAlXE8Ngut8thXXr0nj6JroubQXh6wTqqfpvEb/TQVVgOLMHdS
   31.13 +XHrb9a7fOySbCOZ/d68mf/L+uF9My5ZSadvS8B8ZtlX8TqOoXy7eEf+A+Pwj5mLy
   31.14 +Y/aFBqnsB/fuQkmvGE8hLZJT2H9vfLyW5rpcq8j05zv2EAsG3PPumZ1BcPXdAF2i
   31.15 +SlShPtrd1QZ1QJ1nKKOHX6cYmOv32T1K+HQt+aDprW3CHPr8LRln5pJXW1blN2yM
   31.16 +8AjopELXh2hDqS6VAbFEinWt716AT+xtCXQNHqhELmf6w77F6jr12V2flSxQdxEB
   31.17 +xFlCKK0UECNSUyRihIR22YfTx9ZfkFfa8ehTdwIDAQABozQwMjALBgNVHQ8EBAMC
   31.18 +AvwwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMA0GCSqGSIb3
   31.19 +DQEBBQUAA4IBAQB5yOeJUKEfy3OY9f4M+iWVskdvU2LfvqJwrjqL/a9aVzm+YQH8
   31.20 +Xgkp5XoLK0Hjq1L3jvG17MiEjNp/Qqq1fD3030ElqdtOY4gZfCoc4ybBpVIDtO/a
   31.21 +BXuRSrxDqj7u5qr+QwPDDwABdRa5FrVy+LdPxoKgb5IOO7+hbNrY/OPxhK3Mxh6N
   31.22 +O0Tli9ED8EYxD2qZLyQKspA1TATFGckiJ232MQzLjpQuOPZVXKQLcUguUhRqmYjw
   31.23 +IcLALShdtVnUjq97IFWfBo6hoPB/uu4pKEraKL+DRPQ18w9iYwDJnEkgzqG3xsCc
   31.24 ++ju7r1oP7lsOlOucV9KLG7nJd75T5Lu2df+q
   31.25 +-----END CERTIFICATE-----