A snapshot taken during the long, agonizing crawl toward getting everything running on iPhone.
authorJens Alfke <jens@mooseyard.com>
Sun Jun 07 21:53:56 2009 -0700 (2009-06-07)
changeset 2339fec79de6e8
parent 22 058394513f33
child 24 6856e071d25a
A snapshot taken during the long, agonizing crawl toward getting everything running on iPhone.
MYCertificate-iPhone.m
MYCertificate.h
MYCertificateInfo.m
MYCrypto-iPhone.xcodeproj/project.pbxproj
MYCryptoTest.m
MYCrypto_Private.h
MYDigest.h
MYDigest.m
MYIdentity.m
MYKey-iPhone.m
MYKey.h
MYKey.m
MYKeychain-iPhone.m
MYKeychainItem.m
MYPrivateKey.m
MYPublicKey.m
MYSymmetricKey-iPhone.m
MYSymmetricKey.m
     1.1 --- a/MYCertificate-iPhone.m	Sat Jun 06 15:36:35 2009 -0700
     1.2 +++ b/MYCertificate-iPhone.m	Sun Jun 07 21:53:56 2009 -0700
     1.3 @@ -97,6 +97,10 @@
     1.4      return name ?[(id)CFMakeCollectable(name) autorelease] :nil;
     1.5  }
     1.6  
     1.7 +- (NSArray*) emailAddresses {
     1.8 +    NSString *email = self.info.subject.emailAddress;
     1.9 +    return email ?$array(email) :nil;
    1.10 +}
    1.11  
    1.12  @end
    1.13  
     2.1 --- a/MYCertificate.h	Sat Jun 06 15:36:35 2009 -0700
     2.2 +++ b/MYCertificate.h	Sun Jun 07 21:53:56 2009 -0700
     2.3 @@ -52,6 +52,9 @@
     2.4  /** The common name of the subject (owner) of the certificate. */
     2.5  @property (readonly) NSString *commonName;
     2.6  
     2.7 +/** The list (if any) of the subject's email addresses. */
     2.8 +@property (readonly) NSArray *emailAddresses;
     2.9 +
    2.10  
    2.11  /** @name Mac-Only
    2.12   *  Functionality not available on iPhone. 
    2.13 @@ -64,9 +67,6 @@
    2.14                            type: (CSSM_CERT_TYPE) type
    2.15                        encoding: (CSSM_CERT_ENCODING) encoding;
    2.16  
    2.17 -/** The list (if any) of the subject's email addresses. */
    2.18 -@property (readonly) NSArray *emailAddresses;
    2.19 -
    2.20  /** Finds the current 'preferred' certificate for the given name string. */
    2.21  + (MYCertificate*) preferredCertificateForName: (NSString*)name;
    2.22  
     3.1 --- a/MYCertificateInfo.m	Sat Jun 06 15:36:35 2009 -0700
     3.2 +++ b/MYCertificateInfo.m	Sun Jun 07 21:53:56 2009 -0700
     3.3 @@ -179,8 +179,18 @@
     3.4                                             [MYBitString bitStringWithData: publicKey.keyData] ) ) );
     3.5      self = [super initWithRoot: root];
     3.6      [version release];
     3.7 +    if (self) {
     3.8 +        _publicKey = publicKey.retain;
     3.9 +    }
    3.10      return self;
    3.11  }
    3.12 +    
    3.13 +- (void) dealloc
    3.14 +{
    3.15 +    [_publicKey release];
    3.16 +    [super dealloc];
    3.17 +}
    3.18 +
    3.19  
    3.20  - (NSDate*) validFrom       {return [super validFrom];}
    3.21  - (NSDate*) validTo         {return [super validTo];}
    3.22 @@ -244,11 +254,14 @@
    3.23  - (MYIdentity*) createSelfSignedIdentityWithPrivateKey: (MYPrivateKey*)privateKey
    3.24                                                   error: (NSError**)outError
    3.25  {
    3.26 +    Assert(privateKey.keychain!=nil);
    3.27      NSData *certData = [self selfSignWithPrivateKey: privateKey error: outError];
    3.28      if (!certData)
    3.29          return nil;
    3.30      MYCertificate *cert = [privateKey.keychain importCertificate: certData];
    3.31      Assert(cert!=nil);
    3.32 +    Assert(cert.keychain!=nil);
    3.33 +    AssertEqual(cert.publicKey.keyData, _publicKey.keyData);
    3.34      MYIdentity *identity = cert.identity;
    3.35      Assert(identity!=nil);
    3.36      return identity;
    3.37 @@ -329,10 +342,9 @@
    3.38  #if DEBUG
    3.39  
    3.40  
    3.41 -static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
    3.42 -    Log(@"--- Creating MYCertificateInfo from %@", filename);
    3.43 -    NSData *certData = [NSData dataWithContentsOfFile: filename];
    3.44 +static MYCertificateInfo* testCertData(NSData *certData, BOOL selfSigned) {
    3.45      //Log(@"Cert Data =\n%@", certData);
    3.46 +    CAssert(certData!=nil);
    3.47      NSError *error = nil;
    3.48      MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData 
    3.49                                                                              error: &error];
    3.50 @@ -359,10 +371,21 @@
    3.51      return pcert;
    3.52  }
    3.53  
    3.54 +static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
    3.55 +#if TARGET_OS_IPHONE
    3.56 +    filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"];
    3.57 +#else
    3.58 +    filename = [[@"../../Tests/" stringByAppendingPathComponent: filename]
    3.59 +                stringByAppendingPathExtension: @"cer"];
    3.60 +#endif
    3.61 +    Log(@"--- Creating MYCertificateInfo from %@", filename);
    3.62 +    return testCertData([NSData dataWithContentsOfFile: filename], selfSigned);
    3.63 +}
    3.64 +
    3.65  
    3.66  TestCase(ParsedCert) {
    3.67 -    testCert(@"../../Tests/selfsigned.cer", YES);
    3.68 -    testCert(@"../../Tests/iphonedev.cer", NO);
    3.69 +    testCert(@"selfsigned", YES);
    3.70 +    testCert(@"iphonedev", NO);
    3.71  }
    3.72  
    3.73  
    3.74 @@ -395,8 +418,10 @@
    3.75          CAssert(certData);
    3.76          CAssertNil(error);
    3.77          CAssert(certData);
    3.78 +#if !TARGET_OS_IPHONE
    3.79          [certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
    3.80 -        MYCertificateInfo *pcert2 = testCert(@"../../Tests/generated.cer", YES);
    3.81 +#endif
    3.82 +        MYCertificateInfo *pcert2 = testCertData(certData, YES);
    3.83          
    3.84          Log(@"Verifying Info...");
    3.85          MYCertificateName *subject2 = pcert2.subject;
     4.1 --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj	Sat Jun 06 15:36:35 2009 -0700
     4.2 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj	Sun Jun 07 21:53:56 2009 -0700
     4.3 @@ -25,6 +25,8 @@
     4.4  		276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB3180F856AA700CB326E /* MYPublicKey.m */; };
     4.5  		276FB33B0F856ACB00CB326E /* MYKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB33A0F856ACB00CB326E /* MYKeychain.m */; };
     4.6  		276FB34B0F856CA400CB326E /* MYCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB34A0F856CA400CB326E /* MYCertificate.m */; };
     4.7 +		27958CA30FDB5F8F00095275 /* iphonedev.cer in Resources */ = {isa = PBXBuildFile; fileRef = 27958CA10FDB5F8F00095275 /* iphonedev.cer */; };
     4.8 +		27958CA40FDB5F8F00095275 /* selfsigned.cer in Resources */ = {isa = PBXBuildFile; fileRef = 27958CA20FDB5F8F00095275 /* selfsigned.cer */; };
     4.9  		27A430120F87C6C10063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823110F81D56E0019BE60 /* MYKey.m */; };
    4.10  		27A430140F87C6D50063D362 /* MYSymmetricKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A430130F87C6D50063D362 /* MYSymmetricKey.m */; };
    4.11  		27CD85DD0FDB1A82006BCB47 /* MYCertificateInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CD85DC0FDB1A82006BCB47 /* MYCertificateInfo.m */; };
    4.12 @@ -70,6 +72,8 @@
    4.13  		276FB3180F856AA700CB326E /* MYPublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPublicKey.m; sourceTree = "<group>"; };
    4.14  		276FB33A0F856ACB00CB326E /* MYKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeychain.m; sourceTree = "<group>"; };
    4.15  		276FB34A0F856CA400CB326E /* MYCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificate.m; sourceTree = "<group>"; };
    4.16 +		27958CA10FDB5F8F00095275 /* iphonedev.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = iphonedev.cer; path = Tests/iphonedev.cer; sourceTree = "<group>"; };
    4.17 +		27958CA20FDB5F8F00095275 /* selfsigned.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = selfsigned.cer; path = Tests/selfsigned.cer; sourceTree = "<group>"; };
    4.18  		27A430130F87C6D50063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = "<group>"; };
    4.19  		27A430150F87C6DB0063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = "<group>"; };
    4.20  		27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptoConfig.h; sourceTree = "<group>"; };
    4.21 @@ -155,6 +159,8 @@
    4.22  				275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */,
    4.23  				275D9FEB0FD8795300D85A86 /* MYOID.h */,
    4.24  				275D9FEC0FD8795300D85A86 /* MYOID.m */,
    4.25 +				27958CA10FDB5F8F00095275 /* iphonedev.cer */,
    4.26 +				27958CA20FDB5F8F00095275 /* selfsigned.cer */,
    4.27  			);
    4.28  			name = Certificates;
    4.29  			sourceTree = "<group>";
    4.30 @@ -291,6 +297,8 @@
    4.31  				27E823290F81D56E0019BE60 /* MYCrypto.xcconfig in Resources */,
    4.32  				27E8232A0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig in Resources */,
    4.33  				27E8233C0F81D5760019BE60 /* MYError_CSSMErrorDomain.strings in Resources */,
    4.34 +				27958CA30FDB5F8F00095275 /* iphonedev.cer in Resources */,
    4.35 +				27958CA40FDB5F8F00095275 /* selfsigned.cer in Resources */,
    4.36  			);
    4.37  			runOnlyForDeploymentPostprocessing = 0;
    4.38  		};
     5.1 --- a/MYCryptoTest.m	Sat Jun 06 15:36:35 2009 -0700
     5.2 +++ b/MYCryptoTest.m	Sun Jun 07 21:53:56 2009 -0700
     5.3 @@ -43,23 +43,44 @@
     5.4  }
     5.5  
     5.6  
     5.7 -TestCase(EnumerateKeys) {
     5.8 +TestCase(Enumerate) {
     5.9 +    RequireTestCase(EnumeratePublicKeys);
    5.10 +    RequireTestCase(EnumeratePrivateKeys);
    5.11 +    RequireTestCase(EnumerateSymmetricKeys);
    5.12 +    RequireTestCase(EnumerateCerts);
    5.13 +    RequireTestCase(EnumerateIdentities);
    5.14 +}
    5.15 +
    5.16 +
    5.17 +TestCase(EnumeratePublicKeys) {
    5.18      RequireTestCase(MYKeychain);
    5.19      NSEnumerator *e = [[MYKeychain allKeychains] enumeratePublicKeys];
    5.20      Log(@"Public Key Enumerator = %@", e);
    5.21      CAssert(e);
    5.22      for (MYPublicKey *key in e) {
    5.23 -        Log(@"Found %@ -- name=%@", key, key.name);
    5.24 +        Log(@"Trying public key %@", key.keyRef);
    5.25 +        @try{
    5.26 +            Log(@"Found %@ -- name=%@", key, key.name);
    5.27 +        }@catch (NSException *x) {
    5.28 +            Warn(@"Caught %@",x); //TEMP
    5.29 +        }
    5.30      }
    5.31 -    
    5.32 -    e = [[MYKeychain allKeychains] enumeratePrivateKeys];
    5.33 +}
    5.34 +
    5.35 +TestCase(EnumeratePrivateKeys) {
    5.36 +    RequireTestCase(MYKeychain);
    5.37 +    NSEnumerator *e = [[MYKeychain allKeychains] enumeratePrivateKeys];
    5.38      Log(@"Key-Pair Enumerator = %@", e);
    5.39      CAssert(e);
    5.40      for (MYPrivateKey *key in e) {
    5.41 -        Log(@"Found %@ -- name=%@", key, key.name);
    5.42 +        Log(@"Found %@ -- name=%@ --> %@", key, key.name, key.publicKey);
    5.43 +        CAssert(key.publicKey);
    5.44      }
    5.45 -    
    5.46 -    e = [[MYKeychain allKeychains] enumerateSymmetricKeys];
    5.47 +}
    5.48 +
    5.49 +TestCase(EnumerateSymmetricKeys) {
    5.50 +    RequireTestCase(MYKeychain);
    5.51 +    NSEnumerator *e = [[MYKeychain allKeychains] enumerateSymmetricKeys];
    5.52      Log(@"Symmetric Key Enumerator = %@", e);
    5.53      CAssert(e);
    5.54      for (MYSymmetricKey *key in e) {
    5.55 @@ -74,7 +95,8 @@
    5.56      Log(@"Enumerator = %@", e);
    5.57      CAssert(e);
    5.58      for (MYCertificate *cert in e) {
    5.59 -        //Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses);
    5.60 +        Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses);
    5.61 +        CAssert(cert.publicKey);
    5.62      }
    5.63  }
    5.64  
    5.65 @@ -112,7 +134,7 @@
    5.66          else
    5.67              key = [MYSymmetricKey generateSymmetricKeyOfSize: sizeInBits algorithm: algorithm];
    5.68          Log(@"Created %@", key);
    5.69 -    CAssert(key);
    5.70 +        CAssert(key);
    5.71          CAssertEq(key.algorithm, algorithm);
    5.72          CAssertEq(key.keySizeInBits, sizeInBits);
    5.73      #if !TARGET_OS_IPHONE
     6.1 --- a/MYCrypto_Private.h	Sat Jun 06 15:36:35 2009 -0700
     6.2 +++ b/MYCrypto_Private.h	Sun Jun 07 21:53:56 2009 -0700
     6.3 @@ -53,10 +53,12 @@
     6.4  - (id) initWithKeyData: (NSData*)data;
     6.5  - (id) _initWithKeyData: (NSData*)data
     6.6              forKeychain: (SecKeychainRef)keychain;
     6.7 -@property (readonly) SecExternalItemType keyType;
     6.8 +@property (readonly) SecExternalItemType keyClass, keyType;
     6.9  @property (readonly) MYSHA1Digest* _keyDigest;
    6.10  - (NSData*) _crypt: (NSData *)data operation: (BOOL) op;    // YES to encrypt, NO to decrypt
    6.11 -#if !MYCRYPTO_USE_IPHONE_API
    6.12 +#if MYCRYPTO_USE_IPHONE_API
    6.13 ++ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info;
    6.14 +#else
    6.15  @property (readonly) const CSSM_KEY* cssmKey;
    6.16  @property (readonly) const CSSM_CSP_HANDLE cssmCSPHandle;
    6.17  - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm;
     7.1 --- a/MYDigest.h	Sat Jun 06 15:36:35 2009 -0700
     7.2 +++ b/MYDigest.h	Sun Jun 07 21:53:56 2009 -0700
     7.3 @@ -24,16 +24,16 @@
     7.4  - (id) initWithRawDigest: (const void*)rawDigest length: (size_t)length;
     7.5  
     7.6  /** Wraps an existing digest, stored in an NSData object, in a MYDigest object. */
     7.7 -+ (MYDigest*) digestFromDigestData: (NSData*)digestData;
     7.8 ++ (id) digestFromDigestData: (NSData*)digestData;
     7.9  
    7.10  /** Wraps an existing digest, expressed as a hex string, in a MYDigest object. */
    7.11 -+ (MYDigest*) digestFromHexString: (NSString*)hexString;
    7.12 ++ (id) digestFromHexString: (NSString*)hexString;
    7.13  
    7.14  /** Computes a cryptographic digest of the given data. */
    7.15 -+ (MYDigest*) digestOfData: (NSData*)data;
    7.16 ++ (id) digestOfData: (NSData*)data;
    7.17  
    7.18  /** Computes a cryptographic digest of the given data. */
    7.19 -+ (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length;
    7.20 ++ (id) digestOfBytes: (const void*)bytes length: (size_t)length;
    7.21  
    7.22  /** Returns the digest as an NSData object. */
    7.23  @property (readonly) NSData *asData;
     8.1 --- a/MYDigest.m	Sat Jun 06 15:36:35 2009 -0700
     8.2 +++ b/MYDigest.m	Sun Jun 07 21:53:56 2009 -0700
     8.3 @@ -79,11 +79,11 @@
     8.4  }
     8.5  
     8.6  
     8.7 -+ (MYDigest*) digestFromDigestData: (NSData*)digestData {
     8.8 ++ (id) digestFromDigestData: (NSData*)digestData {
     8.9      return [[[self alloc] initWithRawDigest: digestData.bytes length: digestData.length] autorelease];
    8.10  }
    8.11  
    8.12 -+ (MYDigest*) digestFromHexString: (NSString*)hexString
    8.13 ++ (id) digestFromHexString: (NSString*)hexString
    8.14  {
    8.15      const char *cStr = [hexString UTF8String];
    8.16      const size_t length = [self length];
    8.17 @@ -98,10 +98,11 @@
    8.18      return [[[self alloc] initWithRawDigest: &digest length: length] autorelease];
    8.19  }
    8.20  
    8.21 -+ (MYDigest*) digestOfData: (NSData*)data {
    8.22 ++ (id) digestOfData: (NSData*)data {
    8.23      return [self digestOfBytes: data.bytes length: data.length];
    8.24  }
    8.25 -+ (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length {
    8.26 +
    8.27 ++ (id) digestOfBytes: (const void*)bytes length: (size_t)length {
    8.28      const size_t digestLength = [self length];
    8.29      uint8_t digest[digestLength];
    8.30      [self computeDigest: digest ofBytes: bytes length: length];
     9.1 --- a/MYIdentity.m	Sat Jun 06 15:36:35 2009 -0700
     9.2 +++ b/MYIdentity.m	Sun Jun 07 21:53:56 2009 -0700
     9.3 @@ -35,19 +35,21 @@
     9.4  }
     9.5  
     9.6  
     9.7 -#if !TARGET_OS_IPHONE
     9.8  - (id) initWithCertificateRef: (SecCertificateRef)certificateRef {
     9.9      self = [super initWithCertificateRef: certificateRef];
    9.10      if (self) {
    9.11 +#if !MYCRYPTO_USE_IPHONE_API
    9.12          if (!check(SecIdentityCreateWithCertificate(NULL, certificateRef, &_identityRef),
    9.13                     @"SecIdentityCreateWithCertificate")) {
    9.14              [self release];
    9.15              return nil;
    9.16          }
    9.17 +#else
    9.18 +        Assert(NO,@"-[MYIdentity initWithCertificateRef] isn't implemented for iPhone yet!");//FIX
    9.19 +#endif
    9.20      }
    9.21      return self;
    9.22  }
    9.23 -#endif
    9.24  
    9.25  - (void) dealloc
    9.26  {
    9.27 @@ -69,7 +71,7 @@
    9.28      if (!check(SecIdentityCopyPrivateKey(_identityRef, &keyRef), @"SecIdentityCopyPrivateKey"))
    9.29          return NULL;
    9.30      MYPrivateKey *privateKey = [[MYPrivateKey alloc] _initWithKeyRef: keyRef
    9.31 -                                                          publicKey: self.publicKey];
    9.32 +                                                           publicKey: self.publicKey];
    9.33      CFRelease(keyRef);
    9.34      return [privateKey autorelease];
    9.35  }
    10.1 --- a/MYKey-iPhone.m	Sat Jun 06 15:36:35 2009 -0700
    10.2 +++ b/MYKey-iPhone.m	Sun Jun 07 21:53:56 2009 -0700
    10.3 @@ -19,6 +19,45 @@
    10.4  @implementation MYKey
    10.5  
    10.6  
    10.7 ++ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info {
    10.8 +    if (![info objectForKey: (id)kSecAttrApplicationTag]) {
    10.9 +        // Every keychain item has to have a unique tag, apparently, or you'll get spurious
   10.10 +        // duplicate-item errors. If none was given, make up a random one:
   10.11 +        UInt8 tag[16];
   10.12 +        Assert(check(SecRandomCopyBytes(kSecRandomDefault, sizeof(tag), tag), @"SecRandomCopyBytes"));
   10.13 +        [info setObject: [NSData dataWithBytes: tag length: sizeof(tag)] 
   10.14 +                 forKey: (id)kSecAttrApplicationTag];
   10.15 +    }
   10.16 +    CFDataRef keyPersistentRef;
   10.17 +    SecKeyRef key;
   10.18 +    OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&keyPersistentRef);
   10.19 +    if (err==errSecDuplicateItem) {
   10.20 +        // it's already in the keychain -- get a reference to it:
   10.21 +		[info removeObjectForKey: (id)kSecReturnPersistentRef];
   10.22 +		[info setObject: $true forKey: (id)kSecReturnRef];
   10.23 +		if (check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key), 
   10.24 +                   @"SecItemCopyMatching"))
   10.25 +            return key;
   10.26 +    } else if (check(err, @"SecItemAdd")) {
   10.27 +        // It was added
   10.28 +        if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) {
   10.29 +            // now get its SecKeyRef:
   10.30 +            info = $mdict({(id)kSecValuePersistentRef, (id)keyPersistentRef},
   10.31 +                          {(id)kSecReturnRef, $true});
   10.32 +            err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key);
   10.33 +            CFRelease(keyPersistentRef);
   10.34 +            if (check(err,@"SecItemCopyMatching")) {
   10.35 +                Assert(key!=nil);
   10.36 +                return key;
   10.37 +            }
   10.38 +        } else {
   10.39 +            return (SecKeyRef)keyPersistentRef;
   10.40 +        }
   10.41 +    }
   10.42 +    return NULL;
   10.43 +}
   10.44 +
   10.45 +
   10.46  - (id) initWithKeyRef: (SecKeyRef)key {
   10.47      return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
   10.48  }
   10.49 @@ -27,45 +66,65 @@
   10.50  - (id) _initWithKeyData: (NSData*)data
   10.51              forKeychain: (SecKeychainRef)keychain
   10.52  {
   10.53 -    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
   10.54 -                                {(id)kSecAttrKeyClass, (id)self.keyType},
   10.55 -                                {(id)kSecValueData, data},
   10.56 -                                {(id)kSecAttrIsPermanent, $object(keychain!=nil)},
   10.57 -                                {(id)kSecReturnRef, $true} );
   10.58 -    SecKeyRef key;
   10.59 -    if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&key), @"SecItemAdd"))
   10.60 +    NSMutableDictionary *info = $mdict({(id)kSecClass, (id)kSecClassKey},
   10.61 +                                        {(id)kSecAttrKeyType, (id)self.keyType},
   10.62 +                                        {(id)kSecValueData, data},
   10.63 +                                        {(id)kSecAttrIsPermanent, (keychain ?$true :$false)},
   10.64 +                                        {(id)kSecReturnPersistentRef, $true} );
   10.65 +    SecKeyRef key = [[self class] _addKeyWithInfo: info];
   10.66 +    if (!key) {
   10.67 +        [self release];
   10.68          return nil;
   10.69 -    else
   10.70 -        return [self initWithKeyRef: (SecKeyRef)key];
   10.71 +    }
   10.72 +    self = [self initWithKeyRef: (SecKeyRef)key];
   10.73 +    if (self) {
   10.74 +        if (!keychain)
   10.75 +            _keyData = [data copy];
   10.76 +    }
   10.77 +    return self;
   10.78  }
   10.79  
   10.80  - (id) initWithKeyData: (NSData*)data {
   10.81      return [self _initWithKeyData: data forKeychain: nil];
   10.82  }
   10.83  
   10.84 +- (void) dealloc
   10.85 +{
   10.86 +    [_keyData release];
   10.87 +    [super dealloc];
   10.88 +}
   10.89  
   10.90 -- (SecExternalItemType) keyType {
   10.91 +
   10.92 +- (SecExternalItemType) keyClass {
   10.93      AssertAbstractMethod();
   10.94  }
   10.95  
   10.96 +- (SecExternalItemType) keyType {
   10.97 +    return NULL;
   10.98 +}
   10.99  
  10.100  - (NSData*) keyData {
  10.101 -    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
  10.102 -                                {(id)kSecAttrKeyClass, (id)self.keyType},
  10.103 -                                {(id)kSecMatchItemList, $array((id)self.keyRef)},
  10.104 +    if (_keyData)
  10.105 +        return _keyData;
  10.106 +    
  10.107 +    NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef},
  10.108                                  {(id)kSecReturnData, $true} );
  10.109      CFDataRef data;
  10.110      if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching"))
  10.111          return nil;
  10.112 -    else
  10.113 +    else {
  10.114 +        Assert(data!=NULL);
  10.115          return [(id)CFMakeCollectable(data) autorelease];
  10.116 -    
  10.117 +    }
  10.118      // The format of this data is not documented. There's been some reverse-engineering:
  10.119      // https://devforums.apple.com/message/32089#32089
  10.120      // Apparently it is a DER-formatted sequence of a modulus followed by an exponent.
  10.121      // This can be converted to OpenSSL format by wrapping it in some additional DER goop.
  10.122  }
  10.123  
  10.124 +- (MYSHA1Digest*) _keyDigest {
  10.125 +    return [self.keyData my_SHA1Digest];
  10.126 +}
  10.127  
  10.128  - (SecKeyRef) keyRef {
  10.129      return (SecKeyRef) self.keychainItemRef;
  10.130 @@ -73,13 +132,12 @@
  10.131  
  10.132  
  10.133  - (id) _attribute: (CFTypeRef)attribute {
  10.134 -    NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
  10.135 -                                {(id)kSecAttrKeyClass, (id)self.keyType},
  10.136 -                                {(id)kSecMatchItemList, $array((id)self.keyRef)},
  10.137 -                                {(id)kSecReturnAttributes, $true} );
  10.138 +    NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef},
  10.139 +                               {(id)kSecReturnAttributes, $true});
  10.140      CFDictionaryRef attrs = NULL;
  10.141      if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
  10.142          return nil;
  10.143 +    Log(@"_attribute: %@ of %@ %p", attribute, [self class], self.keyRef);//TEMP
  10.144      CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute);
  10.145      id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil;
  10.146      CFRelease(attrs);
  10.147 @@ -90,7 +148,7 @@
  10.148      if (!value)
  10.149          value = (id)[NSNull null];
  10.150      NSDictionary *query = $dict( {(id)kSecClass, (id)kSecClassKey},
  10.151 -                                {(id)kSecAttrKeyClass, (id)self.keyType},
  10.152 +                                {(id)kSecAttrKeyClass, (id)self.keyClass},
  10.153                                  {(id)kSecMatchItemList, self._itemList} );
  10.154      NSDictionary *attrs = $dict( {(id)attribute, value} );
  10.155      return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
    11.1 --- a/MYKey.h	Sat Jun 06 15:36:35 2009 -0700
    11.2 +++ b/MYKey.h	Sun Jun 07 21:53:56 2009 -0700
    11.3 @@ -28,7 +28,9 @@
    11.4  /** Abstract superclass for keys.
    11.5      Concrete subclasses are MYSymmetricKey and MYPublicKey. */
    11.6  @interface MYKey : MYKeychainItem
    11.7 -{ }
    11.8 +{ 
    11.9 +    NSData *_keyData;
   11.10 +}
   11.11  
   11.12  /** Creates a key from encoded data (but does not add it to any keychain.) */
   11.13  - (id) initWithKeyData: (NSData*)data;
    12.1 --- a/MYKey.m	Sat Jun 06 15:36:35 2009 -0700
    12.2 +++ b/MYKey.m	Sun Jun 07 21:53:56 2009 -0700
    12.3 @@ -26,7 +26,7 @@
    12.4              forKeychain: (SecKeychainRef)keychain {
    12.5      Assert(keyData!=nil);
    12.6      SecKeyImportExportParameters params = {};
    12.7 -    SecKeyRef key = importKey(keyData, self.keyType, keychain, &params);
    12.8 +    SecKeyRef key = importKey(keyData, self.keyClass, keychain, &params);
    12.9      if (!key) {
   12.10          [self release];
   12.11          return nil;
   12.12 @@ -45,10 +45,15 @@
   12.13      return $sprintf(@"%@[%@ /%p]", [self class], (self.name ?:@""), self.keychainItemRef);
   12.14  }
   12.15  
   12.16 -- (SecExternalItemType) keyType {
   12.17 +- (SecExternalItemType) keyClass {
   12.18      AssertAbstractMethod();
   12.19  }
   12.20  
   12.21 +#if MYCRYPTO_USE_IPHONE_API
   12.22 +- (SecExternalItemType) keyType {
   12.23 +    return NULL;
   12.24 +}
   12.25 +#endif
   12.26  
   12.27  - (SecKeyRef) keyRef {
   12.28      return (SecKeyRef) self.keychainItemRef;
    13.1 --- a/MYKeychain-iPhone.m	Sat Jun 06 15:36:35 2009 -0700
    13.2 +++ b/MYKeychain-iPhone.m	Sun Jun 07 21:53:56 2009 -0700
    13.3 @@ -19,6 +19,7 @@
    13.4      CFArrayRef _results;
    13.5      CFTypeRef _itemClass;
    13.6      CFIndex _index;
    13.7 +    MYKeychainItem *_currentObject;
    13.8  }
    13.9  
   13.10  - (id) initWithQuery: (NSMutableDictionary*)query;
   13.11 @@ -62,78 +63,57 @@
   13.12  
   13.13  - (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
   13.14      return [MYKeyEnumerator firstItemWithQuery:
   13.15 -                $mdict({(id)kSecClass, (id)kSecClassKey},
   13.16 -                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
   13.17 -                      {(id)kSecReturnRef, $true})];
   13.18 +                $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic},
   13.19 +                       {(id)kSecAttrApplicationLabel, pubKeyDigest.asData})];
   13.20  }   
   13.21  
   13.22  - (NSEnumerator*) enumeratePublicKeys {
   13.23 -    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   13.24 -                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic},
   13.25 -                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   13.26 -                                {(id)kSecReturnRef, $true});
   13.27 +    NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic});
   13.28      return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   13.29  }
   13.30  
   13.31  
   13.32  - (MYPrivateKey*) privateKeyWithDigest: (MYSHA1Digest*)pubKeyDigest {
   13.33      return [MYKeyEnumerator firstItemWithQuery:
   13.34 -                $mdict({(id)kSecClass, (id)kSecClassKey},
   13.35 -                      {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
   13.36 -                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
   13.37 -                      {(id)kSecReturnRef, $true})];
   13.38 +                $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
   13.39 +                       {(id)kSecAttrApplicationLabel, pubKeyDigest.asData})];
   13.40  }
   13.41  
   13.42  - (NSEnumerator*) enumeratePrivateKeys {
   13.43 -    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   13.44 -                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate},
   13.45 -                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   13.46 -                                {(id)kSecReturnRef, $true});
   13.47 +    NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate});
   13.48      return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   13.49  }
   13.50  
   13.51  - (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest {
   13.52      return [MYKeyEnumerator firstItemWithQuery:
   13.53                  $mdict({(id)kSecClass, (id)kSecClassCertificate},
   13.54 -                      {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
   13.55 -                      {(id)kSecReturnRef, $true})];
   13.56 +                       {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})];
   13.57  }
   13.58  
   13.59  - (NSEnumerator*) enumerateCertificates {
   13.60 -    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate},
   13.61 -                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   13.62 -                                {(id)kSecReturnRef, $true});
   13.63 +    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate});
   13.64      return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   13.65  }
   13.66  
   13.67  - (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest {
   13.68      return [MYKeyEnumerator firstItemWithQuery:
   13.69                  $mdict({(id)kSecClass, (id)kSecClassIdentity},
   13.70 -                        {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData},
   13.71 -                        {(id)kSecReturnRef, $true})];
   13.72 +                        {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})];
   13.73  }
   13.74  
   13.75  - (NSEnumerator*) enumerateIdentities {
   13.76 -    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity},
   13.77 -                                        {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   13.78 -                                        {(id)kSecReturnRef, $true});
   13.79 +    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity});
   13.80      return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   13.81  }
   13.82  
   13.83  - (NSEnumerator*) enumerateSymmetricKeys {
   13.84 -    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   13.85 -                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   13.86 -                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   13.87 -                                {(id)kSecReturnRef, $true});
   13.88 +    NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric});
   13.89      return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
   13.90  }
   13.91  
   13.92  - (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias {
   13.93 -    NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey},
   13.94 -                                {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   13.95 -                                {(id)kSecAttrApplicationTag, alias},
   13.96 -                                {(id)kSecMatchLimit, (id)kSecMatchLimitAll},
   13.97 -                                {(id)kSecReturnRef, $true});
   13.98 +    NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   13.99 +                                        {(id)kSecAttrApplicationTag, alias});
  13.100      return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease];
  13.101  }
  13.102  
  13.103 @@ -187,33 +167,54 @@
  13.104  - (id) initWithQuery: (NSMutableDictionary*)query {
  13.105      self = [super init];
  13.106      if (self) {
  13.107 -        if (![query objectForKey: (id)kSecMatchLimit])
  13.108 -            [query setObject: (id)kSecMatchLimitAll forKey: (id)kSecMatchLimit];
  13.109 +        _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass];
  13.110 +        if (_itemClass)
  13.111 +            [query setObject: (id)kSecClassKey forKey: (id)kSecClass];
  13.112 +        else
  13.113 +            _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass];
  13.114 +        Assert(_itemClass);
  13.115 +        CFRetain(_itemClass);
  13.116 +
  13.117 +        // Ask for all results unless caller specified fewer:
  13.118 +        CFTypeRef limit = [query objectForKey: (id)kSecMatchLimit];
  13.119 +        if (! limit) {
  13.120 +            limit = kSecMatchLimitAll;
  13.121 +            [query setObject: (id)limit forKey: (id)kSecMatchLimit];
  13.122 +        }
  13.123 +        
  13.124 +        [query setObject: $true forKey: (id)kSecReturnRef];
  13.125 +        
  13.126          OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&_results);
  13.127          if (err && err != errSecItemNotFound) {
  13.128              check(err,@"SecItemCopyMatching");
  13.129              [self release];
  13.130              return nil;
  13.131          }
  13.132 -        if (_results) CFRetain(_results);
  13.133 -        _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass];
  13.134 -        if (_itemClass == kSecClassKey)
  13.135 -            _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass];
  13.136 -        if (_itemClass) CFRetain(_itemClass);
  13.137 +        Log(@"Enumerator results = %@", _results);//TEMP
  13.138 +        
  13.139 +        if (_results && CFEqual(limit,kSecMatchLimitOne)) {
  13.140 +            // If you ask for only one, it gives you the object back instead of an array:
  13.141 +            CFArrayRef resultsArray = CFArrayCreate(NULL, (const void**)&_results, 1, 
  13.142 +                                                    &kCFTypeArrayCallBacks);
  13.143 +            CFRelease(_results);
  13.144 +            _results = resultsArray;
  13.145 +        }
  13.146      }
  13.147      return self;
  13.148  }
  13.149  
  13.150  + (id) firstItemWithQuery: (NSMutableDictionary*)query {
  13.151 +    [query setObject: (id)kSecMatchLimitOne forKey: (id)kSecMatchLimit];
  13.152      MYKeyEnumerator *e = [[self alloc] initWithQuery: query];
  13.153 -    MYKeychainItem *item = e.nextObject;
  13.154 +    MYKeychainItem *item = [e.nextObject retain];
  13.155      [e release];
  13.156 -    return item;
  13.157 +    return [item autorelease];
  13.158  }    
  13.159  
  13.160  - (void) dealloc
  13.161  {
  13.162 -    if (_itemClass) CFRelease(_itemClass);
  13.163 +    [_currentObject release];
  13.164 +    CFRelease(_itemClass);
  13.165      if (_results) CFRelease(_results);
  13.166      [super dealloc];
  13.167  }
  13.168 @@ -222,23 +223,24 @@
  13.169  - (id) nextObject {
  13.170      if (!_results)
  13.171          return nil;
  13.172 -    MYKeychainItem *next = nil;
  13.173 -    while (next==nil && _index < CFArrayGetCount(_results)) {
  13.174 +    setObj(&_currentObject,nil);
  13.175 +    while (_currentObject==nil && _index < CFArrayGetCount(_results)) {
  13.176          CFTypeRef found = CFArrayGetValueAtIndex(_results, _index++); 
  13.177          if (_itemClass == kSecAttrKeyClassPrivate) {
  13.178 -            next = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
  13.179 +            _currentObject = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
  13.180          } else if (_itemClass == kSecAttrKeyClassPublic) {
  13.181 -            next = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
  13.182 +            _currentObject = [[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found];
  13.183          } else if (_itemClass == kSecAttrKeyClassSymmetric) {
  13.184 -            next = [[[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease];
  13.185 +            _currentObject = [[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found];
  13.186          } else if (_itemClass == kSecClassCertificate) {
  13.187 -            next = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease];
  13.188 +            _currentObject = [[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found];
  13.189          } else if (_itemClass == kSecClassIdentity) {
  13.190 -            next = [[[MYIdentity alloc] initWithIdentityRef: (SecIdentityRef)found] autorelease];
  13.191 +            _currentObject = [[MYIdentity alloc] initWithIdentityRef: (SecIdentityRef)found];
  13.192 +        } else  {
  13.193 +            Assert(NO,@"Unknown _itemClass: %@",_itemClass);
  13.194          }
  13.195 -        CFRelease(found);
  13.196      }
  13.197 -    return next;
  13.198 +    return _currentObject;
  13.199  }
  13.200  
  13.201  
    14.1 --- a/MYKeychainItem.m	Sat Jun 06 15:36:35 2009 -0700
    14.2 +++ b/MYKeychainItem.m	Sun Jun 07 21:53:56 2009 -0700
    14.3 @@ -17,13 +17,14 @@
    14.4  @implementation MYKeychainItem
    14.5  
    14.6  
    14.7 -- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef;
    14.8 +- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef
    14.9  {
   14.10      Assert(itemRef!=NULL);
   14.11      self = [super init];
   14.12      if (self != nil) {
   14.13          _itemRef = itemRef;
   14.14          CFRetain(_itemRef);
   14.15 +        LogTo(INIT,@"%@, _itemRef=%@", [self class], itemRef);
   14.16      }
   14.17      return self;
   14.18  }
   14.19 @@ -213,6 +214,8 @@
   14.20              return checkcssm(err,what);
   14.21  #endif
   14.22          Warn(@"MYCrypto error, %@: %@", what, MYErrorName(NSOSStatusErrorDomain,err));
   14.23 +        if (err==-50)
   14.24 +            [NSException raise: NSGenericException format: @"%@ failed with paramErr (-50)",what];
   14.25          return NO;
   14.26      } else
   14.27          return YES;
    15.1 --- a/MYPrivateKey.m	Sat Jun 06 15:36:35 2009 -0700
    15.2 +++ b/MYPrivateKey.m	Sun Jun 07 21:53:56 2009 -0700
    15.3 @@ -175,11 +175,18 @@
    15.4  
    15.5  @synthesize publicKey=_publicKey;
    15.6  
    15.7 -- (MYSHA1Digest*) publicKeyDigest {
    15.8 -    return _publicKey.publicKeyDigest;
    15.9 +- (MYSHA1Digest*) _keyDigest {
   15.10 +    if (_publicKey)
   15.11 +        return _publicKey.publicKeyDigest;
   15.12 +    else
   15.13 +        return [MYSHA1Digest digestFromDigestData: [self _attribute: kSecAttrApplicationLabel]];
   15.14  }
   15.15  
   15.16 -- (SecExternalItemType) keyType {
   15.17 +- (MYSHA1Digest*) publicKeyDigest {
   15.18 +    return self._keyDigest;
   15.19 +}
   15.20 +
   15.21 +- (SecExternalItemType) keyClass {
   15.22  #if MYCRYPTO_USE_IPHONE_API
   15.23      return kSecAttrKeyClassPublic;
   15.24  #else
   15.25 @@ -187,6 +194,12 @@
   15.26  #endif
   15.27  }
   15.28  
   15.29 +#if MYCRYPTO_USE_IPHONE_API
   15.30 +- (SecExternalItemType) keyType {
   15.31 +    return kSecAttrKeyTypeRSA;
   15.32 +}
   15.33 +#endif
   15.34 +
   15.35  - (NSData *) keyData {
   15.36      [NSException raise: NSGenericException format: @"Can't access keyData of a PrivateKey"];
   15.37      return nil;
    16.1 --- a/MYPublicKey.m	Sat Jun 06 15:36:35 2009 -0700
    16.2 +++ b/MYPublicKey.m	Sun Jun 07 21:53:56 2009 -0700
    16.3 @@ -36,7 +36,7 @@
    16.4      [super dealloc];
    16.5  }
    16.6  
    16.7 -- (SecExternalItemType) keyType {
    16.8 +- (SecExternalItemType) keyClass {
    16.9  #if MYCRYPTO_USE_IPHONE_API
   16.10      return kSecAttrKeyClassPublic;
   16.11  #else
   16.12 @@ -44,6 +44,16 @@
   16.13  #endif
   16.14  }
   16.15  
   16.16 +#if MYCRYPTO_USE_IPHONE_API
   16.17 +- (SecExternalItemType) keyType {
   16.18 +    return kSecAttrKeyTypeRSA;
   16.19 +}
   16.20 +
   16.21 +- (MYSHA1Digest*) _keyDigest {
   16.22 +    return (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: [self _attribute: kSecAttrApplicationLabel]];
   16.23 +}
   16.24 +#endif
   16.25 +
   16.26  - (NSUInteger)hash {
   16.27      return self.publicKeyDigest.hash;
   16.28  }
    17.1 --- a/MYSymmetricKey-iPhone.m	Sat Jun 06 15:36:35 2009 -0700
    17.2 +++ b/MYSymmetricKey-iPhone.m	Sun Jun 07 21:53:56 2009 -0700
    17.3 @@ -43,27 +43,27 @@
    17.4      Assert(algorithm <= kCCAlgorithmRC4);
    17.5      Assert(keyData);
    17.6      NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8];
    17.7 -    NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey},
    17.8 -                                    //{(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
    17.9 -                                    {(id)kSecAttrKeyType, [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]},
   17.10 -                                    {(id)kSecAttrKeySizeInBits, keySizeInBits},
   17.11 -                                    {(id)kSecAttrEffectiveKeySize, keySizeInBits},
   17.12 -                                    {(id)kSecAttrIsPermanent, keychain ?$true :$false},
   17.13 -                                    {(id)kSecAttrCanEncrypt, $true},
   17.14 -                                    {(id)kSecAttrCanDecrypt, $true},
   17.15 -                                    {(id)kSecAttrCanWrap, $false},
   17.16 -                                    {(id)kSecAttrCanUnwrap, $false},
   17.17 -                                    {(id)kSecAttrCanDerive, $false},
   17.18 -                                    {(id)kSecAttrCanSign, $false},
   17.19 -                                    {(id)kSecAttrCanVerify, $false},
   17.20 -                                    {(id)kSecValueData, keyData},
   17.21 -                                    {(id)kSecReturnPersistentRef, $true});
   17.22 -    SecKeyRef keyRef = NULL;
   17.23 -    if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd")) {
   17.24 +    NSNumber *keyType = [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]];
   17.25 +    NSMutableDictionary *keyAttrs = $mdict( {(id)kSecClass, (id)kSecClassKey},
   17.26 +                                            {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric},
   17.27 +                                            {(id)kSecAttrKeyType, keyType},
   17.28 +                                            {(id)kSecValueData, keyData},
   17.29 +                                            {(id)kSecAttrKeySizeInBits, keySizeInBits},
   17.30 +                                            {(id)kSecAttrEffectiveKeySize, keySizeInBits},
   17.31 +                                            {(id)kSecAttrIsPermanent, keychain ?$true :$false},
   17.32 +                                            {(id)kSecAttrCanEncrypt, $true},
   17.33 +                                            {(id)kSecAttrCanDecrypt, $true},
   17.34 +                                            {(id)kSecAttrCanWrap, $false},
   17.35 +                                            {(id)kSecAttrCanUnwrap, $false},
   17.36 +                                            {(id)kSecAttrCanDerive, $false},
   17.37 +                                            {(id)kSecAttrCanSign, $false},
   17.38 +                                            {(id)kSecAttrCanVerify, $false},
   17.39 +                                            {(id)kSecReturnPersistentRef, $true});
   17.40 +    SecKeyRef keyRef = [[self class] _addKeyWithInfo: keyAttrs];
   17.41 +    if (!keyRef) {
   17.42          [self release];
   17.43          return nil;
   17.44      }
   17.45 -    Assert(keyRef, @"SecItemAdd didn't return anything");
   17.46      self = [self initWithKeyRef: keyRef];
   17.47      CFRelease(keyRef);
   17.48      return self;
   17.49 @@ -93,7 +93,7 @@
   17.50  }
   17.51  
   17.52  
   17.53 -- (SecExternalItemType) keyType {
   17.54 +- (SecExternalItemType) keyClass {
   17.55      return kSecAttrKeyClassSymmetric;
   17.56  }
   17.57  
    18.1 --- a/MYSymmetricKey.m	Sat Jun 06 15:36:35 2009 -0700
    18.2 +++ b/MYSymmetricKey.m	Sun Jun 07 21:53:56 2009 -0700
    18.3 @@ -283,7 +283,7 @@
    18.4  #endif
    18.5  
    18.6  
    18.7 -- (SecExternalItemType) keyType {
    18.8 +- (SecExternalItemType) keyClass {
    18.9      return kSecItemTypeSessionKey;
   18.10  }
   18.11