# HG changeset patch # User Jens Alfke # Date 1246483153 25200 # Node ID d9c2a06d4e4ef9786232f7b59621ff8e3aad87a1 # Parent 38c3c3923e1ff325050c79c94a189dbce6888045 Whew, lots and lots of changes accumulated over the past few weeks. Mostly fixes for bugs I discovered while retrofitting Cloudy to use MYCrypto. diff -r 38c3c3923e1f -r d9c2a06d4e4e MYBERParser.h --- a/MYBERParser.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYBERParser.h Wed Jul 01 14:19:13 2009 -0700 @@ -19,5 +19,6 @@ size_t MYBERGetLength (NSData *ber, NSError **outError); const void* MYBERGetContents (NSData *ber, NSError **outError); +/** A date formatter with the format string "yyyyMMddHHmmss'Z'" */ NSDateFormatter* MYBERGeneralizedTimeFormatter(); NSDateFormatter* MYBERUTCTimeFormatter(); diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCertificate.h --- a/MYCertificate.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYCertificate.h Wed Jul 01 14:19:13 2009 -0700 @@ -12,7 +12,7 @@ #import #endif -@class MYPublicKey, MYIdentity, MYCertificateInfo; +@class MYPublicKey, MYIdentity, MYCertificateInfo, MYSHA1Digest; /** An X.509 certificate. */ @@ -43,6 +43,9 @@ /** The certificate's public key. */ @property (readonly) MYPublicKey *publicKey; +/** The certificate's public key's SHA-1 digest. */ +@property (readonly) MYSHA1Digest *publicKeyDigest; + /** The Identity (if any) that this Certificate is part of. */ @property (readonly) MYIdentity *identity; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCertificate.m --- a/MYCertificate.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYCertificate.m Wed Jul 01 14:19:13 2009 -0700 @@ -157,9 +157,17 @@ return nil; MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease]; CFRelease(keyRef); +#if MYCRYPTO_USE_IPHONE_API + key.certificate = self; + key.isPersistent = NO; +#endif return key; } +- (MYSHA1Digest*) publicKeyDigest { + return self.publicKey.publicKeyDigest; +} + - (MYIdentity*) identity { return [[[MYIdentity alloc] initWithCertificateRef: _certificateRef] autorelease]; } @@ -214,7 +222,7 @@ if (!check(SecTrustEvaluate(trust, &result), @"SecTrustEvaluate")) result = kSecTrustResultOtherError; -#if 0 +#if !MYCRYPTO_USE_IPHONE_API // This is just to log details: CSSM_TP_APPLE_EVIDENCE_INFO *status; CFArrayRef certChain; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCertificateInfo.m --- a/MYCertificateInfo.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYCertificateInfo.m Wed Jul 01 14:19:13 2009 -0700 @@ -7,6 +7,7 @@ // // References: +// "RFC 3280: Internet X.509 Certificate Profile" // "Layman's Guide To ASN.1/BER/DER" // "X.509 Style Guide" // Wikipedia article on X.509 @@ -67,7 +68,7 @@ kSurnameOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 4} count: 4]; kDescriptionOID = [[MYOID alloc] initWithComponents: (UInt32[]){2, 5, 4, 13} - count: 7]; + count: 4]; kEmailOID = [[MYOID alloc] initWithComponents: (UInt32[]){1, 2, 840, 113549, 1, 9, 1} count: 7]; } @@ -160,14 +161,18 @@ } -- (MYPublicKey*) subjectPublicKey { +- (NSData*) subjectPublicKeyData { NSArray *keyInfo = $cast(NSArray, $atIf(self._info, 6)); MYOID *keyAlgorithmID = $castIf(MYOID, $atIf($castIf(NSArray,$atIf(keyInfo,0)), 0)); if (!$equal(keyAlgorithmID, kRSAAlgorithmID)) return nil; - MYBitString *keyData = $cast(MYBitString, $atIf(keyInfo, 1)); + return $cast(MYBitString, $atIf(keyInfo, 1)).bits; +} + +- (MYPublicKey*) subjectPublicKey { + NSData *keyData = self.subjectPublicKeyData; if (!keyData) return nil; - return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease]; + return [[[MYPublicKey alloc] initWithKeyData: keyData] autorelease]; } - (NSData*) signedData { @@ -364,10 +369,15 @@ - (void) setString: (NSString*)value forOID: (MYOID*)oid { NSMutableArray *pair = (NSMutableArray*) [self _pairForOID: oid]; - if (pair) - [pair replaceObjectAtIndex: 1 withObject: value]; - else - [(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]]; + if (pair) { + if (value) + [pair replaceObjectAtIndex: 1 withObject: value]; + else + Assert(NO,@"-setString:forOID: removing strings is unimplemented");//FIX + } else { + if (value) + [(NSMutableArray*)_components addObject: [NSSet setWithObject: $marray(oid,value)]]; + } } - (NSString*) commonName {return [self stringForOID: kCommonNameOID];} @@ -386,152 +396,6 @@ @end - -#pragma mark - -#pragma mark TEST CASES: - -#if DEBUG - - -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]; - CAssertNil(error); - CAssert(pcert != nil); - - CAssertEq(pcert.isRoot, selfSigned); - - Log(@"Subject Public Key = %@", pcert.subjectPublicKey); - CAssert(pcert.subjectPublicKey); - MYCertificateName *subject = pcert.subject; - Log(@"Common Name = %@", subject.commonName); - Log(@"Given Name = %@", subject.givenName); - Log(@"Surname = %@", subject.surname); - Log(@"Desc = %@", subject.nameDescription); - Log(@"Email = %@", subject.emailAddress); - CAssert(subject.commonName); - - // Now go through MYCertificate: - Log(@"Creating a MYCertificate from the data..."); - MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData]; - Log(@"MYCertificate = %@", cert); - CAssert(cert); - CAssertEqual(cert.info, pcert); - Log(@"Trust = %@", MYTrustResultDescribe([cert evaluateTrust])); - - return pcert; -} - -static NSData* readTestFile(NSString *filename) { -#if TARGET_OS_IPHONE - filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"]; -#else - filename = [[@"../../Tests/" stringByAppendingPathComponent: filename] - stringByAppendingPathExtension: @"cer"]; -#endif - Log(@"--- Testing certificate file %@", filename); - NSData *data = [NSData dataWithContentsOfFile: filename]; - CAssert(data, @"Couldn't read file %@", filename); - return data; -} - -static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) { - return testCertData(readTestFile(filename), selfSigned); -} - - -TestCase(ParsedCert) { - testCert(@"selfsigned", YES); - testCert(@"iphonedev", NO); - - // Now test a self-signed cert with a bad signature: - MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: readTestFile(@"selfsigned_altered")]; - Log(@"MYCertificate = %@", cert); - CAssertNil(cert); - - Log(@"Checking /tmp/generated.cer"); - testCertData([NSData dataWithContentsOfFile: @"/tmp/generated.cer"], YES);//TEMP -} - - -#import "MYCrypto_Private.h" - -TestCase(CreateCert) { - MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512]; - CAssert(privateKey); - MYIdentity *identity = nil; - @try{ - MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey]; - MYCertificateName *subject = pcert.subject; - subject.commonName = @"testcase"; - subject.givenName = @"Test"; - subject.surname = @"Case"; - subject.nameDescription = @"Just a test certificate created by MYCrypto"; - subject.emailAddress = @"testcase@example.com"; - - subject = pcert.subject; - CAssertEqual(subject.commonName, @"testcase"); - CAssertEqual(subject.givenName, @"Test"); - CAssertEqual(subject.surname, @"Case"); - CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto"); - CAssertEqual(subject.emailAddress, @"testcase@example.com"); - - Log(@"Signing..."); - NSError *error; - NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error]; - Log(@"Generated cert = \n%@", certData); - CAssert(certData); - CAssertNil(error); - CAssert(certData); -#if TARGET_OS_IPHONE - NSString *path = [@"/tmp/generated.cer" stringByStandardizingPath]; //TEMP - CAssert([certData writeToFile: path atomically: YES]); - Log(@"Wrote generated cert to %@",path); -#else - [certData writeToFile: @"../../Tests/generated.cer" atomically: YES]; -#endif - MYCertificateInfo *pcert2 = testCertData(certData, YES); - - Log(@"Verifying Info..."); - MYCertificateName *subject2 = pcert2.subject; - CAssertEqual(subject2,subject); - CAssertEqual(subject2.commonName, @"testcase"); - CAssertEqual(subject2.givenName, @"Test"); - CAssertEqual(subject2.surname, @"Case"); - CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto"); - CAssertEqual(subject2.emailAddress, @"testcase@example.com"); - - Log(@"Creating MYCertificate object..."); - MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData]; - Log(@"Loaded %@", cert); - CAssert(cert); - MYPublicKey *certKey = cert.publicKey; - Log(@"Its public key = %@", certKey); - CAssertEqual(certKey.keyData, privateKey.publicKey.keyData); - - Log(@"Creating Identity..."); - identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error]; - Log(@"Identity = %@", identity); - CAssert(identity); - CAssertNil(error); - CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]); - CAssertEqual(identity.privateKey, privateKey); - CAssert([identity isEqualToCertificate: cert]); - - [pcert release]; - - } @finally { - [privateKey removeFromKeychain]; - [identity removeFromKeychain]; - } -} - -#endif - - /* Copyright (c) 2009, Jens Alfke . All rights reserved. diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCertificateTest.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MYCertificateTest.m Wed Jul 01 14:19:13 2009 -0700 @@ -0,0 +1,196 @@ +// +// MYCertificateTest.m +// MYCrypto-iPhone +// +// Created by Jens Alfke on 6/15/09. +// Copyright 2009 Jens Alfke. All rights reserved. +// + +#import "MYCertificateInfo.h" +#import "MYCrypto.h" +#import "MYCrypto_Private.h" + + +#if DEBUG + + +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]; + CAssertNil(error); + CAssert(pcert != nil); + + CAssertEq(pcert.isRoot, selfSigned); + + MYCertificateName *subject = pcert.subject; + Log(@"Common Name = %@", subject.commonName); + Log(@"Given Name = %@", subject.givenName); + Log(@"Surname = %@", subject.surname); + Log(@"Desc = %@", subject.nameDescription); + Log(@"Email = %@", subject.emailAddress); + CAssert(subject.commonName); + + MYPublicKey *pcertKey = pcert.subjectPublicKey; + Log(@"Subject Public Key = %@", pcertKey); + CAssert(pcertKey); + + // Now go through MYCertificate: + Log(@"Creating a MYCertificate from the data..."); + MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData]; + Log(@"MYCertificate = %@", cert); + CAssert(cert); + CAssertEqual(cert.info, pcert); + Log(@"Trust = %@", MYTrustResultDescribe([cert evaluateTrust])); + + MYPublicKey *certKey = cert.publicKey; + Log(@"MYCertificate public key = ", certKey); + CAssertEqual(certKey.keyData, pcert.subjectPublicKey.keyData); + [cert release]; + /*TEMP + Log(@"Adding to keychain..."); + cert = [[MYKeychain defaultKeychain] importCertificate: certData]; + Log(@"Imported as %@", cert); + //CAssert(cert); + if (cert) { + Log(@"Removing from keychain..."); + CAssert([cert removeFromKeychain]); + } + */ + return pcert; +} + +static NSData* readTestFile(NSString *filename) { +#if TARGET_OS_IPHONE + filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"]; +#else + filename = [[@"../../Tests/" stringByAppendingPathComponent: filename] + stringByAppendingPathExtension: @"cer"]; +#endif + Log(@"--- Testing certificate file %@", filename); + NSData *data = [NSData dataWithContentsOfFile: filename]; + CAssert(data, @"Couldn't read file %@", filename); + return data; +} + +static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) { + return testCertData(readTestFile(filename), selfSigned); +} + + +TestCase(ParsedCert) { + testCert(@"selfsigned", YES); + testCert(@"iphonedev", NO); + + // Now test a self-signed cert with a bad signature: + MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: readTestFile(@"selfsigned_altered")]; + Log(@"MYCertificate = %@", cert); + CAssertNil(cert); +} + + +#import "MYCrypto_Private.h" + +TestCase(CreateCert) { + MYPrivateKey *privateKey = [[MYKeychain defaultKeychain] generateRSAKeyPairOfSize: 512]; + CAssert(privateKey); + Log(@"---- Generated key-pair with %@, %@", privateKey.publicKey, privateKey); + MYIdentity *identity = nil; + @try{ + MYCertificateRequest *pcert = [[MYCertificateRequest alloc] initWithPublicKey: privateKey.publicKey]; + MYCertificateName *subject = pcert.subject; + subject.commonName = @"testcase"; + subject.givenName = @"Test"; + subject.surname = @"Case"; + subject.nameDescription = @"Just a test certificate created by MYCrypto"; + subject.emailAddress = @"testcase@example.com"; + + subject = pcert.subject; + CAssertEqual(subject.commonName, @"testcase"); + CAssertEqual(subject.givenName, @"Test"); + CAssertEqual(subject.surname, @"Case"); + CAssertEqual(subject.nameDescription, @"Just a test certificate created by MYCrypto"); + CAssertEqual(subject.emailAddress, @"testcase@example.com"); + + CAssertEqual(pcert.subjectPublicKey.keyData, privateKey.publicKey.keyData); + + Log(@"---- Signing..."); + NSError *error; + NSData *certData = [pcert selfSignWithPrivateKey: privateKey error: &error]; + Log(@"Generated cert = \n%@", certData); + CAssert(certData); + CAssertNil(error); + CAssert(certData); + MYCertificateInfo *pcert2 = testCertData(certData, YES); + + Log(@"---- Verifying Info..."); + MYCertificateName *subject2 = pcert2.subject; + CAssertEqual(subject2,subject); + CAssertEqual(subject2.commonName, @"testcase"); + CAssertEqual(subject2.givenName, @"Test"); + CAssertEqual(subject2.surname, @"Case"); + CAssertEqual(subject2.nameDescription, @"Just a test certificate created by MYCrypto"); + CAssertEqual(subject2.emailAddress, @"testcase@example.com"); + + Log(@"---- Creating MYCertificate object..."); + MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData]; + Log(@"Loaded %@", cert); + CAssert(cert); + MYPublicKey *certKey = cert.publicKey; + Log(@"Its public key has name %@", certKey.name);//TEMP + Log(@"Its public key = %@", certKey); + CAssertEqual(certKey.keyData, privateKey.publicKey.keyData); + Log(@"X.509 trust = %@", MYTrustResultDescribe([cert evaluateTrust])); + Log(@"SSL trust = %@", MYTrustResultDescribe([cert evaluateTrustWithPolicy: [MYCertificate SSLPolicy]])); + + Log(@"---- Adding cert to keychain..."); + MYCertificate *addedCert = [[MYKeychain defaultKeychain] importCertificate: certData]; + Log(@"Imported as %@", addedCert); + //CAssert(addedCert); + if (addedCert) + CAssert([addedCert removeFromKeychain]); + + Log(@"---- Creating Identity..."); + identity = [pcert createSelfSignedIdentityWithPrivateKey: privateKey error: &error]; + Log(@"Identity = %@", identity); + CAssert(identity); + CAssertNil(error); + CAssertEqual(identity.keychain, [MYKeychain defaultKeychain]); + CAssertEqual(identity.privateKey.publicKeyDigest, privateKey.publicKeyDigest); + CAssert([identity isEqualToCertificate: cert]); + + [pcert release]; + + } @finally { + // [privateKey removeFromKeychain]; + // [identity removeFromKeychain]; + // Currently I'm leaving them in, so the EnumerateXXX tests can chew on them later. + } +} + +#endif + + +/* + Copyright (c) 2009, Jens Alfke . All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted + provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the + distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRI- + BUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCrypto-iPhone.xcodeproj/project.pbxproj --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj Wed Jun 10 09:02:18 2009 -0700 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj Wed Jul 01 14:19:13 2009 -0700 @@ -25,6 +25,7 @@ 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 */; }; + 278CA5320FE6A5D600296E91 /* MYCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 278CA5310FE6A5D600296E91 /* MYCertificateTest.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 */; }; @@ -54,6 +55,8 @@ 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 27059CF10F8F0F8E00A8422F /* MYIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYIdentity.h; sourceTree = ""; }; 27059CF20F8F0F9200A8422F /* MYIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYIdentity.m; sourceTree = ""; }; + 2726AF890FE19BE8006C55F7 /* MYCrypto_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYCrypto_Prefix.pch; sourceTree = ""; }; + 2726AF910FE19C5A006C55F7 /* MYUtilities_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MYUtilities_Prefix.pch; path = ../MYUtilities/MYUtilities_Prefix.pch; sourceTree = SOURCE_ROOT; }; 273392110F8283B8009414D9 /* MYKeychain-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYKeychain-iPhone.m"; sourceTree = ""; }; 274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYSymmetricKey-iPhone.m"; sourceTree = ""; }; 2748607D0F8D5DF200FE617B /* MYPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPrivateKey.h; sourceTree = ""; }; @@ -72,6 +75,7 @@ 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 = ""; }; + 278CA5310FE6A5D600296E91 /* MYCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificateTest.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 = ""; }; @@ -151,6 +155,7 @@ children = ( 27CD85DB0FDB1A7D006BCB47 /* MYCertificateInfo.h */, 27CD85DC0FDB1A82006BCB47 /* MYCertificateInfo.m */, + 278CA5310FE6A5D600296E91 /* MYCertificateTest.m */, 275D9FE50FD8795300D85A86 /* MYASN1Object.h */, 275D9FE60FD8795300D85A86 /* MYASN1Object.m */, 275D9FE70FD8795300D85A86 /* MYBERParser.h */, @@ -202,6 +207,8 @@ 27E8231C0F81D56E0019BE60 /* MYDigest.m */, 27E8231A0F81D56E0019BE60 /* MYCrypto_Private.h */, 276FB16D0F84152B00CB326E /* MYCryptoTest.m */, + 2726AF890FE19BE8006C55F7 /* MYCrypto_Prefix.pch */, + 2726AF910FE19C5A006C55F7 /* MYUtilities_Prefix.pch */, 27E8231E0F81D56E0019BE60 /* MYCrypto.xcconfig */, 27E8231F0F81D56E0019BE60 /* MYCrypto_Debug.xcconfig */, ); @@ -336,6 +343,7 @@ 275D9FF10FD8795300D85A86 /* MYDEREncoder.m in Sources */, 275D9FF20FD8795300D85A86 /* MYOID.m in Sources */, 27CD85DD0FDB1A82006BCB47 /* MYCertificateInfo.m in Sources */, + 278CA5320FE6A5D600296E91 /* MYCertificateTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -351,7 +359,7 @@ GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = ../MYUtilities/MYUtilities_Prefix.pch; + GCC_PREFIX_HEADER = MYCrypto_Prefix.pch; INFOPLIST_FILE = "iPhone/MYCrypto_iPhone-Info.plist"; PRODUCT_NAME = "MYCrypto-iPhone"; }; @@ -364,7 +372,7 @@ ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = MYCrypto_iPhone_Prefix.pch; + GCC_PREFIX_HEADER = MYCrypto_Prefix.pch; INFOPLIST_FILE = "MYCrypto_iPhone-Info.plist"; PRODUCT_NAME = "MYCrypto-iPhone"; }; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCrypto.xcodeproj/project.pbxproj --- a/MYCrypto.xcodeproj/project.pbxproj Wed Jun 10 09:02:18 2009 -0700 +++ b/MYCrypto.xcodeproj/project.pbxproj Wed Jul 01 14:19:13 2009 -0700 @@ -43,6 +43,8 @@ 270A7A740FD58FF200770C4D /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 270A7A720FD58FF200770C4D /* MYBERParser.m */; }; 270A7A750FD58FF200770C4D /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 270A7A720FD58FF200770C4D /* MYBERParser.m */; }; 270B879F0F8C565000C56781 /* MYPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 270B879E0F8C565000C56781 /* MYPrivateKey.m */; }; + 27205C440FF2D88200C5E25B /* MYCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27205C430FF2D88200C5E25B /* MYCertificateTest.m */; }; + 27205C450FF2D88200C5E25B /* MYCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 27205C430FF2D88200C5E25B /* MYCertificateTest.m */; }; 27410FF00F99200A00AD413F /* MYSymmetricKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 27410FEF0F99200A00AD413F /* MYSymmetricKey-iPhone.m */; }; 274863A20F8EF39400FE617B /* MYIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 274863A10F8EF39400FE617B /* MYIdentity.m */; }; 275DA1270FD980D400D85A86 /* MYCertificateInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 275DA1250FD980D400D85A86 /* MYCertificateInfo.h */; }; @@ -104,6 +106,7 @@ 270A7A720FD58FF200770C4D /* MYBERParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYBERParser.m; sourceTree = ""; }; 270B879D0F8C565000C56781 /* MYPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPrivateKey.h; sourceTree = ""; }; 270B879E0F8C565000C56781 /* MYPrivateKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPrivateKey.m; sourceTree = ""; }; + 27205C430FF2D88200C5E25B /* MYCertificateTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCertificateTest.m; sourceTree = ""; }; 27410FEF0F99200A00AD413F /* MYSymmetricKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYSymmetricKey-iPhone.m"; sourceTree = ""; }; 2748604D0F8D5C4C00FE617B /* MYCrypto_Release.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MYCrypto_Release.xcconfig; sourceTree = ""; }; 274863A00F8EF39400FE617B /* MYIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYIdentity.h; sourceTree = ""; }; @@ -275,6 +278,7 @@ children = ( 275DA1250FD980D400D85A86 /* MYCertificateInfo.h */, 275DA1260FD980D400D85A86 /* MYCertificateInfo.m */, + 27205C430FF2D88200C5E25B /* MYCertificateTest.m */, 27B852F30FCF4EB6005631F9 /* MYASN1Object.h */, 27B852F40FCF4EB7005631F9 /* MYASN1Object.m */, 270A7A710FD58FF200770C4D /* MYBERParser.h */, @@ -440,6 +444,7 @@ 27B855280FD077A7005631F9 /* MYDEREncoder.m in Sources */, 270A7A740FD58FF200770C4D /* MYBERParser.m in Sources */, 275DA1280FD980D400D85A86 /* MYCertificateInfo.m in Sources */, + 27205C440FF2D88200C5E25B /* MYCertificateTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -473,6 +478,7 @@ 27B855290FD077A7005631F9 /* MYDEREncoder.m in Sources */, 270A7A750FD58FF200770C4D /* MYBERParser.m in Sources */, 275DA1290FD980D400D85A86 /* MYCertificateInfo.m in Sources */, + 27205C450FF2D88200C5E25B /* MYCertificateTest.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCryptoTest.m --- a/MYCryptoTest.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYCryptoTest.m Wed Jul 01 14:19:13 2009 -0700 @@ -43,6 +43,16 @@ } +#if MYCRYPTO_USE_IPHONE_API +TestCase(RemoveAll) { + RequireTestCase(MYKeychain); + MYKeychain *kc = [MYKeychain defaultKeychain]; + CAssert([kc removeAllCertificates]); + CAssert([kc removeAllKeys]); +} +#endif + + TestCase(Enumerate) { RequireTestCase(EnumeratePublicKeys); RequireTestCase(EnumeratePrivateKeys); @@ -95,8 +105,26 @@ Log(@"Enumerator = %@", e); CAssert(e); for (MYCertificate *cert in e) { - Log(@"Found %@ -- name=%@, email=%@", cert, cert.commonName, cert.emailAddresses); + Log(@"Found %@ -- key=%@, name=%@, email=%@", cert, + cert.publicKey, cert.commonName, cert.emailAddresses); CAssert(cert.publicKey); + +#if MYCRYPTO_USE_IPHONE_API + // Verify that cert has public-key-hash attribute: + NSData *digestData = [MYKeychainItem _getAttribute: kSecAttrPublicKeyHash + ofItem: cert.certificateRef]; + CAssert(digestData, @"SecCertificateRef missing kSecAttrPublicKeyHash"); + MYSHA1Digest *digest = [MYSHA1Digest digestFromDigestData: digestData]; + CAssertEqual(digest, cert.publicKey.publicKeyDigest); + Log(@"kSecAttrPublicKeyHash matches: %@", digest); +#else + MYSHA1Digest *digest = cert.publicKey.publicKeyDigest; +#endif + // Verify that certificateWithDigest will find it: + MYCertificate *cert2 = [[MYKeychain allKeychains] certificateWithDigest: digest]; + Log(@"certificateWithDigest(%@) returned %@", digest,cert2); + CAssert(cert2); + CAssertEqual(cert2.certificateData, cert.certificateData); } } @@ -108,12 +136,15 @@ for (MYIdentity *ident in e) { Log(@"Found %@\n\tcommonName=%@\n\temails=(%@)\n\tkey=%@", ident, ident.commonName, -#if TARGET_OS_IPHONE - nil, -#else [ident.emailAddresses componentsJoinedByString: @", "], -#endif ident.privateKey); + + // Verify that identityWithDigest will find it: + MYSHA1Digest *digest = ident.publicKey.publicKeyDigest; + MYIdentity *ident2 = [[MYKeychain allKeychains] identityWithDigest:digest]; + Log(@"identityWithDigest(%@) returned %@", digest,ident2); + CAssert(ident2); + CAssertEqual(ident2.certificateData, ident.certificateData); } } @@ -177,7 +208,6 @@ #endif #if !TARGET_OS_IPHONE -#if 1 // TEMP-ORARILY OUT OF ORDER // Try exporting and importing a wrapped key: Log(@"Testing export/import..."); NSData *exported = [key exportWrappedKeyWithPassphrasePrompt: @"Export symmetric key with passphrase:"]; @@ -197,7 +227,6 @@ decrypted = [key2 decryptData: encrypted]; CAssertEqual(decrypted, cleartext); } -#endif 0 #endif }@finally{ [key removeFromKeychain]; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCrypto_Prefix.pch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MYCrypto_Prefix.pch Wed Jul 01 14:19:13 2009 -0700 @@ -0,0 +1,11 @@ +// +// MYCrypto_Prefix.h +// MYCrypto-iPhone +// +// Created by Jens Alfke on 6/11/09. +// Copyright 2009 Jens Alfke. All rights reserved. +// + +#define USE_SECURITY_API 1 /* tells MYErrorUtils it can call Security to look up error names */ + +#import "MYUtilities_Prefix.pch" diff -r 38c3c3923e1f -r d9c2a06d4e4e MYCrypto_Private.h --- a/MYCrypto_Private.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYCrypto_Private.h Wed Jul 01 14:19:13 2009 -0700 @@ -13,6 +13,8 @@ #import "MYPublicKey.h" #import "MYPrivateKey.h" #import "MYCertificate.h" +#import "MYCertificateInfo.h" + #import "Test.h" #import @@ -33,6 +35,9 @@ @property (readonly) CSSM_CSP_HANDLE CSPHandle; @property (readonly) NSString* path; #endif +#if MYCRYPTO_USE_IPHONE_API ++ (CFTypeRef) _addItemWithInfo: (NSMutableDictionary*)info; +#endif @end @@ -56,9 +61,7 @@ @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 -+ (SecKeyRef) _addKeyWithInfo: (NSMutableDictionary*)info; -#else +#if !MYCRYPTO_USE_IPHONE_API @property (readonly) const CSSM_KEY* cssmKey; @property (readonly) const CSSM_CSP_HANDLE cssmCSPHandle; - (CSSM_CC_HANDLE) _createSignatureContext: (CSSM_ALGORITHMS)algorithm; @@ -79,6 +82,7 @@ @interface MYPublicKey (Private) +@property (retain) MYCertificate *certificate; - (BOOL) setValue: (NSString*)valueStr ofAttribute: (SecKeychainAttrType)attr; #if !TARGET_OS_IPHONE - (CSSM_WRAP_KEY*) _unwrappedCSSMKey; @@ -117,6 +121,15 @@ #endif +@interface MYCertificateInfo (Private) +- (NSData*) subjectPublicKeyData; +- (MYPublicKey*) subjectPublicKey; +- (NSData*) signedData; +- (MYOID*) signatureAlgorithmID; +- (NSData*) signature; +@end + + #undef check BOOL check(OSStatus err, NSString *what); diff -r 38c3c3923e1f -r d9c2a06d4e4e MYDigest.h --- a/MYDigest.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYDigest.h Wed Jul 01 14:19:13 2009 -0700 @@ -63,6 +63,9 @@ /** The length of digests created by this subclass. (Abstract method.) */ + (size_t) length; +/** Byte-by-byte lexical comparison of digest data. */ +- (NSComparisonResult) compare: (MYDigest*)other; + /** Primitive digest generation method. (Abstract.) */ + (void) computeDigest: (void*)dstDigest ofBytes: (const void*)bytes length: (size_t)length; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYIdentity.m --- a/MYIdentity.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYIdentity.m Wed Jul 01 14:19:13 2009 -0700 @@ -8,6 +8,7 @@ #import "MYIdentity.h" #import "MYCrypto_Private.h" +#import "MYDigest.h" @implementation MYIdentity @@ -45,7 +46,28 @@ return nil; } #else - Assert(NO,@"-[MYIdentity initWithCertificateRef] isn't implemented for iPhone yet!");//FIX + MYSHA1Digest *keyDigest = self.publicKey.publicKeyDigest; + if (!keyDigest) { + Warn(@"MYIdentity: Couldn't get key digest of cert %@",certificateRef); + [self release]; + return nil; + } + _identityRef = [self.keychain identityWithDigest: keyDigest].identityRef; + if (!_identityRef) { + Warn(@"MYIdentity: Couldn't look up identity for cert %@ with %@",certificateRef, keyDigest); + [self release]; + return nil; + } + + // Debugging: Make sure the cert is correct + SecCertificateRef identitysCert = NULL; + SecIdentityCopyCertificate(_identityRef, &identitysCert); + CFDataRef identitysData = SecCertificateCopyData(identitysCert); + AssertEqual(self.certificateData, (NSData*)identitysData); + CFRelease(identitysData); + CFRelease(identitysCert); + + CFRetain(_identityRef); #endif } return self; @@ -77,6 +99,11 @@ } +- (BOOL) removeFromKeychain { + return [self.privateKey removeFromKeychain] && [super removeFromKeychain]; +} + + #if !TARGET_OS_IPHONE + (MYIdentity*) preferredIdentityForName: (NSString*)name diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKey-iPhone.m --- a/MYKey-iPhone.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKey-iPhone.m Wed Jul 01 14:19:13 2009 -0700 @@ -19,45 +19,6 @@ @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 [self initWithKeychainItemRef: (SecKeychainItemRef)key]; } @@ -70,8 +31,8 @@ {(id)kSecAttrKeyType, (id)self.keyType}, {(id)kSecValueData, data}, {(id)kSecAttrIsPermanent, (keychain ?$true :$false)}, - {(id)kSecReturnPersistentRef, $true} ); - SecKeyRef key = [[self class] _addKeyWithInfo: info]; + {(id)kSecReturnPersistentRef, (keychain ?$true :$false)} ); + SecKeyRef key = (SecKeyRef)[MYKeychain _addItemWithInfo: info]; if (!key) { [self release]; return nil; @@ -80,6 +41,9 @@ if (self) { if (!keychain) _keyData = [data copy]; + + //TEMP For debugging: + AssertEqual(self.keyData, data); } return self; } @@ -95,6 +59,19 @@ } +/*- (NSData*) persistentRef { + NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef}, + //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)}, + {(id)kSecReturnPersistentRef, $true} ); + CFDataRef data; + if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching")) + return nil; + if (!data) + Warn(@"MYKey persistentRef couldn't get ref"); + return [NSMakeCollectable(data) autorelease]; +}*/ + + - (SecExternalItemType) keyClass { AssertAbstractMethod(); } @@ -108,11 +85,13 @@ return _keyData; NSDictionary *info = $dict( {(id)kSecValueRef, (id)self.keyRef}, + //{(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)}, {(id)kSecReturnData, $true} ); CFDataRef data; - if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching")) + if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&data), @"SecItemCopyMatching")) { + Log(@"SecItemCopyMatching failed; input = %@", info); return nil; - else { + } else { Assert(data!=NULL); _keyData = NSMakeCollectable(data); return _keyData; @@ -134,11 +113,11 @@ - (id) _attribute: (CFTypeRef)attribute { NSDictionary *info = $dict({(id)kSecValueRef, (id)self.keyRef}, + {(id)kSecAttrIsPermanent, (self.isPersistent ?$true :$false)}, {(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); diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKey.h --- a/MYKey.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKey.h Wed Jul 01 14:19:13 2009 -0700 @@ -39,6 +39,9 @@ /** The key's raw data. */ @property (readonly) NSData *keyData; +/** The key's size/length, in bits. */ +@property (readonly) unsigned keySizeInBits; + /** The user-visible name (kSecKeyPrintName) associated with this key in the Keychain. The user can edit this, so don't expect it to be immutable. */ @property (copy) NSString *name; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKey.m --- a/MYKey.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKey.m Wed Jul 01 14:19:13 2009 -0700 @@ -33,6 +33,12 @@ } self = [self initWithKeyRef: key]; CFRelease(key); + if (self) { +#if MYCRYPTO_USE_IPHONE_API + if (!keychain) + self.isPersistent = NO; +#endif + } return self; } @@ -104,6 +110,12 @@ return nil; } +- (unsigned) keySizeInBits { + const CSSM_KEY *key = self.cssmKey; + Assert(key); + return key->KeyHeader.LogicalKeySizeInBits; +} + - (NSString*) name { return [self stringValueOfAttribute: kSecKeyPrintName]; } diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKeychain-iPhone.m --- a/MYKeychain-iPhone.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKeychain-iPhone.m Wed Jul 01 14:19:13 2009 -0700 @@ -14,6 +14,20 @@ #if MYCRYPTO_USE_IPHONE_API +// from cssmtype.h: +enum { + CSSM_CERT_UNKNOWN = 0x00, + CSSM_CERT_X_509v1 = 0x01, + CSSM_CERT_X_509v2 = 0x02, + CSSM_CERT_X_509v3 = 0x03, + + CSSM_CERT_ENCODING_UNKNOWN = 0x00, + CSSM_CERT_ENCODING_CUSTOM = 0x01, + CSSM_CERT_ENCODING_BER = 0x02, + CSSM_CERT_ENCODING_DER = 0x03, +}; + + @interface MYKeyEnumerator : NSEnumerator { CFArrayRef _results; @@ -98,7 +112,7 @@ - (MYIdentity*) identityWithDigest: (MYSHA1Digest*)pubKeyDigest { return [MYKeyEnumerator firstItemWithQuery: $mdict({(id)kSecClass, (id)kSecClassIdentity}, - {(id)kSecAttrPublicKeyHash, pubKeyDigest.asData})]; + {(id)kSecAttrApplicationLabel/*kSecAttrPublicKeyHash*/, pubKeyDigest.asData})]; } - (NSEnumerator*) enumerateIdentities { @@ -122,6 +136,50 @@ #pragma mark IMPORT: ++ (CFTypeRef) _addItemWithInfo: (NSMutableDictionary*)info { + // Generally SecItemAdd will fail (return paramErr) if asked to return a regular ref. + // As a workaround ask for a persistent ref instead, then convert that to regular ref. + if (![[info objectForKey: (id)kSecReturnRef] boolValue]) + [info setObject: $true forKey: (id)kSecReturnPersistentRef]; + + CFDataRef itemPersistentRef; + CFTypeRef item; + OSStatus err = SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&itemPersistentRef); + if (err==errSecDuplicateItem) { + Log(@"_addItemWithInfo: Keychain claims it's a dup, so look for existing item"); + // 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 *)&item), + @"SecItemCopyMatching")) { + if (!item) + Warn(@"_addItemWithInfo: Couldn't find supposedly-duplicate item, info=%@",info); + Log(@"_addItemWithInfo: SecItemAdd found item; ref=%@", item);//TEMP + return item; + } + } else if (check(err, @"SecItemAdd")) { + // It was added + if ([[info objectForKey: (id)kSecReturnPersistentRef] boolValue]) { + // now get its item ref: + Log(@"SecItemAdd added item; persistenRef=%@", itemPersistentRef);//TEMP + info = $mdict({(id)kSecValuePersistentRef, (id)itemPersistentRef}, + {(id)kSecReturnRef, $true}); + err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef *)&item); + CFRelease(itemPersistentRef); + if (check(err,@"SecItemCopyMatching")) { + Assert(item!=nil); + return item; + } + } else { + Log(@"SecItemAdd added item; ref=%@", itemPersistentRef);//TEMP + return (CFTypeRef)itemPersistentRef; + } + } + Log(@"SecItemAdd failed: info = %@", info); // for help in debugging, dump the input dict + return NULL; +} + + - (MYPublicKey*) importPublicKey: (NSData*)keyData { return [[[MYPublicKey alloc] _initWithKeyData: keyData forKeychain: self] @@ -131,13 +189,25 @@ - (MYCertificate*) importCertificate: (NSData*)data { Assert(data); - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassCertificate}, - {(id)kSecValueData, data}, - {(id)kSecReturnRef, $true} ); - SecCertificateRef cert; - if (!check(SecItemAdd((CFDictionaryRef)info, (CFTypeRef*)&cert), @"SecItemAdd")) + +#if 1 + SecCertificateRef cert0 = SecCertificateCreateWithData(NULL, (CFDataRef)data); + if (!cert0) return nil; - return [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease]; + NSMutableDictionary *info = $mdict( {(id)kSecClass, (id)kSecClassCertificate}, + {(id)kSecValueRef, (id)cert0}); +#else + NSMutableDictionary *info = $mdict( {(id)kSecClass, (id)kSecClassCertificate}, + {(id)kSecAttrCertificateType, $object(CSSM_CERT_X_509v3)}, + {(id)kSecAttrCertificateEncoding, $object(CSSM_CERT_ENCODING_BER)}, + {(id)kSecValueData, data} ); +#endif + SecCertificateRef cert = (SecCertificateRef) [[self class] _addItemWithInfo: info]; + if (!cert) + return nil; + MYCertificate *myCert = [[[MYCertificate alloc] initWithCertificateRef: cert] autorelease]; + AssertEqual(data, myCert.certificateData); //TEMP for debugging + return myCert; } @@ -157,6 +227,21 @@ } +#pragma mark - +#pragma mark REMOVING: + + +- (BOOL) removeAllCertificates { + NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassCertificate}); + return check(SecItemDelete((CFDictionaryRef)query), @"SecItemDelete"); +} + +- (BOOL) removeAllKeys { + NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassKey}); + return check(SecItemDelete((CFDictionaryRef)query), @"SecItemDelete"); +} + + @end @@ -190,7 +275,7 @@ [self release]; return nil; } - Log(@"Enumerator results = %@", _results);//TEMP + //Log(@"Enumerator results = %@", _results); if (_results && CFEqual(limit,kSecMatchLimitOne)) { // If you ask for only one, it gives you the object back instead of an array: @@ -225,7 +310,7 @@ // when you try to use them for anything. As a workaround, detect these early on before // even creating a MYPublicKey: NSDictionary *info = $dict({(id)kSecValueRef, (id)itemRef}, - {(id)kSecReturnAttributes, $true}); + {(id)kSecReturnAttributes, $true}); CFDictionaryRef attrs = NULL; OSStatus err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs); if (attrs) CFRelease(attrs); diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKeychain.h --- a/MYKeychain.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKeychain.h Wed Jul 01 14:19:13 2009 -0700 @@ -113,6 +113,8 @@ /** Enumerates all public keys in the keychain that have the given alias string. */ - (NSEnumerator*) publicKeysWithAlias: (NSString*)alias; +- (NSEnumerator*) enumerateIdentitiesWithKeyUsage: (CSSM_KEYUSE)keyUsage; + /** Imports a key-pair into the keychain, given the external representations of both the public and private keys. Since the private key data is wrapped (encrypted), the Security agent will prompt the user to enter @@ -138,6 +140,16 @@ encoding: (CSSM_CERT_ENCODING) encoding; //@} +#else +/** @name iPhone-Only + * Functionality only available on iPhone. + */ +//@{ + +- (BOOL) removeAllCertificates; +- (BOOL) removeAllKeys; + +//@} #endif diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKeychain.m --- a/MYKeychain.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKeychain.m Wed Jul 01 14:19:13 2009 -0700 @@ -36,7 +36,7 @@ SecIdentitySearchRef _searchRef; } -- (id) initWithKeychain: (MYKeychain*)keychain; +- (id) initWithKeychain: (MYKeychain*)keychain keyUsage: (CSSM_KEYUSE)keyUsage; @end @@ -269,7 +269,11 @@ } - (NSEnumerator*) enumerateIdentities { - return [[[MYIdentityEnumerator alloc] initWithKeychain: self] autorelease]; + return [self enumerateIdentitiesWithKeyUsage: 0]; +} + +- (NSEnumerator*) enumerateIdentitiesWithKeyUsage: (CSSM_KEYUSE)keyUsage { + return [[[MYIdentityEnumerator alloc] initWithKeychain: self keyUsage: keyUsage] autorelease]; } - (NSEnumerator*) enumerateSymmetricKeys { @@ -448,10 +452,10 @@ @implementation MYIdentityEnumerator -- (id) initWithKeychain: (MYKeychain*)keychain { +- (id) initWithKeychain: (MYKeychain*)keychain keyUsage: (CSSM_KEYUSE)keyUsage { self = [super init]; if (self) { - if (!check(SecIdentitySearchCreate(keychain.keychainRef, 0, &_searchRef), + if (!check(SecIdentitySearchCreate(keychain.keychainRef, keyUsage, &_searchRef), @"SecIdentitySearchCreate")) { [self release]; return nil; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKeychainItem.h --- a/MYKeychainItem.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKeychainItem.h Wed Jul 01 14:19:13 2009 -0700 @@ -29,6 +29,9 @@ { @private MYKeychainItemRef _itemRef; +#if MYCRYPTO_USE_IPHONE_API + BOOL _isPersistent; +#endif } /** The Keychain item reference that this object represents. */ @@ -40,4 +43,8 @@ /** Removes the item from its keychain, if any. */ - (BOOL) removeFromKeychain; +#if MYCRYPTO_USE_IPHONE_API +@property BOOL isPersistent; +#endif + @end diff -r 38c3c3923e1f -r d9c2a06d4e4e MYKeychainItem.m --- a/MYKeychainItem.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYKeychainItem.m Wed Jul 01 14:19:13 2009 -0700 @@ -8,6 +8,7 @@ #import "MYKeychainItem.h" #import "MYCrypto_Private.h" +#import "MYBERParser.h" #import "MYErrorUtils.h" @@ -25,6 +26,9 @@ _itemRef = itemRef; CFRetain(_itemRef); LogTo(INIT,@"%@, _itemRef=%@", [self class], itemRef); +#if MYCRYPTO_USE_IPHONE_API + _isPersistent = YES; +#endif } return self; } @@ -32,6 +36,10 @@ @synthesize keychainItemRef=_itemRef; +#if MYCRYPTO_USE_IPHONE_API +@synthesize isPersistent = _isPersistent; +#endif + - (void) dealloc { if (_itemRef) CFRelease(_itemRef); @@ -71,7 +79,7 @@ - (MYKeychain*) keychain { #if MYCRYPTO_USE_IPHONE_API - return [MYKeychain defaultKeychain]; + return _isPersistent ? [MYKeychain defaultKeychain] : nil; #else MYKeychain *keychain = nil; SecKeychainRef keychainRef = NULL; @@ -89,6 +97,8 @@ OSStatus err; #if MYCRYPTO_USE_IPHONE_API err = SecItemDelete((CFDictionaryRef) $dict( {(id)kSecValueRef, (id)_itemRef} )); + if (!err) + _isPersistent = NO; #else err = SecKeychainItemDelete((SecKeychainItemRef)_itemRef); if (err==errSecInvalidItemRef) @@ -98,6 +108,43 @@ } +/* (Not useful yet, as only password items have dates.) +- (NSDate*) dateValueOfAttribute: (SecKeychainAttrType)attr { + NSString *dateStr = [self stringValueOfAttribute: attr]; + if (dateStr.length == 0) + return nil; + NSDate *date = [MYBERGeneralizedTimeFormatter() dateFromString: dateStr]; + if (!date) + Warn(@"MYKeychainItem: unable to parse date '%@'", dateStr); + return date; +} + +- (void) setDateValue: (NSDate*)date ofAttribute: (SecKeychainAttrType)attr { + NSString *timeStr = nil; + if (date) + timeStr = [MYBERGeneralizedTimeFormatter() stringFromDate: date]; + [self setValue: timeStr ofAttribute: attr]; +} + + +- (NSDate*) creationDate { + return [self dateValueOfAttribute: kSecCreationDateItemAttr]; +} + +- (void) setCreationDate: (NSDate*)date { + [self setDateValue: date ofAttribute: kSecCreationDateItemAttr]; +} + +- (NSDate*) modificationDate { + return [self dateValueOfAttribute: kSecModDateItemAttr]; +} + +- (void) setModificationDate: (NSDate*)date { + [self setDateValue: date ofAttribute: kSecModDateItemAttr]; +} +*/ + + #pragma mark - #pragma mark DATA / METADATA ACCESSORS: @@ -165,6 +212,10 @@ } - (NSString*) stringValueOfAttribute: (SecKeychainAttrType)attr { +#if MYCRYPTO_USE_IPHONE_API + if (!self.isPersistent) + return nil; +#endif return [[self class] _getStringAttribute: attr ofItem: _itemRef]; } diff -r 38c3c3923e1f -r d9c2a06d4e4e MYOID.h --- a/MYOID.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYOID.h Wed Jul 01 14:19:13 2009 -0700 @@ -16,6 +16,10 @@ NSData *_data; } +#if TARGET_OS_MAC ++ (MYOID*) OIDFromCSSM: (CSSM_OID)cssmOid; +#endif + - (id) initWithComponents: (const UInt32*)components count: (unsigned)componentCount; - (id) initWithBEREncoding: (NSData*)encoding; - (NSData*) DEREncoding; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYOID.m --- a/MYOID.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYOID.m Wed Jul 01 14:19:13 2009 -0700 @@ -59,6 +59,16 @@ return [[[self alloc] initWithBEREncoding: encoding] autorelease]; } +#if TARGET_OS_MAC ++ (MYOID*) OIDFromCSSM: (CSSM_OID)cssmOid +{ + NSData *ber = [[NSData alloc] initWithBytesNoCopy: cssmOid.Data length: cssmOid.Length freeWhenDone: NO]; + MYOID *oid = [[[self alloc] initWithBEREncoding: ber] autorelease]; + [ber release]; + return oid; +} +#endif + - (id) copyWithZone: (NSZone*)zone { return [self retain]; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYPublicKey.h --- a/MYPublicKey.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYPublicKey.h Wed Jul 01 14:19:13 2009 -0700 @@ -7,7 +7,7 @@ // #import "MYKey.h" -@class MYSHA1Digest, MYSymmetricKey; +@class MYSHA1Digest, MYSymmetricKey, MYCertificate; #if !TARGET_OS_IPHONE #import @@ -20,7 +20,8 @@ @interface MYPublicKey : MYKey { @private - MYSHA1Digest *_digest; + MYSHA1Digest *_digest; // The key's SHA-1 digest (null if not determined yet) + MYCertificate *_certificate; // The cert this key came from (if any) } /** The public key's SHA-1 digest. This is a convenient short (20-byte) identifier for the key. */ diff -r 38c3c3923e1f -r d9c2a06d4e4e MYPublicKey.m --- a/MYPublicKey.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYPublicKey.m Wed Jul 01 14:19:13 2009 -0700 @@ -16,6 +16,11 @@ #import +@interface MYPublicKey () +@property (retain) MYCertificate *certificate; +@end + + #pragma mark - @implementation MYPublicKey @@ -35,6 +40,8 @@ [super dealloc]; } +@synthesize certificate=_certificate; + - (SecExternalItemType) keyClass { #if MYCRYPTO_USE_IPHONE_API return kSecAttrKeyClassPublic; @@ -63,6 +70,16 @@ return _digest; } +#if MYCRYPTO_USE_IPHONE_API +- (NSData*) keyData { + if (_certificate) { + return _certificate.info.subjectPublicKeyData; + } else { + return [super keyData]; + } +} +#endif + #if !MYCRYPTO_USE_IPHONE_API - (SecExternalFormat) _externalFormat { return kSecFormatBSAFE; diff -r 38c3c3923e1f -r d9c2a06d4e4e MYSymmetricKey-iPhone.m --- a/MYSymmetricKey-iPhone.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYSymmetricKey-iPhone.m Wed Jul 01 14:19:13 2009 -0700 @@ -13,6 +13,9 @@ #if MYCRYPTO_USE_IPHONE_API +#define kAlgorithmNone 0xFFFFFFFF + + typedef uint32_t CSSM_ALGORITHMS; enum { // Taken from cssmtype.h in OS X 10.5 SDK: @@ -36,20 +39,27 @@ @implementation MYSymmetricKey +- (id) initWithKeyRef: (SecKeyRef)key { + self = [super initWithKeyRef: key]; + if (self) { + _algorithm = kAlgorithmNone; + } + return self; +} + - (id) _initWithKeyData: (NSData*)keyData algorithm: (CCAlgorithm)algorithm inKeychain: (MYKeychain*)keychain { Assert(algorithm <= kCCAlgorithmRC4); Assert(keyData); - NSNumber *keySizeInBits = [NSNumber numberWithUnsignedInt: keyData.length * 8]; - NSNumber *keyType = [NSNumber numberWithUnsignedInt: kCSSMAlgorithms[algorithm]]; + unsigned keySizeInBits = keyData.length * 8; NSMutableDictionary *keyAttrs = $mdict( {(id)kSecClass, (id)kSecClassKey}, {(id)kSecAttrKeyClass, (id)kSecAttrKeyClassSymmetric}, - {(id)kSecAttrKeyType, keyType}, + {(id)kSecAttrKeyType, $object(kCSSMAlgorithms[algorithm])}, {(id)kSecValueData, keyData}, - {(id)kSecAttrKeySizeInBits, keySizeInBits}, - {(id)kSecAttrEffectiveKeySize, keySizeInBits}, + {(id)kSecAttrKeySizeInBits, $object(keySizeInBits)}, + {(id)kSecAttrEffectiveKeySize, $object(keySizeInBits)}, {(id)kSecAttrIsPermanent, keychain ?$true :$false}, {(id)kSecAttrCanEncrypt, $true}, {(id)kSecAttrCanDecrypt, $true}, @@ -57,14 +67,17 @@ {(id)kSecAttrCanUnwrap, $false}, {(id)kSecAttrCanDerive, $false}, {(id)kSecAttrCanSign, $false}, - {(id)kSecAttrCanVerify, $false}, - {(id)kSecReturnPersistentRef, $true}); - SecKeyRef keyRef = [[self class] _addKeyWithInfo: keyAttrs]; + {(id)kSecAttrCanVerify, $false}); + SecKeyRef keyRef = (SecKeyRef) [MYKeychain _addItemWithInfo: keyAttrs]; if (!keyRef) { [self release]; return nil; } self = [self initWithKeyRef: keyRef]; + if (self) { + _algorithm = algorithm; + _keySizeInBits = keySizeInBits; + } CFRelease(keyRef); return self; } @@ -98,25 +111,33 @@ } - (CCAlgorithm) algorithm { - CSSM_ALGORITHMS cssmAlg; - id keyType = [self _attribute: kSecAttrKeyType]; - Assert(keyType!=nil, @"Key has no kSecAttrKeyType"); - cssmAlg = [keyType unsignedIntValue]; - switch(cssmAlg) { - case CSSM_ALGID_AES: - return kCCAlgorithmAES128; - case CSSM_ALGID_DES: - return kCCAlgorithmDES; - case CSSM_ALGID_3DES_3KEY: - return kCCAlgorithm3DES; - case CSSM_ALGID_CAST: - return kCCAlgorithmCAST; - case CSSM_ALGID_RC4: - return kCCAlgorithmRC4; - default: - Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg); - return (CCAlgorithm)-1; + if (_algorithm == kAlgorithmNone) { + CSSM_ALGORITHMS cssmAlg; + id keyType = [self _attribute: kSecAttrKeyType]; + Assert(keyType!=nil, @"Key has no kSecAttrKeyType"); + cssmAlg = [keyType unsignedIntValue]; + switch(cssmAlg) { + case CSSM_ALGID_AES: + _algorithm = kCCAlgorithmAES128; + break; + case CSSM_ALGID_DES: + _algorithm = kCCAlgorithmDES; + break; + case CSSM_ALGID_3DES_3KEY: + _algorithm = kCCAlgorithm3DES; + break; + case CSSM_ALGID_CAST: + _algorithm = kCCAlgorithmCAST; + break; + case CSSM_ALGID_RC4: + _algorithm = kCCAlgorithmRC4; + break; + default: + Warn(@"CSSM_ALGORITHMS #%u doesn't map to any CCAlgorithm", cssmAlg); + break; + } } + return _algorithm; } - (const char*) algorithmName { @@ -128,9 +149,12 @@ } - (unsigned) keySizeInBits { - id keySize = [self _attribute: kSecAttrKeySizeInBits]; - Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits"); - return [keySize unsignedIntValue]; + if (_keySizeInBits == 0) { + id keySize = [self _attribute: kSecAttrKeySizeInBits]; + Assert(keySize!=nil, @"Key has no kSecAttrKeySizeInBits"); + _keySizeInBits = [keySize unsignedIntValue]; + } + return _keySizeInBits; } diff -r 38c3c3923e1f -r d9c2a06d4e4e MYSymmetricKey.h --- a/MYSymmetricKey.h Wed Jun 10 09:02:18 2009 -0700 +++ b/MYSymmetricKey.h Wed Jul 01 14:19:13 2009 -0700 @@ -21,7 +21,10 @@ @interface MYSymmetricKey : MYKey { @private -#if !MYCRYPTO_USE_IPHONE_API +#if MYCRYPTO_USE_IPHONE_API + CCAlgorithm _algorithm; + unsigned _keySizeInBits; +#else CSSM_KEY *_ownedCSSMKey; #endif } @@ -39,9 +42,6 @@ /** The key's algorithm. */ @property (readonly) CCAlgorithm algorithm; -/** The key's size/length, in bits. */ -@property (readonly) unsigned keySizeInBits; - #if !TARGET_OS_IPHONE diff -r 38c3c3923e1f -r d9c2a06d4e4e MYSymmetricKey.m --- a/MYSymmetricKey.m Wed Jun 10 09:02:18 2009 -0700 +++ b/MYSymmetricKey.m Wed Jul 01 14:19:13 2009 -0700 @@ -315,12 +315,6 @@ return "???"; } -- (unsigned) keySizeInBits { - const CSSM_KEY *key = self.cssmKey; - Assert(key); - return key->KeyHeader.LogicalKeySizeInBits; -} - - (NSString*) description { return $sprintf(@"%@[%u-bit %s]", [self class], self.keySizeInBits, self.algorithmName); diff -r 38c3c3923e1f -r d9c2a06d4e4e Tests/generated.cer Binary file Tests/generated.cer has changed diff -r 38c3c3923e1f -r d9c2a06d4e4e Tests/iphonedev.pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tests/iphonedev.pem Wed Jul 01 14:19:13 2009 -0700 @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFXDCCBESgAwIBAgIIGobFgVhxq7UwDQYJKoZIhvcNAQEFBQAwgZYxCzAJBgNV +BAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3Js +ZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3 +aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkw +HhcNMDkwMzMxMDUxODMxWhcNMTAwMzMxMDUxODMxWjBQMRowGAYKCZImiZPyLGQB +AQwKWE5YQVlGOU45NzElMCMGA1UEAwwcaVBob25lIERldmVsb3BlcjogSmVucyBB +bGZrZTELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQDAnbltHERIUGlrXpuiI7zJq34WuVotTSOhGbquWN9JanqesgwBqEMQLI2rcHgl +jdxwpmIuTS3vYUi8skKnn0M3NZay3/jD9pjJdbvj27B5O/OHF0vQ3wvVgyKaD/DF +qxKtC8NPr3pfTM3qZ1c/ItyyJqLwQEIaqm4DQ24eZW7XP+WDmCW2pKddwSDbhMX4 +IYnZYUIofRREpEVqxFM3eOYQ5d2QuOtEOagE+Cmll+mR9izNdUk/rQqtMcM0uW4v +DGQA8eNG9lkQ+NEgDJiamI4R4laR6JoJv8u/+brcKMWB5MzjOwB8H2vDVmbUKQHA +TNdGIT5O1S/QrK1fx6zbUsCjAgMBAAGjggHxMIIB7TAMBgNVHRMBAf8EAjAAMA4G +A1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU +JiwPQTnjJffW28sAv/MUYRR4SIUwHwYDVR0jBBgwFoAUiCcXCam2GGCL7Ou69kdZ +xVJUo7cwggEPBgNVHSAEggEGMIIBAjCB/wYJKoZIhvdjZAUBMIHxMIHDBggrBgEF +BQcCAjCBtgyBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBh +cnR5IGFzc3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0 +YW5kYXJkIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUg +cG9saWN5IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMCkG +CCsGAQUFBwIBFh1odHRwOi8vd3d3LmFwcGxlLmNvbS9hcHBsZWNhLzBNBgNVHR8E +RjBEMEKgQKA+hjxodHRwOi8vZGV2ZWxvcGVyLmFwcGxlLmNvbS9jZXJ0aWZpY2F0 +aW9uYXV0aG9yaXR5L3d3ZHJjYS5jcmwwEwYKKoZIhvdjZAYBAgEB/wQCBQAwDQYJ +KoZIhvcNAQEFBQADggEBAHDSLmE7EGuWPZ2p9v79FUzIqE8kWHwD7mCF5JfA9XWW +NAtoBxqg1600RRh1RslH6wn7eDQj/39+V4INwqOjheUkwwvsLqbw3meDAdJI3QQ/ +0D1Ig7vdAPSjo+heXauXlmrYGtMkZYr6U0nTYaPZJtj4JlJganatMPRtzHw+r35H +oZe3CtKOfE/GYGsXmTxzhkA21wX0Gd8QorVteI5n6zmU2qNcEOdVPa6hsF9f1BC8 +GKVpw5+vGOtBlimYzg7fpw940IaXaLh5Ax2zJ8pUAPjKsPAMqrr24jwVlJwH0vqa +QufMuuUFgFYsW8xPeCQs13/DaA11Hm6srm6yh8sbx58= +-----END CERTIFICATE----- diff -r 38c3c3923e1f -r d9c2a06d4e4e Tests/selfsigned.pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tests/selfsigned.pem Wed Jul 01 14:19:13 2009 -0700 @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpzCCAo+gAwIBAgIBATALBgkqhkiG9w0BAQEwezEUMBIGA1UEBBMLV2lkZGVy +c2hpbnMxIDAeBgkqhkiG9w0BCQETEXdhbGRvQGV4YW1wbGUuY29tMQ4wDAYDVQQD +EwV3YWxkbzEOMAwGA1UEKhMFV2FsZG8xITAfBgNVBA0TGEp1c3QgYSBmaWN0aXRp +b3VzIHBlcnNvbjAiGA8yMDA5MDQxMzA0NTQzNVoYDzIwMTAwNDE0MDQ1NDM1WjB7 +MRQwEgYDVQQEEwtXaWRkZXJzaGluczEgMB4GCSqGSIb3DQEJARMRd2FsZG9AZXhh +bXBsZS5jb20xDjAMBgNVBAMTBXdhbGRvMQ4wDAYDVQQqEwVXYWxkbzEhMB8GA1UE +DRMYSnVzdCBhIGZpY3RpdGlvdXMgcGVyc29uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAlXE8Ngut8thXXr0nj6JroubQXh6wTqqfpvEb/TQVVgOLMHdS +XHrb9a7fOySbCOZ/d68mf/L+uF9My5ZSadvS8B8ZtlX8TqOoXy7eEf+A+Pwj5mLy +Y/aFBqnsB/fuQkmvGE8hLZJT2H9vfLyW5rpcq8j05zv2EAsG3PPumZ1BcPXdAF2i +SlShPtrd1QZ1QJ1nKKOHX6cYmOv32T1K+HQt+aDprW3CHPr8LRln5pJXW1blN2yM +8AjopELXh2hDqS6VAbFEinWt716AT+xtCXQNHqhELmf6w77F6jr12V2flSxQdxEB +xFlCKK0UECNSUyRihIR22YfTx9ZfkFfa8ehTdwIDAQABozQwMjALBgNVHQ8EBAMC +AvwwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMA0GCSqGSIb3 +DQEBBQUAA4IBAQB5yOeJUKEfy3OY9f4M+iWVskdvU2LfvqJwrjqL/a9aVzm+YQH8 +Xgkp5XoLK0Hjq1L3jvG17MiEjNp/Qqq1fD3030ElqdtOY4gZfCoc4ybBpVIDtO/a +BXuRSrxDqj7u5qr+QwPDDwABdRa5FrVy+LdPxoKgb5IOO7+hbNrY/OPxhK3Mxh6N +O0Tli9ED8EYxD2qZLyQKspA1TATFGckiJ232MQzLjpQuOPZVXKQLcUguUhRqmYjw +IcLALShdtVnUjq97IFWfBo6hoPB/uu4pKEraKL+DRPQ18w9iY/DJnEkgzqG3xsCc ++ju7r1oP7lsOlOucV9KLG7nJd75T5Lu2df+q +-----END CERTIFICATE----- diff -r 38c3c3923e1f -r d9c2a06d4e4e Tests/selfsigned_altered.pem --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Tests/selfsigned_altered.pem Wed Jul 01 14:19:13 2009 -0700 @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDpzCCAo+gAwIBAgIBATALBgkqhkiG9w0BAQEwezEUMBIGA1UEBBMLUG9vb3B5 +c2hpbnMxIDAeBgkqhkiG9w0BCQETEXdhbGRvQGV4YW1wbGUuY29tMQ4wDAYDVQQD +EwV3YWxkbzEOMAwGA1UEKhMFV2FsZG8xITAfBgNVBA0TGEp1c3QgYSBmaWN0aXRp +b3VzIHBlcnNvbjAiGA8yMDA5MDQxMzA0NTQzNVoYDzIwMTAwNDE0MDQ1NDM1WjB7 +MRQwEgYDVQQEEwtQb29vcHlzaGluczEgMB4GCSqGSIb3DQEJARMRd2FsZG9AZXhh +bXBsZS5jb20xDjAMBgNVBAMTBXdhbGRvMQ4wDAYDVQQqEwVXYWxkbzEhMB8GA1UE +DRMYSnVzdCBhIGZpY3RpdGlvdXMgcGVyc29uMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEAlXE8Ngut8thXXr0nj6JroubQXh6wTqqfpvEb/TQVVgOLMHdS +XHrb9a7fOySbCOZ/d68mf/L+uF9My5ZSadvS8B8ZtlX8TqOoXy7eEf+A+Pwj5mLy +Y/aFBqnsB/fuQkmvGE8hLZJT2H9vfLyW5rpcq8j05zv2EAsG3PPumZ1BcPXdAF2i +SlShPtrd1QZ1QJ1nKKOHX6cYmOv32T1K+HQt+aDprW3CHPr8LRln5pJXW1blN2yM +8AjopELXh2hDqS6VAbFEinWt716AT+xtCXQNHqhELmf6w77F6jr12V2flSxQdxEB +xFlCKK0UECNSUyRihIR22YfTx9ZfkFfa8ehTdwIDAQABozQwMjALBgNVHQ8EBAMC +AvwwIwYDVR0lBBwwGgYIKwYBBQUHAwEGCCsGAQUFBwMCBgRVHSUAMA0GCSqGSIb3 +DQEBBQUAA4IBAQB5yOeJUKEfy3OY9f4M+iWVskdvU2LfvqJwrjqL/a9aVzm+YQH8 +Xgkp5XoLK0Hjq1L3jvG17MiEjNp/Qqq1fD3030ElqdtOY4gZfCoc4ybBpVIDtO/a +BXuRSrxDqj7u5qr+QwPDDwABdRa5FrVy+LdPxoKgb5IOO7+hbNrY/OPxhK3Mxh6N +O0Tli9ED8EYxD2qZLyQKspA1TATFGckiJ232MQzLjpQuOPZVXKQLcUguUhRqmYjw +IcLALShdtVnUjq97IFWfBo6hoPB/uu4pKEraKL+DRPQ18w9iYwDJnEkgzqG3xsCc ++ju7r1oP7lsOlOucV9KLG7nJd75T5Lu2df+q +-----END CERTIFICATE-----