# HG changeset patch # User Jens Alfke # Date 1244436836 25200 # Node ID 39fec79de6e85b629a9ede44c890f586fa642255 # Parent 058394513f333982f519a75517199622c0b00e32 A snapshot taken during the long, agonizing crawl toward getting everything running on iPhone. diff -r 058394513f33 -r 39fec79de6e8 MYCertificate-iPhone.m --- a/MYCertificate-iPhone.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYCertificate-iPhone.m Sun Jun 07 21:53:56 2009 -0700 @@ -97,6 +97,10 @@ return name ?[(id)CFMakeCollectable(name) autorelease] :nil; } +- (NSArray*) emailAddresses { + NSString *email = self.info.subject.emailAddress; + return email ?$array(email) :nil; +} @end diff -r 058394513f33 -r 39fec79de6e8 MYCertificate.h --- a/MYCertificate.h Sat Jun 06 15:36:35 2009 -0700 +++ b/MYCertificate.h Sun Jun 07 21:53:56 2009 -0700 @@ -52,6 +52,9 @@ /** The common name of the subject (owner) of the certificate. */ @property (readonly) NSString *commonName; +/** The list (if any) of the subject's email addresses. */ +@property (readonly) NSArray *emailAddresses; + /** @name Mac-Only * Functionality not available on iPhone. @@ -64,9 +67,6 @@ type: (CSSM_CERT_TYPE) type encoding: (CSSM_CERT_ENCODING) encoding; -/** The list (if any) of the subject's email addresses. */ -@property (readonly) NSArray *emailAddresses; - /** Finds the current 'preferred' certificate for the given name string. */ + (MYCertificate*) preferredCertificateForName: (NSString*)name; diff -r 058394513f33 -r 39fec79de6e8 MYCertificateInfo.m --- a/MYCertificateInfo.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYCertificateInfo.m Sun Jun 07 21:53:56 2009 -0700 @@ -179,8 +179,18 @@ [MYBitString bitStringWithData: publicKey.keyData] ) ) ); self = [super initWithRoot: root]; [version release]; + if (self) { + _publicKey = publicKey.retain; + } return self; } + +- (void) dealloc +{ + [_publicKey release]; + [super dealloc]; +} + - (NSDate*) validFrom {return [super validFrom];} - (NSDate*) validTo {return [super validTo];} @@ -244,11 +254,14 @@ - (MYIdentity*) createSelfSignedIdentityWithPrivateKey: (MYPrivateKey*)privateKey error: (NSError**)outError { + Assert(privateKey.keychain!=nil); NSData *certData = [self selfSignWithPrivateKey: privateKey error: outError]; if (!certData) return nil; MYCertificate *cert = [privateKey.keychain importCertificate: certData]; Assert(cert!=nil); + Assert(cert.keychain!=nil); + AssertEqual(cert.publicKey.keyData, _publicKey.keyData); MYIdentity *identity = cert.identity; Assert(identity!=nil); return identity; @@ -329,10 +342,9 @@ #if DEBUG -static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) { - Log(@"--- Creating MYCertificateInfo from %@", filename); - NSData *certData = [NSData dataWithContentsOfFile: filename]; +static MYCertificateInfo* testCertData(NSData *certData, BOOL selfSigned) { //Log(@"Cert Data =\n%@", certData); + CAssert(certData!=nil); NSError *error = nil; MYCertificateInfo *pcert = [[MYCertificateInfo alloc] initWithCertificateData: certData error: &error]; @@ -359,10 +371,21 @@ return pcert; } +static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) { +#if TARGET_OS_IPHONE + filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"]; +#else + filename = [[@"../../Tests/" stringByAppendingPathComponent: filename] + stringByAppendingPathExtension: @"cer"]; +#endif + Log(@"--- Creating MYCertificateInfo from %@", filename); + return testCertData([NSData dataWithContentsOfFile: filename], selfSigned); +} + TestCase(ParsedCert) { - testCert(@"../../Tests/selfsigned.cer", YES); - testCert(@"../../Tests/iphonedev.cer", NO); + testCert(@"selfsigned", YES); + testCert(@"iphonedev", NO); } @@ -395,8 +418,10 @@ CAssert(certData); CAssertNil(error); CAssert(certData); +#if !TARGET_OS_IPHONE [certData writeToFile: @"../../Tests/generated.cer" atomically: YES]; - MYCertificateInfo *pcert2 = testCert(@"../../Tests/generated.cer", YES); +#endif + MYCertificateInfo *pcert2 = testCertData(certData, YES); Log(@"Verifying Info..."); MYCertificateName *subject2 = pcert2.subject; diff -r 058394513f33 -r 39fec79de6e8 MYCrypto-iPhone.xcodeproj/project.pbxproj --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj Sat Jun 06 15:36:35 2009 -0700 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj Sun Jun 07 21:53:56 2009 -0700 @@ -25,6 +25,8 @@ 276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB3180F856AA700CB326E /* MYPublicKey.m */; }; 276FB33B0F856ACB00CB326E /* MYKeychain.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB33A0F856ACB00CB326E /* MYKeychain.m */; }; 276FB34B0F856CA400CB326E /* MYCertificate.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB34A0F856CA400CB326E /* MYCertificate.m */; }; + 27958CA30FDB5F8F00095275 /* iphonedev.cer in Resources */ = {isa = PBXBuildFile; fileRef = 27958CA10FDB5F8F00095275 /* iphonedev.cer */; }; + 27958CA40FDB5F8F00095275 /* selfsigned.cer in Resources */ = {isa = PBXBuildFile; fileRef = 27958CA20FDB5F8F00095275 /* selfsigned.cer */; }; 27A430120F87C6C10063D362 /* MYKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27E823110F81D56E0019BE60 /* MYKey.m */; }; 27A430140F87C6D50063D362 /* MYSymmetricKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 27A430130F87C6D50063D362 /* MYSymmetricKey.m */; }; 27CD85DD0FDB1A82006BCB47 /* MYCertificateInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 27CD85DC0FDB1A82006BCB47 /* MYCertificateInfo.m */; }; @@ -70,6 +72,8 @@ 276FB3180F856AA700CB326E /* MYPublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPublicKey.m; sourceTree = ""; }; 276FB33A0F856ACB00CB326E /* MYKeychain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYKeychain.m; sourceTree = ""; }; 276FB34A0F856CA400CB326E /* MYCertificate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificate.m; sourceTree = ""; }; + 27958CA10FDB5F8F00095275 /* iphonedev.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = iphonedev.cer; path = Tests/iphonedev.cer; sourceTree = ""; }; + 27958CA20FDB5F8F00095275 /* selfsigned.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = selfsigned.cer; path = Tests/selfsigned.cer; sourceTree = ""; }; 27A430130F87C6D50063D362 /* MYSymmetricKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYSymmetricKey.m; sourceTree = ""; }; 27A430150F87C6DB0063D362 /* MYSymmetricKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYSymmetricKey.h; sourceTree = ""; }; 27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCryptoConfig.h; sourceTree = ""; }; @@ -155,6 +159,8 @@ 275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */, 275D9FEB0FD8795300D85A86 /* MYOID.h */, 275D9FEC0FD8795300D85A86 /* MYOID.m */, + 27958CA10FDB5F8F00095275 /* iphonedev.cer */, + 27958CA20FDB5F8F00095275 /* selfsigned.cer */, ); name = Certificates; sourceTree = ""; @@ -291,6 +297,8 @@ 27E823290F81D56E0019BE60 /* MYCrypto.xcconfig in Resources */, 27E8232A0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig in Resources */, 27E8233C0F81D5760019BE60 /* MYError_CSSMErrorDomain.strings in Resources */, + 27958CA30FDB5F8F00095275 /* iphonedev.cer in Resources */, + 27958CA40FDB5F8F00095275 /* selfsigned.cer in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff -r 058394513f33 -r 39fec79de6e8 MYCryptoTest.m --- a/MYCryptoTest.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYCryptoTest.m Sun Jun 07 21:53:56 2009 -0700 @@ -43,23 +43,44 @@ } -TestCase(EnumerateKeys) { +TestCase(Enumerate) { + RequireTestCase(EnumeratePublicKeys); + RequireTestCase(EnumeratePrivateKeys); + RequireTestCase(EnumerateSymmetricKeys); + RequireTestCase(EnumerateCerts); + RequireTestCase(EnumerateIdentities); +} + + +TestCase(EnumeratePublicKeys) { RequireTestCase(MYKeychain); NSEnumerator *e = [[MYKeychain allKeychains] enumeratePublicKeys]; Log(@"Public Key Enumerator = %@", e); CAssert(e); for (MYPublicKey *key in e) { - Log(@"Found %@ -- name=%@", key, key.name); + Log(@"Trying public key %@", key.keyRef); + @try{ + Log(@"Found %@ -- name=%@", key, key.name); + }@catch (NSException *x) { + Warn(@"Caught %@",x); //TEMP + } } - - e = [[MYKeychain allKeychains] enumeratePrivateKeys]; +} + +TestCase(EnumeratePrivateKeys) { + RequireTestCase(MYKeychain); + NSEnumerator *e = [[MYKeychain allKeychains] enumeratePrivateKeys]; Log(@"Key-Pair Enumerator = %@", e); CAssert(e); for (MYPrivateKey *key in e) { - Log(@"Found %@ -- name=%@", key, key.name); + Log(@"Found %@ -- name=%@ --> %@", key, key.name, key.publicKey); + CAssert(key.publicKey); } - - e = [[MYKeychain allKeychains] enumerateSymmetricKeys]; +} + +TestCase(EnumerateSymmetricKeys) { + RequireTestCase(MYKeychain); + NSEnumerator *e = [[MYKeychain allKeychains] enumerateSymmetricKeys]; Log(@"Symmetric Key Enumerator = %@", e); CAssert(e); for (MYSymmetricKey *key in e) { @@ -74,7 +95,8 @@ Log(@"Enumerator = %@", e); CAssert(e); for (MYCertificate *cert in e) { - //Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses); + Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses); + CAssert(cert.publicKey); } } @@ -112,7 +134,7 @@ else key = [MYSymmetricKey generateSymmetricKeyOfSize: sizeInBits algorithm: algorithm]; Log(@"Created %@", key); - CAssert(key); + CAssert(key); CAssertEq(key.algorithm, algorithm); CAssertEq(key.keySizeInBits, sizeInBits); #if !TARGET_OS_IPHONE diff -r 058394513f33 -r 39fec79de6e8 MYCrypto_Private.h --- a/MYCrypto_Private.h Sat Jun 06 15:36:35 2009 -0700 +++ b/MYCrypto_Private.h Sun Jun 07 21:53:56 2009 -0700 @@ -53,10 +53,12 @@ - (id) initWithKeyData: (NSData*)data; - (id) _initWithKeyData: (NSData*)data forKeychain: (SecKeychainRef)keychain; -@property (readonly) SecExternalItemType keyType; +@property (readonly) SecExternalItemType keyClass, keyType; @property (readonly) MYSHA1Digest* _keyDigest; - (NSData*) _crypt: (NSData *)data operation: (BOOL) op; // YES to encrypt, NO to decrypt -#if !MYCRYPTO_USE_IPHONE_API +#if MYCRYPTO_USE_IPHONE_API ++ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info; +#else @property (readonly) const CSSM_KEY* cssmKey; @property (readonly) const CSSM_CSP_HANDLE cssmCSPHandle; - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm; diff -r 058394513f33 -r 39fec79de6e8 MYDigest.h --- a/MYDigest.h Sat Jun 06 15:36:35 2009 -0700 +++ b/MYDigest.h Sun Jun 07 21:53:56 2009 -0700 @@ -24,16 +24,16 @@ - (id) initWithRawDigest: (const void*)rawDigest length: (size_t)length; /** Wraps an existing digest, stored in an NSData object, in a MYDigest object. */ -+ (MYDigest*) digestFromDigestData: (NSData*)digestData; ++ (id) digestFromDigestData: (NSData*)digestData; /** Wraps an existing digest, expressed as a hex string, in a MYDigest object. */ -+ (MYDigest*) digestFromHexString: (NSString*)hexString; ++ (id) digestFromHexString: (NSString*)hexString; /** Computes a cryptographic digest of the given data. */ -+ (MYDigest*) digestOfData: (NSData*)data; ++ (id) digestOfData: (NSData*)data; /** Computes a cryptographic digest of the given data. */ -+ (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length; ++ (id) digestOfBytes: (const void*)bytes length: (size_t)length; /** Returns the digest as an NSData object. */ @property (readonly) NSData *asData; diff -r 058394513f33 -r 39fec79de6e8 MYDigest.m --- a/MYDigest.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYDigest.m Sun Jun 07 21:53:56 2009 -0700 @@ -79,11 +79,11 @@ } -+ (MYDigest*) digestFromDigestData: (NSData*)digestData { ++ (id) digestFromDigestData: (NSData*)digestData { return [[[self alloc] initWithRawDigest: digestData.bytes length: digestData.length] autorelease]; } -+ (MYDigest*) digestFromHexString: (NSString*)hexString ++ (id) digestFromHexString: (NSString*)hexString { const char *cStr = [hexString UTF8String]; const size_t length = [self length]; @@ -98,10 +98,11 @@ return [[[self alloc] initWithRawDigest: &digest length: length] autorelease]; } -+ (MYDigest*) digestOfData: (NSData*)data { ++ (id) digestOfData: (NSData*)data { return [self digestOfBytes: data.bytes length: data.length]; } -+ (MYDigest*) digestOfBytes: (const void*)bytes length: (size_t)length { + ++ (id) digestOfBytes: (const void*)bytes length: (size_t)length { const size_t digestLength = [self length]; uint8_t digest[digestLength]; [self computeDigest: digest ofBytes: bytes length: length]; diff -r 058394513f33 -r 39fec79de6e8 MYIdentity.m --- a/MYIdentity.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYIdentity.m Sun Jun 07 21:53:56 2009 -0700 @@ -35,19 +35,21 @@ } -#if !TARGET_OS_IPHONE - (id) initWithCertificateRef: (SecCertificateRef)certificateRef { self = [super initWithCertificateRef: certificateRef]; if (self) { +#if !MYCRYPTO_USE_IPHONE_API if (!check(SecIdentityCreateWithCertificate(NULL, certificateRef, &_identityRef), @"SecIdentityCreateWithCertificate")) { [self release]; return nil; } +#else + Assert(NO,@"-[MYIdentity initWithCertificateRef] isn't implemented for iPhone yet!");//FIX +#endif } return self; } -#endif - (void) dealloc { @@ -69,7 +71,7 @@ if (!check(SecIdentityCopyPrivateKey(_identityRef, &keyRef), @"SecIdentityCopyPrivateKey")) return NULL; MYPrivateKey *privateKey = [[MYPrivateKey alloc] _initWithKeyRef: keyRef - publicKey: self.publicKey]; + publicKey: self.publicKey]; CFRelease(keyRef); return [privateKey autorelease]; } diff -r 058394513f33 -r 39fec79de6e8 MYKey-iPhone.m --- a/MYKey-iPhone.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYKey-iPhone.m Sun Jun 07 21:53:56 2009 -0700 @@ -19,6 +19,45 @@ @implementation MYKey ++ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info { + if (![info objectForKey: (id)kSecAttrApplicationTag]) { + // Every keychain item has to have a unique tag, apparently, or you'll get spurious + // duplicate-item errors. If none was given, make up a random one: + UInt8 tag[16]; + Assert(check(SecRandomCopyBytes(kSecRandomDefault, sizeof(tag), tag), @"SecRandomCopyBytes")); + [info setObject: [NSData dataWithBytes: tag length: sizeof(tag)] + forKey: (id)kSecAttrApplicationTag]; + } + CFDataRef keyPersistentRef; + SecKeyRef key; + OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&keyPersistentRef); + if (err==errSecDuplicateItem) { + // it's already in the keychain -- get a reference to it: + [info removeObjectForKey: (id)kSecReturnPersistentRef]; + [info setObject: $true forKey: (id)kSecReturnRef]; + if (check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key), + @"SecItemCopyMatching")) + return key; + } else if (check(err, @"SecItemAdd")) { + // It was added + if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) { + // now get its SecKeyRef: + info = $mdict({(id)kSecValuePersistentRef, (id)keyPersistentRef}, + {(id)kSecReturnRef, $true}); + err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&key); + CFRelease(keyPersistentRef); + if (check(err,@"SecItemCopyMatching")) { + Assert(key!=nil); + return key; + } + } else { + return (SecKeyRef)keyPersistentRef; + } + } + return NULL; +} + + - (id) initWithKeyRef: (SecKeyRef)key { return [super initWithKeychainItemRef: (SecKeychainItemRef)key]; } @@ -27,45 +66,65 @@ - (id) _initWithKeyData: (NSData*)data forKeychain: (SecKeychainRef)keychain { - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)self.keyType}, - {(id)kSecValueData, data}, - {(id)kSecAttrIsPermanent, $object(keychain!=nil)}, - {(id)kSecReturnRef, $true} ); - SecKeyRef key; - if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&key), @"SecItemAdd")) + NSMutableDictionary *info = $mdict({(id)kSecClass, (id)kSecClassKey}, + {(id)kSecAttrKeyType, (id)self.keyType}, + {(id)kSecValueData, data}, + {(id)kSecAttrIsPermanent, (keychain ?$true :$false)}, + {(id)kSecReturnPersistentRef, $true} ); + SecKeyRef key = [[self class] _addKeyWithInfo: info]; + if (!key) { + [self release]; return nil; - else - return [self initWithKeyRef: (SecKeyRef)key]; + } + self = [self initWithKeyRef: (SecKeyRef)key]; + if (self) { + if (!keychain) + _keyData = [data copy]; + } + return self; } - (id) initWithKeyData: (NSData*)data { return [self _initWithKeyData: data forKeychain: nil]; } +- (void) dealloc +{ + [_keyData release]; + [super dealloc]; +} -- (SecExternalItemType) keyType { + +- (SecExternalItemType) keyClass { AssertAbstractMethod(); } +- (SecExternalItemType) keyType { + return NULL; +} - (NSData*) keyData { - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)self.keyType}, - {(id)kSecMatchItemList, $array((id)self.keyRef)}, + if (_keyData) + return _keyData; + + NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef}, {(id)kSecReturnData, $true} ); CFDataRef data; if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching")) return nil; - else + else { + Assert(data!=NULL); return [(id)CFMakeCollectable(data) autorelease]; - + } // The format of this data is not documented. There's been some reverse-engineering: // https://devforums.apple.com/message/32089#32089 // Apparently it is a DER-formatted sequence of a modulus followed by an exponent. // This can be converted to OpenSSL format by wrapping it in some additional DER goop. } +- (MYSHA1Digest*) _keyDigest { + return [self.keyData my_SHA1Digest]; +} - (SecKeyRef) keyRef { return (SecKeyRef) self.keychainItemRef; @@ -73,13 +132,12 @@ - (id) _attribute: (CFTypeRef)attribute { - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)self.keyType}, - {(id)kSecMatchItemList, $array((id)self.keyRef)}, - {(id)kSecReturnAttributes, $true} ); + NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef}, + {(id)kSecReturnAttributes, $true}); CFDictionaryRef attrs = NULL; if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching")) return nil; + Log(@"_attribute: %@ of %@ %p", attribute, [self class], self.keyRef);//TEMP CFTypeRef rawValue = CFDictionaryGetValue(attrs,attribute); id value = rawValue ?[[(id)CFMakeCollectable(rawValue) retain] autorelease] :nil; CFRelease(attrs); @@ -90,7 +148,7 @@ if (!value) value = (id)[NSNull null]; NSDictionary *query = $dict( {(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)self.keyType}, + {(id)kSecAttrKeyClass, (id)self.keyClass}, {(id)kSecMatchItemList, self._itemList} ); NSDictionary *attrs = $dict( {(id)attribute, value} ); return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate"); diff -r 058394513f33 -r 39fec79de6e8 MYKey.h --- a/MYKey.h Sat Jun 06 15:36:35 2009 -0700 +++ b/MYKey.h Sun Jun 07 21:53:56 2009 -0700 @@ -28,7 +28,9 @@ /** Abstract superclass for keys. Concrete subclasses are MYSymmetricKey and MYPublicKey. */ @interface MYKey : MYKeychainItem -{ } +{ + NSData *_keyData; +} /** Creates a key from encoded data (but does not add it to any keychain.) */ - (id) initWithKeyData: (NSData*)data; diff -r 058394513f33 -r 39fec79de6e8 MYKey.m --- a/MYKey.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYKey.m Sun Jun 07 21:53:56 2009 -0700 @@ -26,7 +26,7 @@ forKeychain: (SecKeychainRef)keychain { Assert(keyData!=nil); SecKeyImportExportParameters params = {}; - SecKeyRef key = importKey(keyData, self.keyType, keychain, ¶ms); + SecKeyRef key = importKey(keyData, self.keyClass, keychain, ¶ms); if (!key) { [self release]; return nil; @@ -45,10 +45,15 @@ return $sprintf(@"%@[%@ /%p]", [self class], (self.name ?:@""), self.keychainItemRef); } -- (SecExternalItemType) keyType { +- (SecExternalItemType) keyClass { AssertAbstractMethod(); } +#if MYCRYPTO_USE_IPHONE_API +- (SecExternalItemType) keyType { + return NULL; +} +#endif - (SecKeyRef) keyRef { return (SecKeyRef) self.keychainItemRef; diff -r 058394513f33 -r 39fec79de6e8 MYKeychain-iPhone.m --- a/MYKeychain-iPhone.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYKeychain-iPhone.m Sun Jun 07 21:53:56 2009 -0700 @@ -19,6 +19,7 @@ CFArrayRef _results; CFTypeRef _itemClass; CFIndex _index; + MYKeychainItem *_currentObject; } - (id) initWithQuery: (NSMutableDictionary*)query; @@ -62,78 +63,57 @@ - (MYPublicKey*) publicKeyWithDigest: (MYSHA1Digest*)pubKeyDigest { return [MYKeyEnumerator firstItemWithQuery: - $mdict({(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData}, - {(id)kSecReturnRef, $true})]; + $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic}, + {(id)kSecAttrApplicationLabel, pubKeyDigest.asData})]; } - (NSEnumerator*) enumeratePublicKeys { - NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic}, - {(id)kSecMatchLimit, (id)kSecMatchLimitAll}, - {(id)kSecReturnRef, $true}); + NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPublic}); return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease]; } - (MYPrivateKey*) privateKeyWithDigest: (MYSHA1Digest*)pubKeyDigest { return [MYKeyEnumerator firstItemWithQuery: - $mdict({(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate}, - {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData}, - {(id)kSecReturnRef, $true})]; + $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate}, + {(id)kSecAttrApplicationLabel, pubKeyDigest.asData})]; } - (NSEnumerator*) enumeratePrivateKeys { - NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate}, - {(id)kSecMatchLimit, (id)kSecMatchLimitAll}, - {(id)kSecReturnRef, $true}); + NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassPrivate}); return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease]; } - (MYCertificate*) certificateWithDigest: (MYSHA1Digest*)pubKeyDigest { return [MYKeyEnumerator firstItemWithQuery: $mdict({(id)kSecClass, (id)kSecClassCertificate}, - {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData}, - {(id)kSecReturnRef, $true})]; + {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})]; } - (NSEnumerator*) enumerateCertificates { - NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate}, - {(id)kSecMatchLimit, (id)kSecMatchLimitAll}, - {(id)kSecReturnRef, $true}); + NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassCertificate}); return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease]; } - (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest { return [MYKeyEnumerator firstItemWithQuery: $mdict({(id)kSecClass, (id)kSecClassIdentity}, - {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData}, - {(id)kSecReturnRef, $true})]; + {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})]; } - (NSEnumerator*) enumerateIdentities { - NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity}, - {(id)kSecMatchLimit, (id)kSecMatchLimitAll}, - {(id)kSecReturnRef, $true}); + NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassIdentity}); return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease]; } - (NSEnumerator*) enumerateSymmetricKeys { - NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, - {(id)kSecMatchLimit, (id)kSecMatchLimitAll}, - {(id)kSecReturnRef, $true}); + NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}); return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease]; } - (NSEnumerator*) symmetricKeysWithAlias: (NSString*)alias { - NSMutableDictionary *query = $mdict({(id)kSecClass, (id)kSecClassKey}, - {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, - {(id)kSecAttrApplicationTag, alias}, - {(id)kSecMatchLimit, (id)kSecMatchLimitAll}, - {(id)kSecReturnRef, $true}); + NSMutableDictionary *query = $mdict({(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, + {(id)kSecAttrApplicationTag, alias}); return [[[MYKeyEnumerator alloc] initWithQuery: query] autorelease]; } @@ -187,33 +167,54 @@ - (id) initWithQuery: (NSMutableDictionary*)query { self = [super init]; if (self) { - if (![query objectForKey: (id)kSecMatchLimit]) - [query setObject: (id)kSecMatchLimitAll forKey: (id)kSecMatchLimit]; + _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass]; + if (_itemClass) + [query setObject: (id)kSecClassKey forKey: (id)kSecClass]; + else + _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass]; + Assert(_itemClass); + CFRetain(_itemClass); + + // Ask for all results unless caller specified fewer: + CFTypeRef limit = [query objectForKey: (id)kSecMatchLimit]; + if (! limit) { + limit = kSecMatchLimitAll; + [query setObject: (id)limit forKey: (id)kSecMatchLimit]; + } + + [query setObject: $true forKey: (id)kSecReturnRef]; + OSStatus err = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef*)&_results); if (err && err != errSecItemNotFound) { check(err,@"SecItemCopyMatching"); [self release]; return nil; } - if (_results) CFRetain(_results); - _itemClass = (CFTypeRef)[query objectForKey: (id)kSecClass]; - if (_itemClass == kSecClassKey) - _itemClass = (CFTypeRef)[query objectForKey: (id)kSecAttrKeyClass]; - if (_itemClass) CFRetain(_itemClass); + Log(@"Enumerator results = %@", _results);//TEMP + + if (_results && CFEqual(limit,kSecMatchLimitOne)) { + // If you ask for only one, it gives you the object back instead of an array: + CFArrayRef resultsArray = CFArrayCreate(NULL, (const void**)&_results, 1, + &kCFTypeArrayCallBacks); + CFRelease(_results); + _results = resultsArray; + } } return self; } + (id) firstItemWithQuery: (NSMutableDictionary*)query { + [query setObject: (id)kSecMatchLimitOne forKey: (id)kSecMatchLimit]; MYKeyEnumerator *e = [[self alloc] initWithQuery: query]; - MYKeychainItem *item = e.nextObject; + MYKeychainItem *item = [e.nextObject retain]; [e release]; - return item; + return [item autorelease]; } - (void) dealloc { - if (_itemClass) CFRelease(_itemClass); + [_currentObject release]; + CFRelease(_itemClass); if (_results) CFRelease(_results); [super dealloc]; } @@ -222,23 +223,24 @@ - (id) nextObject { if (!_results) return nil; - MYKeychainItem *next = nil; - while (next==nil && _index < CFArrayGetCount(_results)) { + setObj(&_currentObject,nil); + while (_currentObject==nil && _index < CFArrayGetCount(_results)) { CFTypeRef found = CFArrayGetValueAtIndex(_results, _index++); if (_itemClass == kSecAttrKeyClassPrivate) { - next = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found]; + _currentObject = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found]; } else if (_itemClass == kSecAttrKeyClassPublic) { - next = [[[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease]; + _currentObject = [[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found]; } else if (_itemClass == kSecAttrKeyClassSymmetric) { - next = [[[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found] autorelease]; + _currentObject = [[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found]; } else if (_itemClass == kSecClassCertificate) { - next = [[[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found] autorelease]; + _currentObject = [[MYCertificate alloc] initWithCertificateRef: (SecCertificateRef)found]; } else if (_itemClass == kSecClassIdentity) { - next = [[[MYIdentity alloc] initWithIdentityRef: (SecIdentityRef)found] autorelease]; + _currentObject = [[MYIdentity alloc] initWithIdentityRef: (SecIdentityRef)found]; + } else { + Assert(NO,@"Unknown _itemClass: %@",_itemClass); } - CFRelease(found); } - return next; + return _currentObject; } diff -r 058394513f33 -r 39fec79de6e8 MYKeychainItem.m --- a/MYKeychainItem.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYKeychainItem.m Sun Jun 07 21:53:56 2009 -0700 @@ -17,13 +17,14 @@ @implementation MYKeychainItem -- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef; +- (id) initWithKeychainItemRef: (MYKeychainItemRef)itemRef { Assert(itemRef!=NULL); self = [super init]; if (self != nil) { _itemRef = itemRef; CFRetain(_itemRef); + LogTo(INIT,@"%@, _itemRef=%@", [self class], itemRef); } return self; } @@ -213,6 +214,8 @@ return checkcssm(err,what); #endif Warn(@"MYCrypto error, %@: %@", what, MYErrorName(NSOSStatusErrorDomain,err)); + if (err==-50) + [NSException raise: NSGenericException format: @"%@ failed with paramErr (-50)",what]; return NO; } else return YES; diff -r 058394513f33 -r 39fec79de6e8 MYPrivateKey.m --- a/MYPrivateKey.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYPrivateKey.m Sun Jun 07 21:53:56 2009 -0700 @@ -175,11 +175,18 @@ @synthesize publicKey=_publicKey; -- (MYSHA1Digest*) publicKeyDigest { - return _publicKey.publicKeyDigest; +- (MYSHA1Digest*) _keyDigest { + if (_publicKey) + return _publicKey.publicKeyDigest; + else + return [MYSHA1Digest digestFromDigestData: [self _attribute: kSecAttrApplicationLabel]]; } -- (SecExternalItemType) keyType { +- (MYSHA1Digest*) publicKeyDigest { + return self._keyDigest; +} + +- (SecExternalItemType) keyClass { #if MYCRYPTO_USE_IPHONE_API return kSecAttrKeyClassPublic; #else @@ -187,6 +194,12 @@ #endif } +#if MYCRYPTO_USE_IPHONE_API +- (SecExternalItemType) keyType { + return kSecAttrKeyTypeRSA; +} +#endif + - (NSData *) keyData { [NSException raise: NSGenericException format: @"Can't access keyData of a PrivateKey"]; return nil; diff -r 058394513f33 -r 39fec79de6e8 MYPublicKey.m --- a/MYPublicKey.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYPublicKey.m Sun Jun 07 21:53:56 2009 -0700 @@ -36,7 +36,7 @@ [super dealloc]; } -- (SecExternalItemType) keyType { +- (SecExternalItemType) keyClass { #if MYCRYPTO_USE_IPHONE_API return kSecAttrKeyClassPublic; #else @@ -44,6 +44,16 @@ #endif } +#if MYCRYPTO_USE_IPHONE_API +- (SecExternalItemType) keyType { + return kSecAttrKeyTypeRSA; +} + +- (MYSHA1Digest*) _keyDigest { + return (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: [self _attribute: kSecAttrApplicationLabel]]; +} +#endif + - (NSUInteger)hash { return self.publicKeyDigest.hash; } diff -r 058394513f33 -r 39fec79de6e8 MYSymmetricKey-iPhone.m --- a/MYSymmetricKey-iPhone.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYSymmetricKey-iPhone.m Sun Jun 07 21:53:56 2009 -0700 @@ -43,27 +43,27 @@ Assert(algorithm <= kCCAlgorithmRC4); Assert(keyData); NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8]; - NSDictionary *keyAttrs = $dict( {(id)kSecClass, (id)kSecClassKey}, - //{(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, - {(id)kSecAttrKeyType, [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]}, - {(id)kSecAttrKeySizeInBits, keySizeInBits}, - {(id)kSecAttrEffectiveKeySize, keySizeInBits}, - {(id)kSecAttrIsPermanent, keychain ?$true :$false}, - {(id)kSecAttrCanEncrypt, $true}, - {(id)kSecAttrCanDecrypt, $true}, - {(id)kSecAttrCanWrap, $false}, - {(id)kSecAttrCanUnwrap, $false}, - {(id)kSecAttrCanDerive, $false}, - {(id)kSecAttrCanSign, $false}, - {(id)kSecAttrCanVerify, $false}, - {(id)kSecValueData, keyData}, - {(id)kSecReturnPersistentRef, $true}); - SecKeyRef keyRef = NULL; - if (!check(SecItemAdd((CFDictionaryRef)keyAttrs, (CFTypeRef*)&keyRef), @"SecItemAdd")) { + NSNumber *keyType = [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]; + NSMutableDictionary *keyAttrs = $mdict( {(id)kSecClass, (id)kSecClassKey}, + {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, + {(id)kSecAttrKeyType, keyType}, + {(id)kSecValueData, keyData}, + {(id)kSecAttrKeySizeInBits, keySizeInBits}, + {(id)kSecAttrEffectiveKeySize, keySizeInBits}, + {(id)kSecAttrIsPermanent, keychain ?$true :$false}, + {(id)kSecAttrCanEncrypt, $true}, + {(id)kSecAttrCanDecrypt, $true}, + {(id)kSecAttrCanWrap, $false}, + {(id)kSecAttrCanUnwrap, $false}, + {(id)kSecAttrCanDerive, $false}, + {(id)kSecAttrCanSign, $false}, + {(id)kSecAttrCanVerify, $false}, + {(id)kSecReturnPersistentRef, $true}); + SecKeyRef keyRef = [[self class] _addKeyWithInfo: keyAttrs]; + if (!keyRef) { [self release]; return nil; } - Assert(keyRef, @"SecItemAdd didn't return anything"); self = [self initWithKeyRef: keyRef]; CFRelease(keyRef); return self; @@ -93,7 +93,7 @@ } -- (SecExternalItemType) keyType { +- (SecExternalItemType) keyClass { return kSecAttrKeyClassSymmetric; } diff -r 058394513f33 -r 39fec79de6e8 MYSymmetricKey.m --- a/MYSymmetricKey.m Sat Jun 06 15:36:35 2009 -0700 +++ b/MYSymmetricKey.m Sun Jun 07 21:53:56 2009 -0700 @@ -283,7 +283,7 @@ #endif -- (SecExternalItemType) keyType { +- (SecExternalItemType) keyClass { return kSecItemTypeSessionKey; }