* More work on iPhone compatibility.
* Restored the signature-verification code to MYCertInfo, which I'd removed earlier. I now need it to verify self-signed certs, since the Security framework won't do it for me.
* Merged MYCertificate-iPhone.m into MYCertificate.m since there's more shared code now.
1.1 --- a/MYCertificate-iPhone.m Sun Jun 07 21:53:56 2009 -0700
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,107 +0,0 @@
1.4 -//
1.5 -// MYCertificate-iPhone.m
1.6 -// MYCrypto-iPhone
1.7 -//
1.8 -// Created by Jens Alfke on 3/30/09.
1.9 -// Copyright 2009 Jens Alfke. All rights reserved.
1.10 -//
1.11 -
1.12 -#import "MYCertificate.h"
1.13 -#import "MYCertificateInfo.h"
1.14 -#import "MYCrypto_Private.h"
1.15 -
1.16 -#if MYCRYPTO_USE_IPHONE_API
1.17 -
1.18 -
1.19 -@implementation MYCertificate
1.20 -
1.21 -
1.22 -+ (MYCertificate*) certificateWithCertificateRef: (SecCertificateRef)certificateRef {
1.23 - return [[[self alloc] initWithCertificateRef: certificateRef] autorelease];
1.24 -}
1.25 -
1.26 -/** Creates a MYCertificate object for an existing Keychain certificate reference. */
1.27 -- (id) initWithCertificateRef: (SecCertificateRef)certificateRef {
1.28 - self = [super initWithKeychainItemRef: (SecKeychainItemRef)certificateRef];
1.29 - if (self) {
1.30 - _certificateRef = certificateRef; // superclass has already CFRetained it
1.31 - }
1.32 - return self;
1.33 -}
1.34 -
1.35 -/** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
1.36 -- (id) initWithCertificateData: (NSData*)data
1.37 -{
1.38 - SecCertificateRef certificateRef = SecCertificateCreateWithData(NULL, (CFDataRef)data);
1.39 - self = [self initWithCertificateRef: certificateRef];
1.40 - CFRelease(certificateRef);
1.41 - return self;
1.42 -}
1.43 -
1.44 -- (void) dealloc
1.45 -{
1.46 - [_info release];
1.47 - [super dealloc];
1.48 -}
1.49 -
1.50 -
1.51 -- (BOOL)isEqualToCertificate:(MYCertificate*)cert {
1.52 - return [self isEqual: cert] || [self.certificateData isEqual: cert.certificateData];
1.53 -}
1.54 -
1.55 -@synthesize certificateRef=_certificateRef;
1.56 -
1.57 -- (NSData*) certificateData {
1.58 - CFDataRef data = SecCertificateCopyData(_certificateRef);
1.59 - return data ?[(id)CFMakeCollectable(data) autorelease] :nil;
1.60 -}
1.61 -
1.62 -- (MYPublicKey*) publicKey {
1.63 - SecTrustRef trust = NULL;
1.64 - SecPolicyRef policy = SecPolicyCreateBasicX509();
1.65 - OSStatus err = SecTrustCreateWithCertificates((CFArrayRef)$array((id)_certificateRef),
1.66 - policy,
1.67 - &trust);
1.68 - CFRelease(policy);
1.69 - if (!check(err,@"SecTrustCreateWithCertificates"))
1.70 - return nil;
1.71 -
1.72 - MYPublicKey *key = nil;
1.73 - SecKeyRef keyRef = SecTrustCopyPublicKey(trust);
1.74 - if (keyRef) {
1.75 - key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
1.76 - CFRelease(keyRef);
1.77 - }
1.78 - CFRelease(trust);
1.79 - return key;
1.80 -}
1.81 -
1.82 -- (MYIdentity*) identity {
1.83 - return [self.keychain identityWithDigest: self.publicKey.publicKeyDigest];
1.84 -}
1.85 -
1.86 -
1.87 -- (MYCertificateInfo*) info {
1.88 - if (!_info) {
1.89 - NSError *error;
1.90 - _info = [[MYCertificateInfo alloc] initWithCertificateData: self.certificateData
1.91 - error: &error];
1.92 - if (!_info)
1.93 - Warn(@"Couldn't parse certificate %@: %@", self, error);
1.94 - }
1.95 - return _info;
1.96 -}
1.97 -
1.98 -- (NSString*) commonName {
1.99 - CFStringRef name = SecCertificateCopySubjectSummary(_certificateRef);
1.100 - return name ?[(id)CFMakeCollectable(name) autorelease] :nil;
1.101 -}
1.102 -
1.103 -- (NSArray*) emailAddresses {
1.104 - NSString *email = self.info.subject.emailAddress;
1.105 - return email ?$array(email) :nil;
1.106 -}
1.107 -
1.108 -@end
1.109 -
1.110 -#endif MYCRYPTO_USE_IPHONE_API
2.1 --- a/MYCertificate.h Sun Jun 07 21:53:56 2009 -0700
2.2 +++ b/MYCertificate.h Tue Jun 09 23:58:03 2009 -0700
2.3 @@ -55,6 +55,9 @@
2.4 /** The list (if any) of the subject's email addresses. */
2.5 @property (readonly) NSArray *emailAddresses;
2.6
2.7 +- (SecTrustResultType) evaluateTrustWithPolicy: (SecPolicyRef)policy;
2.8 +- (SecTrustResultType) evaluateTrust;
2.9 +
2.10
2.11 /** @name Mac-Only
2.12 * Functionality not available on iPhone.
2.13 @@ -80,21 +83,24 @@
2.14 /** @name Expert
2.15 */
2.16 //@{
2.17 -#if !TARGET_OS_IPHONE
2.18
2.19 + (SecPolicyRef) X509Policy;
2.20 + (SecPolicyRef) SSLPolicy;
2.21 +
2.22 +#if !TARGET_OS_IPHONE
2.23 + (SecPolicyRef) SMIMEPolicy;
2.24 - (CSSM_CERT_TYPE) certificateType;
2.25 - (NSArray*) trustSettings;
2.26 - (BOOL) setUserTrust: (SecTrustUserSetting)trustSetting;
2.27 +#endif
2.28
2.29 -#endif
2.30 //@}
2.31
2.32 @end
2.33
2.34
2.35 +NSString* MYTrustResultDescribe( SecTrustResultType result );
2.36 +#if !TARGET_OS_IPHONE
2.37 NSString* MYPolicyGetName( SecPolicyRef policy );
2.38 NSString* MYTrustDescribe( SecTrustRef trust );
2.39 -NSString* MYTrustResultDescribe( SecTrustResultType result );
2.40 +#endif
3.1 --- a/MYCertificate.m Sun Jun 07 21:53:56 2009 -0700
3.2 +++ b/MYCertificate.m Tue Jun 09 23:58:03 2009 -0700
3.3 @@ -13,8 +13,6 @@
3.4 #import "MYCertificateInfo.h"
3.5 #import "MYErrorUtils.h"
3.6
3.7 -#if !MYCRYPTO_USE_IPHONE_API
3.8 -
3.9
3.10 @implementation MYCertificate
3.11
3.12 @@ -34,28 +32,51 @@
3.13
3.14 /** Creates a MYCertificate object from exported key data, but does not add it to any keychain. */
3.15 - (id) initWithCertificateData: (NSData*)data
3.16 +#if !MYCRYPTO_USE_IPHONE_API
3.17 type: (CSSM_CERT_TYPE) type
3.18 encoding: (CSSM_CERT_ENCODING) encoding
3.19 +#endif
3.20 {
3.21 Assert(data);
3.22 + SecCertificateRef certificateRef = NULL;
3.23 +#if MYCRYPTO_USE_IPHONE_API
3.24 + certificateRef = SecCertificateCreateWithData(NULL, (CFDataRef)data);
3.25 +#else
3.26 CSSM_DATA cssmData = {.Data=(void*)data.bytes, .Length=data.length};
3.27 - SecCertificateRef certificateRef = NULL;
3.28 if (!check(SecCertificateCreateFromData(&cssmData, type, encoding, &certificateRef),
3.29 - @"SecCertificateCreateFromData")) {
3.30 + @"SecCertificateCreateFromData"))
3.31 + certificateRef = NULL;
3.32 +#endif
3.33 + if (!certificateRef) {
3.34 [self release];
3.35 return nil;
3.36 }
3.37 self = [self initWithCertificateRef: certificateRef];
3.38 CFRelease(certificateRef);
3.39 +
3.40 + // If the cert is self-signed, verify its signature. Apple's frameworks don't do this,
3.41 + // even the SecTrust API; if the signature doesn't verify, they just assume it could be
3.42 + // signed by a different cert. Seems like a bad decision to me, so I'll add the check:
3.43 + MYCertificateInfo *info = self.info;
3.44 + if (info.isRoot) {
3.45 + Log(@"Verifying self-signed certificate %@ ...", self);
3.46 + if (![info verifySignatureWithKey: self.publicKey]) {
3.47 + Log(@"Self-signed cert failed signature verification (%@)", self);
3.48 + [self release];
3.49 + return nil;
3.50 + }
3.51 + }
3.52 +
3.53 return self;
3.54 }
3.55
3.56 +#if !MYCRYPTO_USE_IPHONE_API
3.57 - (id) initWithCertificateData: (NSData*)data {
3.58 return [self initWithCertificateData: data
3.59 type: CSSM_CERT_X_509v3
3.60 encoding: CSSM_CERT_ENCODING_BER];
3.61 }
3.62 -
3.63 +#endif
3.64 - (void) dealloc
3.65 {
3.66 [_info release];
3.67 @@ -78,6 +99,7 @@
3.68 }
3.69
3.70
3.71 +#if !TARGET_OS_IPHONE
3.72 + (MYCertificate*) preferredCertificateForName: (NSString*)name {
3.73 SecCertificateRef certRef = NULL;
3.74 if (!check(SecCertificateCopyPreference((CFStringRef)name, 0, &certRef),
3.75 @@ -90,23 +112,49 @@
3.76 return check(SecCertificateSetPreference(_certificateRef, (CFStringRef)name, 0, NULL),
3.77 @"SecCertificateSetPreference");
3.78 }
3.79 +#endif TARGET_OS_IPHONE
3.80
3.81
3.82 @synthesize certificateRef=_certificateRef;
3.83
3.84 - (NSData*) certificateData {
3.85 +#if MYCRYPTO_USE_IPHONE_API
3.86 + CFDataRef data = SecCertificateCopyData(_certificateRef);
3.87 + return data ?[(id)CFMakeCollectable(data) autorelease] :nil;
3.88 +#else
3.89 CSSM_DATA cssmData;
3.90 if (!check(SecCertificateGetData(_certificateRef, &cssmData),
3.91 @"SecCertificateGetData"))
3.92 return nil;
3.93 return [NSData dataWithBytes: cssmData.Data length: cssmData.Length];
3.94 +#endif
3.95 }
3.96
3.97 - (MYPublicKey*) publicKey {
3.98 SecKeyRef keyRef = NULL;
3.99 +#if MYCRYPTO_USE_IPHONE_API
3.100 + SecTrustRef trust = NULL;
3.101 + SecPolicyRef policy = SecPolicyCreateBasicX509();
3.102 + OSStatus err = SecTrustCreateWithCertificates((CFArrayRef)$array((id)_certificateRef),
3.103 + policy,
3.104 + &trust);
3.105 + CFRelease(policy);
3.106 + if (!check(err,@"SecTrustCreateWithCertificates"))
3.107 + return nil;
3.108 + SecTrustResultType result;
3.109 + if (!check(SecTrustEvaluate(trust, &result), @"SecTrustEvaluate")) {
3.110 + CFRelease(trust);
3.111 + return nil;
3.112 + }
3.113 + keyRef = SecTrustCopyPublicKey(trust);
3.114 + CFRelease(trust);
3.115 +#else
3.116 if (!check(SecCertificateCopyPublicKey(_certificateRef, &keyRef),
3.117 @"SecCertificateCopyPublicKey") || !keyRef)
3.118 return nil;
3.119 +#endif
3.120 + if (!keyRef)
3.121 + return nil;
3.122 MYPublicKey *key = [[[MYPublicKey alloc] initWithKeyRef: keyRef] autorelease];
3.123 CFRelease(keyRef);
3.124 return key;
3.125 @@ -129,18 +177,27 @@
3.126
3.127 - (NSString*) commonName {
3.128 CFStringRef name = NULL;
3.129 +#if MYCRYPTO_USE_IPHONE_API
3.130 + name = SecCertificateCopySubjectSummary(_certificateRef);
3.131 +#else
3.132 if (!check(SecCertificateCopyCommonName(_certificateRef, &name),
3.133 - @"SecCertificateCopyCommonName") || !name)
3.134 + @"SecCertificateCopyCommonName"))
3.135 return nil;
3.136 - return [(id)CFMakeCollectable(name) autorelease];
3.137 +#endif
3.138 + return name ?[NSMakeCollectable(name) autorelease] :nil;
3.139 }
3.140
3.141 - (NSArray*) emailAddresses {
3.142 +#if MYCRYPTO_USE_IPHONE_API
3.143 + NSString *email = self.info.subject.emailAddress;
3.144 + return email ?$array(email) :nil;
3.145 +#else
3.146 CFArrayRef addrs = NULL;
3.147 if (!check(SecCertificateCopyEmailAddresses(_certificateRef, &addrs),
3.148 @"SecCertificateCopyEmailAddresses") || !addrs)
3.149 return nil;
3.150 return [(id)CFMakeCollectable(addrs) autorelease];
3.151 +#endif
3.152 }
3.153
3.154
3.155 @@ -148,6 +205,37 @@
3.156 #pragma mark TRUST/POLICY STUFF:
3.157
3.158
3.159 +- (SecTrustResultType) evaluateTrustWithPolicy: (SecPolicyRef)policy {
3.160 + SecTrustRef trust;
3.161 + if (!check(SecTrustCreateWithCertificates((CFArrayRef)$array((id)_certificateRef), policy, &trust),
3.162 + @"SecTrustCreateWithCertificates"))
3.163 + return kSecTrustResultOtherError;
3.164 + SecTrustResultType result;
3.165 + if (!check(SecTrustEvaluate(trust, &result), @"SecTrustEvaluate"))
3.166 + result = kSecTrustResultOtherError;
3.167 +
3.168 +#if 0
3.169 + // This is just to log details:
3.170 + CSSM_TP_APPLE_EVIDENCE_INFO *status;
3.171 + CFArrayRef certChain;
3.172 + if (check(SecTrustGetResult(trust, &result, &certChain, &status), @"SecTrustGetResult")) {
3.173 + Log(@"evaluateTrust: result=%@, bits=%X, certChain=%@", MYTrustResultDescribe(result),status->StatusBits, certChain);
3.174 + for (unsigned i=0; i<status->NumStatusCodes; i++)
3.175 + Log(@" #%i: %X", i, status->StatusCodes[i]);
3.176 + CFRelease(certChain);
3.177 + }
3.178 +#endif
3.179 +
3.180 + CFRelease(trust);
3.181 + return result;
3.182 +}
3.183 +
3.184 +- (SecTrustResultType) evaluateTrust {
3.185 + return [self evaluateTrustWithPolicy: [[self class] X509Policy]];
3.186 +}
3.187 +
3.188 +
3.189 +#if !MYCRYPTO_USE_IPHONE_API
3.190 + (SecPolicyRef) policyForOID: (CSSM_OID) policyOID {
3.191 SecPolicySearchRef search;
3.192 if (!check(SecPolicySearchCreate(CSSM_CERT_X_509v3, &policyOID, NULL, &search),
3.193 @@ -159,29 +247,41 @@
3.194 CFRelease(search);
3.195 return policy;
3.196 }
3.197 +#endif
3.198
3.199 + (SecPolicyRef) X509Policy {
3.200 static SecPolicyRef sX509Policy = NULL;
3.201 - if (!sX509Policy)
3.202 + if (!sX509Policy) {
3.203 +#if MYCRYPTO_USE_IPHONE_API
3.204 + sX509Policy = SecPolicyCreateBasicX509();
3.205 +#else
3.206 sX509Policy = [self policyForOID: CSSMOID_APPLE_X509_BASIC];
3.207 +#endif
3.208 + }
3.209 return sX509Policy;
3.210 }
3.211
3.212 + (SecPolicyRef) SSLPolicy {
3.213 static SecPolicyRef sSSLPolicy = NULL;
3.214 - if (!sSSLPolicy)
3.215 + if (!sSSLPolicy) {
3.216 +#if MYCRYPTO_USE_IPHONE_API
3.217 + sSSLPolicy = SecPolicyCreateSSL(NO,NULL);
3.218 +#else
3.219 sSSLPolicy = [self policyForOID: CSSMOID_APPLE_TP_SSL];
3.220 +#endif
3.221 + }
3.222 return sSSLPolicy;
3.223 }
3.224
3.225 +#if !TARGET_OS_IPHONE
3.226 + (SecPolicyRef) SMIMEPolicy {
3.227 static SecPolicyRef sSMIMEPolicy = NULL;
3.228 - if (!sSMIMEPolicy)
3.229 + if (!sSMIMEPolicy) {
3.230 sSMIMEPolicy = [self policyForOID: CSSMOID_APPLE_TP_SMIME];
3.231 + }
3.232 return sSMIMEPolicy;
3.233 }
3.234
3.235 -
3.236 - (CSSM_CERT_TYPE) certificateType {
3.237 CSSM_CERT_TYPE type = CSSM_CERT_UNKNOWN;
3.238 if (!check(SecCertificateGetType(_certificateRef, &type), @"SecCertificateGetType"))
3.239 @@ -212,19 +312,12 @@
3.240 } else
3.241 return paramErr;
3.242 }
3.243 +#endif
3.244
3.245
3.246 @end
3.247
3.248
3.249 -NSString* MYPolicyGetName( SecPolicyRef policy ) {
3.250 - if (!policy)
3.251 - return @"(null)";
3.252 - CSSM_OID oid = {};
3.253 - SecPolicyGetOID(policy, &oid);
3.254 - return $sprintf(@"SecPolicy[%@]", OIDAsString(oid));
3.255 -}
3.256 -
3.257 NSString* MYTrustResultDescribe( SecTrustResultType result ) {
3.258 static NSString* const kTrustResultNames[kSecTrustResultOtherError+1] = {
3.259 @"Invalid",
3.260 @@ -243,6 +336,15 @@
3.261 }
3.262
3.263
3.264 +#if !TARGET_OS_IPHONE
3.265 +NSString* MYPolicyGetName( SecPolicyRef policy ) {
3.266 + if (!policy)
3.267 + return @"(null)";
3.268 + CSSM_OID oid = {};
3.269 + SecPolicyGetOID(policy, &oid);
3.270 + return $sprintf(@"SecPolicy[%@]", OIDAsString(oid));
3.271 +}
3.272 +
3.273 NSString* MYTrustDescribe( SecTrustRef trust ) {
3.274 SecTrustResultType result;
3.275 CFArrayRef certChain=NULL;
3.276 @@ -275,9 +377,10 @@
3.277 return result;
3.278 }
3.279 }
3.280 +#endif
3.281
3.282
3.283 -
3.284 +#if !TARGET_OS_IPHONE
3.285 TestCase(Trust) {
3.286 Log(@"X.509 policy = %@", MYPolicyGetName([MYCertificate X509Policy]));
3.287 Log(@" SSL policy = %@", MYPolicyGetName([MYCertificate SSLPolicy]));
3.288 @@ -288,9 +391,7 @@
3.289 Log(@"---- %@ = %@", cert, settings);
3.290 }
3.291 }
3.292 -
3.293 -
3.294 -#endif !MYCRYPTO_USE_IPHONE_API
3.295 +#endif
3.296
3.297
3.298
4.1 --- a/MYCertificateInfo.h Sun Jun 07 21:53:56 2009 -0700
4.2 +++ b/MYCertificateInfo.h Tue Jun 09 23:58:03 2009 -0700
4.3 @@ -14,6 +14,7 @@
4.4 {
4.5 @private
4.6 NSArray *_root;
4.7 + NSData *_data;
4.8 }
4.9
4.10 /** Initialize by parsing X.509 certificate data.
4.11 @@ -35,6 +36,10 @@
4.12 /** Returns YES if the issuer is the same as the subject. (Aka a "self-signed" certificate.) */
4.13 @property (readonly) BOOL isRoot;
4.14
4.15 +/** Verifies the certificate's signature, using the given public key.
4.16 + If the certificate is root/self-signed, use the cert's own subject public key. */
4.17 +- (BOOL) verifySignatureWithKey: (MYPublicKey*)issuerPublicKey;
4.18 +
4.19 @end
4.20
4.21
5.1 --- a/MYCertificateInfo.m Sun Jun 07 21:53:56 2009 -0700
5.2 +++ b/MYCertificateInfo.m Tue Jun 09 23:58:03 2009 -0700
5.3 @@ -107,12 +107,17 @@
5.4 return nil;
5.5 }
5.6
5.7 - return [self initWithRoot: root];
5.8 + self = [self initWithRoot: root];
5.9 + if (self) {
5.10 + _data = [data copy];
5.11 + }
5.12 + return self;
5.13 }
5.14
5.15 - (void) dealloc
5.16 {
5.17 [_root release];
5.18 + [_data release];
5.19 [super dealloc];
5.20 }
5.21
5.22 @@ -157,6 +162,42 @@
5.23 return [[[MYPublicKey alloc] initWithKeyData: keyData.bits] autorelease];
5.24 }
5.25
5.26 +- (NSData*) signedData {
5.27 + if (!_data)
5.28 + return nil;
5.29 + // The root object is a sequence; we want to extract the 1st object of that sequence.
5.30 + const UInt8 *certStart = _data.bytes;
5.31 + const UInt8 *start = MYBERGetContents(_data, nil);
5.32 + if (!start) return nil;
5.33 + size_t length = MYBERGetLength([NSData dataWithBytesNoCopy: (void*)start
5.34 + length: _data.length - (start-certStart)
5.35 + freeWhenDone: NO],
5.36 + NULL);
5.37 + if (length==0)
5.38 + return nil;
5.39 + return [NSData dataWithBytes: start length: (start + length - certStart)];
5.40 +}
5.41 +
5.42 +- (MYOID*) signatureAlgorithmID {
5.43 + return $castIf(MYOID, $atIf($castIf(NSArray,$atIf(_root,1)), 0));
5.44 +}
5.45 +
5.46 +- (NSData*) signature {
5.47 + id signature = $atIf(_root,2);
5.48 + if ([signature isKindOfClass: [MYBitString class]])
5.49 + signature = [signature bits];
5.50 + return $castIf(NSData,signature);
5.51 +}
5.52 +
5.53 +- (BOOL) verifySignatureWithKey: (MYPublicKey*)issuerPublicKey {
5.54 + if (!$equal(self.signatureAlgorithmID, kRSAWithSHA1AlgorithmID))
5.55 + return NO;
5.56 + NSData *signedData = self.signedData;
5.57 + NSData *signature = self.signature;
5.58 + return signedData && signature && [issuerPublicKey verifySignature: signature ofData: signedData];
5.59 +}
5.60 +
5.61 +
5.62 @end
5.63
5.64
5.65 @@ -364,28 +405,45 @@
5.66 CAssert(subject.commonName);
5.67
5.68 // Now go through MYCertificate:
5.69 + Log(@"Creating a MYCertificate from the data...");
5.70 MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: certData];
5.71 + Log(@"MYCertificate = %@", cert);
5.72 CAssert(cert);
5.73 CAssertEqual(cert.info, pcert);
5.74 + Log(@"Trust = %@", MYTrustResultDescribe([cert evaluateTrust]));
5.75
5.76 return pcert;
5.77 }
5.78
5.79 -static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
5.80 +static NSData* readTestFile(NSString *filename) {
5.81 #if TARGET_OS_IPHONE
5.82 filename = [[NSBundle mainBundle] pathForResource: filename ofType: @"cer"];
5.83 #else
5.84 filename = [[@"../../Tests/" stringByAppendingPathComponent: filename]
5.85 stringByAppendingPathExtension: @"cer"];
5.86 #endif
5.87 - Log(@"--- Creating MYCertificateInfo from %@", filename);
5.88 - return testCertData([NSData dataWithContentsOfFile: filename], selfSigned);
5.89 + Log(@"--- Testing certificate file %@", filename);
5.90 + NSData *data = [NSData dataWithContentsOfFile: filename];
5.91 + CAssert(data, @"Couldn't read file %@", filename);
5.92 + return data;
5.93 +}
5.94 +
5.95 +static MYCertificateInfo* testCert(NSString *filename, BOOL selfSigned) {
5.96 + return testCertData(readTestFile(filename), selfSigned);
5.97 }
5.98
5.99
5.100 TestCase(ParsedCert) {
5.101 testCert(@"selfsigned", YES);
5.102 testCert(@"iphonedev", NO);
5.103 +
5.104 + // Now test a self-signed cert with a bad signature:
5.105 + MYCertificate *cert = [[MYCertificate alloc] initWithCertificateData: readTestFile(@"selfsigned_altered")];
5.106 + Log(@"MYCertificate = %@", cert);
5.107 + CAssertNil(cert);
5.108 +
5.109 + Log(@"Checking /tmp/generated.cer");
5.110 + testCertData([NSData dataWithContentsOfFile: @"/tmp/generated.cer"], YES);//TEMP
5.111 }
5.112
5.113
5.114 @@ -418,7 +476,11 @@
5.115 CAssert(certData);
5.116 CAssertNil(error);
5.117 CAssert(certData);
5.118 -#if !TARGET_OS_IPHONE
5.119 +#if TARGET_OS_IPHONE
5.120 + NSString *path = [@"/tmp/generated.cer" stringByStandardizingPath]; //TEMP
5.121 + CAssert([certData writeToFile: path atomically: YES]);
5.122 + Log(@"Wrote generated cert to %@",path);
5.123 +#else
5.124 [certData writeToFile: @"../../Tests/generated.cer" atomically: YES];
5.125 #endif
5.126 MYCertificateInfo *pcert2 = testCertData(certData, YES);
6.1 --- a/MYCrypto-iPhone.xcodeproj/project.pbxproj Sun Jun 07 21:53:56 2009 -0700
6.2 +++ b/MYCrypto-iPhone.xcodeproj/project.pbxproj Tue Jun 09 23:58:03 2009 -0700
6.3 @@ -12,7 +12,6 @@
6.4 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
6.5 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
6.6 27059CF30F8F0F9200A8422F /* MYIdentity.m in Sources */ = {isa = PBXBuildFile; fileRef = 27059CF20F8F0F9200A8422F /* MYIdentity.m */; };
6.7 - 273391CD0F81EC70009414D9 /* MYCertificate-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273391CC0F81EC70009414D9 /* MYCertificate-iPhone.m */; };
6.8 273392120F8283B8009414D9 /* MYKeychain-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 273392110F8283B8009414D9 /* MYKeychain-iPhone.m */; };
6.9 274110090F99234100AD413F /* MYSymmetricKey-iPhone.m in Sources */ = {isa = PBXBuildFile; fileRef = 274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */; };
6.10 2748607F0F8D5E0600FE617B /* MYPrivateKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 2748607E0F8D5E0600FE617B /* MYPrivateKey.m */; };
6.11 @@ -20,6 +19,7 @@
6.12 275D9FF00FD8795300D85A86 /* MYBERParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FE80FD8795300D85A86 /* MYBERParser.m */; };
6.13 275D9FF10FD8795300D85A86 /* MYDEREncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */; };
6.14 275D9FF20FD8795300D85A86 /* MYOID.m in Sources */ = {isa = PBXBuildFile; fileRef = 275D9FEC0FD8795300D85A86 /* MYOID.m */; };
6.15 + 275ED90F0FDF8C22006A371D /* selfsigned_altered.cer in Resources */ = {isa = PBXBuildFile; fileRef = 275ED90E0FDF8C22006A371D /* selfsigned_altered.cer */; };
6.16 276FB13F0F84090900CB326E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 276FB13E0F84090900CB326E /* Security.framework */; };
6.17 276FB16E0F84152B00CB326E /* MYCryptoTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB16D0F84152B00CB326E /* MYCryptoTest.m */; };
6.18 276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */ = {isa = PBXBuildFile; fileRef = 276FB3180F856AA700CB326E /* MYPublicKey.m */; };
6.19 @@ -54,7 +54,6 @@
6.20 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
6.21 27059CF10F8F0F8E00A8422F /* MYIdentity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYIdentity.h; sourceTree = "<group>"; };
6.22 27059CF20F8F0F9200A8422F /* MYIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYIdentity.m; sourceTree = "<group>"; };
6.23 - 273391CC0F81EC70009414D9 /* MYCertificate-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYCertificate-iPhone.m"; sourceTree = "<group>"; };
6.24 273392110F8283B8009414D9 /* MYKeychain-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYKeychain-iPhone.m"; sourceTree = "<group>"; };
6.25 274110080F99234100AD413F /* MYSymmetricKey-iPhone.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MYSymmetricKey-iPhone.m"; sourceTree = "<group>"; };
6.26 2748607D0F8D5DF200FE617B /* MYPrivateKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYPrivateKey.h; sourceTree = "<group>"; };
6.27 @@ -67,6 +66,7 @@
6.28 275D9FEA0FD8795300D85A86 /* MYDEREncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYDEREncoder.m; sourceTree = "<group>"; };
6.29 275D9FEB0FD8795300D85A86 /* MYOID.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MYOID.h; sourceTree = "<group>"; };
6.30 275D9FEC0FD8795300D85A86 /* MYOID.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYOID.m; sourceTree = "<group>"; };
6.31 + 275ED90E0FDF8C22006A371D /* selfsigned_altered.cer */ = {isa = PBXFileReference; lastKnownFileType = file; name = selfsigned_altered.cer; path = Tests/selfsigned_altered.cer; sourceTree = "<group>"; };
6.32 276FB13E0F84090900CB326E /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
6.33 276FB16D0F84152B00CB326E /* MYCryptoTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYCryptoTest.m; sourceTree = "<group>"; };
6.34 276FB3180F856AA700CB326E /* MYPublicKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MYPublicKey.m; sourceTree = "<group>"; };
6.35 @@ -161,6 +161,7 @@
6.36 275D9FEC0FD8795300D85A86 /* MYOID.m */,
6.37 27958CA10FDB5F8F00095275 /* iphonedev.cer */,
6.38 27958CA20FDB5F8F00095275 /* selfsigned.cer */,
6.39 + 275ED90E0FDF8C22006A371D /* selfsigned_altered.cer */,
6.40 );
6.41 name = Certificates;
6.42 sourceTree = "<group>";
6.43 @@ -180,7 +181,6 @@
6.44 27AAD9710F8927DB0064DD7C /* MYCryptoConfig.h */,
6.45 27E8230C0F81D56E0019BE60 /* MYCertificate.h */,
6.46 276FB34A0F856CA400CB326E /* MYCertificate.m */,
6.47 - 273391CC0F81EC70009414D9 /* MYCertificate-iPhone.m */,
6.48 27059CF10F8F0F8E00A8422F /* MYIdentity.h */,
6.49 27059CF20F8F0F9200A8422F /* MYIdentity.m */,
6.50 27E823100F81D56E0019BE60 /* MYKey.h */,
6.51 @@ -299,6 +299,7 @@
6.52 27E8233C0F81D5760019BE60 /* MYError_CSSMErrorDomain.strings in Resources */,
6.53 27958CA30FDB5F8F00095275 /* iphonedev.cer in Resources */,
6.54 27958CA40FDB5F8F00095275 /* selfsigned.cer in Resources */,
6.55 + 275ED90F0FDF8C22006A371D /* selfsigned_altered.cer in Resources */,
6.56 );
6.57 runOnlyForDeploymentPostprocessing = 0;
6.58 };
6.59 @@ -318,7 +319,6 @@
6.60 27E823390F81D5760019BE60 /* Logging.m in Sources */,
6.61 27E8233A0F81D5760019BE60 /* Test.m in Sources */,
6.62 27E8233B0F81D5760019BE60 /* MYErrorUtils.m in Sources */,
6.63 - 273391CD0F81EC70009414D9 /* MYCertificate-iPhone.m in Sources */,
6.64 273392120F8283B8009414D9 /* MYKeychain-iPhone.m in Sources */,
6.65 276FB16E0F84152B00CB326E /* MYCryptoTest.m in Sources */,
6.66 276FB3190F856AA700CB326E /* MYPublicKey.m in Sources */,
7.1 --- a/MYKey-iPhone.m Sun Jun 07 21:53:56 2009 -0700
7.2 +++ b/MYKey-iPhone.m Tue Jun 09 23:58:03 2009 -0700
7.3 @@ -59,7 +59,7 @@
7.4
7.5
7.6 - (id) initWithKeyRef: (SecKeyRef)key {
7.7 - return [super initWithKeychainItemRef: (SecKeychainItemRef)key];
7.8 + return [self initWithKeychainItemRef: (SecKeychainItemRef)key];
7.9 }
7.10
7.11
7.12 @@ -114,7 +114,8 @@
7.13 return nil;
7.14 else {
7.15 Assert(data!=NULL);
7.16 - return [(id)CFMakeCollectable(data) autorelease];
7.17 + _keyData = NSMakeCollectable(data);
7.18 + return _keyData;
7.19 }
7.20 // The format of this data is not documented. There's been some reverse-engineering:
7.21 // https://devforums.apple.com/message/32089#32089
7.22 @@ -147,9 +148,7 @@
7.23 - (BOOL) setValue: (NSString*)value ofAttribute: (SecKeychainAttrType)attribute {
7.24 if (!value)
7.25 value = (id)[NSNull null];
7.26 - NSDictionary *query = $dict( {(id)kSecClass, (id)kSecClassKey},
7.27 - {(id)kSecAttrKeyClass, (id)self.keyClass},
7.28 - {(id)kSecMatchItemList, self._itemList} );
7.29 + NSDictionary *query = $dict( {(id)kSecValueRef, (id)self.keyRef} );
7.30 NSDictionary *attrs = $dict( {(id)attribute, value} );
7.31 return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
7.32 }
8.1 --- a/MYKey.h Sun Jun 07 21:53:56 2009 -0700
8.2 +++ b/MYKey.h Tue Jun 09 23:58:03 2009 -0700
8.3 @@ -29,6 +29,7 @@
8.4 Concrete subclasses are MYSymmetricKey and MYPublicKey. */
8.5 @interface MYKey : MYKeychainItem
8.6 {
8.7 + @private
8.8 NSData *_keyData;
8.9 }
8.10
9.1 --- a/MYKeychain-iPhone.m Sun Jun 07 21:53:56 2009 -0700
9.2 +++ b/MYKeychain-iPhone.m Tue Jun 09 23:58:03 2009 -0700
9.3 @@ -220,6 +220,22 @@
9.4 }
9.5
9.6
9.7 +- (BOOL) _verifyPublicKeyRef: (MYKeychainItemRef)itemRef {
9.8 + // Enumerating the keychain sometimes returns public-key refs that give not-found errors
9.9 + // when you try to use them for anything. As a workaround, detect these early on before
9.10 + // even creating a MYPublicKey:
9.11 + NSDictionary *info = $dict({(id)kSecValueRef, (id)itemRef},
9.12 + {(id)kSecReturnAttributes, $true});
9.13 + CFDictionaryRef attrs = NULL;
9.14 + OSStatus err = SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs);
9.15 + if (attrs) CFRelease(attrs);
9.16 + if (err == errSecItemNotFound) {
9.17 + Log(@"MYKeyEnumerator: Ignoring bogus(?) key with ref %p", itemRef);
9.18 + return NO;
9.19 + } else
9.20 + return YES;
9.21 +}
9.22 +
9.23 - (id) nextObject {
9.24 if (!_results)
9.25 return nil;
9.26 @@ -229,7 +245,8 @@
9.27 if (_itemClass == kSecAttrKeyClassPrivate) {
9.28 _currentObject = [[MYPrivateKey alloc] initWithKeyRef: (SecKeyRef)found];
9.29 } else if (_itemClass == kSecAttrKeyClassPublic) {
9.30 - _currentObject = [[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found];
9.31 + if ([self _verifyPublicKeyRef: found])
9.32 + _currentObject = [[MYPublicKey alloc] initWithKeyRef: (SecKeyRef)found];
9.33 } else if (_itemClass == kSecAttrKeyClassSymmetric) {
9.34 _currentObject = [[MYSymmetricKey alloc] initWithKeyRef: (SecKeyRef)found];
9.35 } else if (_itemClass == kSecClassCertificate) {
10.1 --- a/MYKeychainItem.m Sun Jun 07 21:53:56 2009 -0700
10.2 +++ b/MYKeychainItem.m Tue Jun 09 23:58:03 2009 -0700
10.3 @@ -68,13 +68,6 @@
10.4 return $array((id)_itemRef);
10.5 }
10.6
10.7 -#if MYCRYPTO_USE_IPHONE_API
10.8 -- (CFDictionaryRef) asQuery {
10.9 - return (CFDictionaryRef) $dict( {(id)kSecClass, (id)kSecClassKey},//FIX
10.10 - {(id)kSecMatchItemList, self._itemList} );
10.11 -}
10.12 -#endif
10.13 -
10.14
10.15 - (MYKeychain*) keychain {
10.16 #if MYCRYPTO_USE_IPHONE_API
10.17 @@ -95,7 +88,7 @@
10.18 - (BOOL) removeFromKeychain {
10.19 OSStatus err;
10.20 #if MYCRYPTO_USE_IPHONE_API
10.21 - err = SecItemDelete(self.asQuery);
10.22 + err = SecItemDelete((CFDictionaryRef) $dict( {(id)kSecValueRef, (id)_itemRef} ));
10.23 #else
10.24 err = SecKeychainItemDelete((SecKeychainItemRef)_itemRef);
10.25 if (err==errSecInvalidItemRef)
10.26 @@ -127,8 +120,7 @@
10.27 + (NSData*) _getAttribute: (SecKeychainAttrType)attr ofItem: (MYKeychainItemRef)item {
10.28 NSData *value = nil;
10.29 #if MYCRYPTO_USE_IPHONE_API
10.30 - NSDictionary *info = $dict( {(id)kSecClass, (id)kSecClassKey},
10.31 - {(id)kSecMatchItemList, $array((id)item)},
10.32 + NSDictionary *info = $dict( {(id)kSecValueRef, (id)item},
10.33 {(id)kSecReturnAttributes, $true} );
10.34 CFDictionaryRef attrs;
10.35 if (!check(SecItemCopyMatching((CFDictionaryRef)info, (CFTypeRef*)&attrs), @"SecItemCopyMatching"))
10.36 @@ -182,9 +174,7 @@
10.37 {
10.38 #if MYCRYPTO_USE_IPHONE_API
10.39 id value = stringValue ?(id)stringValue :(id)[NSNull null];
10.40 - NSDictionary *query = $dict({(id)kSecClass, (id)kSecClassKey},
10.41 - {(id)kSecAttrKeyType, (id)attr},
10.42 - {(id)kSecMatchItemList, $array((id)item)});
10.43 + NSDictionary *query = $dict({(id)kSecValueRef, (id)item});
10.44 NSDictionary *attrs = $dict({(id)attr, value});
10.45 return check(SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attrs), @"SecItemUpdate");
10.46
11.1 --- a/MYPrivateKey.m Sun Jun 07 21:53:56 2009 -0700
11.2 +++ b/MYPrivateKey.m Tue Jun 09 23:58:03 2009 -0700
11.3 @@ -178,8 +178,16 @@
11.4 - (MYSHA1Digest*) _keyDigest {
11.5 if (_publicKey)
11.6 return _publicKey.publicKeyDigest;
11.7 - else
11.8 - return [MYSHA1Digest digestFromDigestData: [self _attribute: kSecAttrApplicationLabel]];
11.9 + else {
11.10 + NSData *digestData;
11.11 +#if MYCRYPTO_USE_IPHONE_API
11.12 + digestData = [self _attribute: kSecAttrApplicationLabel];
11.13 +#else
11.14 + digestData = [[self class] _getAttribute: kSecKeyLabel
11.15 + ofItem: (SecKeychainItemRef)self.keyRef];
11.16 +#endif
11.17 + return [MYSHA1Digest digestFromDigestData: digestData];
11.18 + }
11.19 }
11.20
11.21 - (MYSHA1Digest*) publicKeyDigest {
12.1 --- a/MYPublicKey.m Sun Jun 07 21:53:56 2009 -0700
12.2 +++ b/MYPublicKey.m Tue Jun 09 23:58:03 2009 -0700
12.3 @@ -29,7 +29,6 @@
12.4 return [self initWithKeyData: keyData];
12.5 }
12.6
12.7 -
12.8 - (void) dealloc
12.9 {
12.10 [_digest release];
12.11 @@ -48,10 +47,6 @@
12.12 - (SecExternalItemType) keyType {
12.13 return kSecAttrKeyTypeRSA;
12.14 }
12.15 -
12.16 -- (MYSHA1Digest*) _keyDigest {
12.17 - return (MYSHA1Digest*) [MYSHA1Digest digestFromDigestData: [self _attribute: kSecAttrApplicationLabel]];
12.18 -}
12.19 #endif
12.20
12.21 - (NSUInteger)hash {
13.1 Binary file Tests/generated.cer has changed
14.1 Binary file Tests/selfsigned_altered.cer has changed