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