Ben Copsey

Allow adding extra client certificates via the clientCertificates array

Added a test for client certificates (iOS only)
Attempt to fix, YET AGAIN, building for 10.6 and that stupid NSXMLParserDelegate
... ... @@ -335,6 +335,7 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
// If not nil and the URL scheme is https, CFNetwork configured to supply a client certificate
SecIdentityRef clientCertificateIdentity;
NSArray *clientCertificates;
// Details on the proxy to use - you could set these yourself, but it's probably best to let ASIHTTPRequest detect the system proxy settings
NSString *proxyHost;
... ... @@ -741,7 +742,6 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
// Hides the network activity spinner thing on iOS
+ (void)hideNetworkActivityIndicator;
#pragma mark miscellany
// Used for generating Authorization header when using basic authentication when shouldPresentCredentialsBeforeChallenge is true
... ... @@ -854,4 +854,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount;
@property (assign) ASICacheStoragePolicy cacheStoragePolicy;
@property (assign, readonly) BOOL didUseCachedResponse;
@property (assign) NSTimeInterval secondsToCache;
@property (retain) NSArray *clientCertificates;
@end
... ...
... ... @@ -23,7 +23,7 @@
// Automatically set on build
NSString *ASIHTTPRequestVersion = @"v1.7-53 2010-08-18";
NSString *ASIHTTPRequestVersion = @"v1.7-50 2010-08-18";
NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain";
... ... @@ -318,6 +318,9 @@ static NSOperationQueue *sharedQueue = nil;
if (request) {
CFRelease(request);
}
if (clientCertificateIdentity) {
CFRelease(clientCertificateIdentity);
}
[self cancelLoad];
[queue release];
[userInfo release];
... ... @@ -359,11 +362,6 @@ static NSOperationQueue *sharedQueue = nil;
[responseStatusMessage release];
[connectionInfo release];
[requestID release];
if (clientCertificateIdentity) {
CFRelease(clientCertificateIdentity);
}
[super dealloc];
}
... ... @@ -946,29 +944,34 @@ static NSOperationQueue *sharedQueue = nil;
//
// Handle SSL certificate settings
//
if([[[[self url] scheme] lowercaseString] isEqualToString:@"https"]) {
NSMutableDictionary *sslProperties = [[NSMutableDictionary alloc] initWithCapacity:1];
NSMutableDictionary *sslProperties = [NSMutableDictionary dictionaryWithCapacity:1];
// Tell CFNetwork not to validate SSL certificates
if (![self validatesSecureCertificate]) {
[sslProperties setObject:(NSString *)kCFBooleanFalse forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
}
// Tell CFNetwork to use a client certificate
if (clientCertificateIdentity) {
CFArrayRef ca = CFArrayCreate(NULL, (const void **)&clientCertificateIdentity, 1, NULL);
[sslProperties setObject:(NSArray *)ca forKey:(NSString *)kCFStreamSSLCertificates];
CFRelease(ca);
NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[clientCertificates count]+1];
// The first object in the array is our SecIdentityRef
[certificates addObject:(id)clientCertificateIdentity];
// If we've added any additional certificates, add them too
for (id cert in clientCertificates) {
[certificates addObject:cert];
}
[sslProperties setObject:certificates forKey:(NSString *)kCFStreamSSLCertificates];
}
CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertySSLSettings, sslProperties);
[sslProperties release];
}
//
... ... @@ -4086,8 +4089,6 @@ static NSOperationQueue *sharedQueue = nil;
CFRelease(source);
}
#pragma mark miscellany
// From: http://www.cocoadev.com/index.pl?BaseSixtyFour
... ... @@ -4250,4 +4251,5 @@ static NSOperationQueue *sharedQueue = nil;
@synthesize cacheStoragePolicy;
@synthesize didUseCachedResponse;
@synthesize secondsToCache;
@synthesize clientCertificates;
@end
... ...
... ... @@ -6,7 +6,7 @@
#import "ASICloudFilesRequest.h"
#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
#import "ASINSXMLParserCompat.h"
#endif
... ...
... ... @@ -6,7 +6,7 @@
#import "ASICloudFilesRequest.h"
#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
#import "ASINSXMLParserCompat.h"
#endif
... ...
... ... @@ -8,7 +8,7 @@
//
#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED <= __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_4_0)
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_4_0)
@protocol NSXMLParserDelegate
@optional
... ...
... ... @@ -11,7 +11,7 @@
#import <Foundation/Foundation.h>
#import "ASIHTTPRequest.h"
#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0)
#import "ASINSXMLParserCompat.h"
#endif
... ...
//
// ClientCertificateTests.h
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
//
// Created by Ben Copsey on 18/08/2010.
// Copyright 2010 All-Seeing Interactive. All rights reserved.
//
// Currently, these tests only work on iOS - it looks like the method for parsing the PKCS12 file would need to be ported
#import <Foundation/Foundation.h>
#import <Security/Security.h>
#import "ASITestCase.h"
@interface ClientCertificateTests : ASITestCase {
}
- (void)testClientCertificate;
+ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data;
@end
... ...
//
// ClientCertificateTests.m
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
//
// Created by Ben Copsey on 18/08/2010.
// Copyright 2010 All-Seeing Interactive. All rights reserved.
//
#import "ClientCertificateTests.h"
#import "ASIHTTPRequest.h"
@implementation ClientCertificateTests
- (void)testClientCertificate
{
// This test will fail the second time it is run, I presume the certificate is being cached somewhere
// This url requires we present a client certificate to connect to it
NSURL *url = [NSURL URLWithString:@"https://clientcertificate.allseeing-i.com:8080/ASIHTTPRequest/tests/first"];
// First, let's attempt to connect to the url without supplying a certificate
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
// We have to turn off validation for these tests, as the server has a self-signed certificate
[request setValidatesSecureCertificate:NO];
[request startSynchronous];
GHAssertNotNil([request error],@"Request succeeded even though we presented no certificate, cannot proceed with test");
// Now, let's grab the certificate (included in the resources of the test app)
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]];
[ClientCertificateTests extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"https://clientcertificate.allseeing-i.com:8080/ASIHTTPRequest/tests/first"]];
// In this case, we have no need to add extra certificates, just the one inside the indentity will be used
[request setClientCertificateIdentity:identity];
[request setValidatesSecureCertificate:NO];
[request startSynchronous];
// Make sure the request got the correct content
GHAssertNil([request error],@"Request failed with error %@",[request error]);
BOOL success = [[request responseString] isEqualToString:@"This is the expected content for the first string"];
GHAssertTrue(success,@"Request failed to download the correct content");
}
// Based on code from http://developer.apple.com/mac/library/documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html
+ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data
{
OSStatus securityError = errSecSuccess;
NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"" forKey:(id)kSecImportExportPassphrase];
CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items);
if (securityError == 0) {
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0);
const void *tempIdentity = NULL;
tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity);
*outIdentity = (SecIdentityRef)tempIdentity;
const void *tempTrust = NULL;
tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust);
*outTrust = (SecTrustRef)tempTrust;
} else {
NSLog(@"Failed with error code %i",securityError);
return NO;
}
return YES;
}
@end
... ...
This diff was suppressed by a .gitattributes entry.
No preview for this file type
This diff was suppressed by a .gitattributes entry.