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
Showing
11 changed files
with
126 additions
and
26 deletions
@@ -335,6 +335,7 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | @@ -335,6 +335,7 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | ||
335 | 335 | ||
336 | // If not nil and the URL scheme is https, CFNetwork configured to supply a client certificate | 336 | // If not nil and the URL scheme is https, CFNetwork configured to supply a client certificate |
337 | SecIdentityRef clientCertificateIdentity; | 337 | SecIdentityRef clientCertificateIdentity; |
338 | + NSArray *clientCertificates; | ||
338 | 339 | ||
339 | // Details on the proxy to use - you could set these yourself, but it's probably best to let ASIHTTPRequest detect the system proxy settings | 340 | // Details on the proxy to use - you could set these yourself, but it's probably best to let ASIHTTPRequest detect the system proxy settings |
340 | NSString *proxyHost; | 341 | NSString *proxyHost; |
@@ -741,7 +742,6 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | @@ -741,7 +742,6 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | ||
741 | // Hides the network activity spinner thing on iOS | 742 | // Hides the network activity spinner thing on iOS |
742 | + (void)hideNetworkActivityIndicator; | 743 | + (void)hideNetworkActivityIndicator; |
743 | 744 | ||
744 | - | ||
745 | #pragma mark miscellany | 745 | #pragma mark miscellany |
746 | 746 | ||
747 | // Used for generating Authorization header when using basic authentication when shouldPresentCredentialsBeforeChallenge is true | 747 | // Used for generating Authorization header when using basic authentication when shouldPresentCredentialsBeforeChallenge is true |
@@ -854,4 +854,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | @@ -854,4 +854,5 @@ extern unsigned long const ASIWWANBandwidthThrottleAmount; | ||
854 | @property (assign) ASICacheStoragePolicy cacheStoragePolicy; | 854 | @property (assign) ASICacheStoragePolicy cacheStoragePolicy; |
855 | @property (assign, readonly) BOOL didUseCachedResponse; | 855 | @property (assign, readonly) BOOL didUseCachedResponse; |
856 | @property (assign) NSTimeInterval secondsToCache; | 856 | @property (assign) NSTimeInterval secondsToCache; |
857 | +@property (retain) NSArray *clientCertificates; | ||
857 | @end | 858 | @end |
@@ -23,7 +23,7 @@ | @@ -23,7 +23,7 @@ | ||
23 | 23 | ||
24 | 24 | ||
25 | // Automatically set on build | 25 | // Automatically set on build |
26 | -NSString *ASIHTTPRequestVersion = @"v1.7-53 2010-08-18"; | 26 | +NSString *ASIHTTPRequestVersion = @"v1.7-50 2010-08-18"; |
27 | 27 | ||
28 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; | 28 | NSString* const NetworkRequestErrorDomain = @"ASIHTTPRequestErrorDomain"; |
29 | 29 | ||
@@ -318,6 +318,9 @@ static NSOperationQueue *sharedQueue = nil; | @@ -318,6 +318,9 @@ static NSOperationQueue *sharedQueue = nil; | ||
318 | if (request) { | 318 | if (request) { |
319 | CFRelease(request); | 319 | CFRelease(request); |
320 | } | 320 | } |
321 | + if (clientCertificateIdentity) { | ||
322 | + CFRelease(clientCertificateIdentity); | ||
323 | + } | ||
321 | [self cancelLoad]; | 324 | [self cancelLoad]; |
322 | [queue release]; | 325 | [queue release]; |
323 | [userInfo release]; | 326 | [userInfo release]; |
@@ -359,11 +362,6 @@ static NSOperationQueue *sharedQueue = nil; | @@ -359,11 +362,6 @@ static NSOperationQueue *sharedQueue = nil; | ||
359 | [responseStatusMessage release]; | 362 | [responseStatusMessage release]; |
360 | [connectionInfo release]; | 363 | [connectionInfo release]; |
361 | [requestID release]; | 364 | [requestID release]; |
362 | - | ||
363 | - if (clientCertificateIdentity) { | ||
364 | - CFRelease(clientCertificateIdentity); | ||
365 | - } | ||
366 | - | ||
367 | [super dealloc]; | 365 | [super dealloc]; |
368 | } | 366 | } |
369 | 367 | ||
@@ -946,29 +944,34 @@ static NSOperationQueue *sharedQueue = nil; | @@ -946,29 +944,34 @@ static NSOperationQueue *sharedQueue = nil; | ||
946 | // | 944 | // |
947 | // Handle SSL certificate settings | 945 | // Handle SSL certificate settings |
948 | // | 946 | // |
947 | + | ||
949 | if([[[[self url] scheme] lowercaseString] isEqualToString:@"https"]) { | 948 | if([[[[self url] scheme] lowercaseString] isEqualToString:@"https"]) { |
950 | - NSMutableDictionary *sslProperties = [[NSMutableDictionary alloc] initWithCapacity:1]; | 949 | + |
951 | - | 950 | + NSMutableDictionary *sslProperties = [NSMutableDictionary dictionaryWithCapacity:1]; |
951 | + | ||
952 | // Tell CFNetwork not to validate SSL certificates | 952 | // Tell CFNetwork not to validate SSL certificates |
953 | if (![self validatesSecureCertificate]) { | 953 | if (![self validatesSecureCertificate]) { |
954 | [sslProperties setObject:(NSString *)kCFBooleanFalse forKey:(NSString *)kCFStreamSSLValidatesCertificateChain]; | 954 | [sslProperties setObject:(NSString *)kCFBooleanFalse forKey:(NSString *)kCFStreamSSLValidatesCertificateChain]; |
955 | } | 955 | } |
956 | - | 956 | + |
957 | // Tell CFNetwork to use a client certificate | 957 | // Tell CFNetwork to use a client certificate |
958 | if (clientCertificateIdentity) { | 958 | if (clientCertificateIdentity) { |
959 | - CFArrayRef ca = CFArrayCreate(NULL, (const void **)&clientCertificateIdentity, 1, NULL); | 959 | + |
960 | - | 960 | + NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[clientCertificates count]+1]; |
961 | - [sslProperties setObject:(NSArray *)ca forKey:(NSString *)kCFStreamSSLCertificates]; | 961 | + |
962 | - | 962 | + // The first object in the array is our SecIdentityRef |
963 | - CFRelease(ca); | 963 | + [certificates addObject:(id)clientCertificateIdentity]; |
964 | + | ||
965 | + // If we've added any additional certificates, add them too | ||
966 | + for (id cert in clientCertificates) { | ||
967 | + [certificates addObject:cert]; | ||
968 | + } | ||
969 | + [sslProperties setObject:certificates forKey:(NSString *)kCFStreamSSLCertificates]; | ||
964 | } | 970 | } |
965 | - | 971 | + |
966 | CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertySSLSettings, sslProperties); | 972 | CFReadStreamSetProperty((CFReadStreamRef)[self readStream], kCFStreamPropertySSLSettings, sslProperties); |
967 | - | ||
968 | - [sslProperties release]; | ||
969 | } | 973 | } |
970 | - | 974 | + |
971 | - | ||
972 | 975 | ||
973 | 976 | ||
974 | // | 977 | // |
@@ -4086,8 +4089,6 @@ static NSOperationQueue *sharedQueue = nil; | @@ -4086,8 +4089,6 @@ static NSOperationQueue *sharedQueue = nil; | ||
4086 | CFRelease(source); | 4089 | CFRelease(source); |
4087 | } | 4090 | } |
4088 | 4091 | ||
4089 | - | ||
4090 | - | ||
4091 | #pragma mark miscellany | 4092 | #pragma mark miscellany |
4092 | 4093 | ||
4093 | // From: http://www.cocoadev.com/index.pl?BaseSixtyFour | 4094 | // From: http://www.cocoadev.com/index.pl?BaseSixtyFour |
@@ -4250,4 +4251,5 @@ static NSOperationQueue *sharedQueue = nil; | @@ -4250,4 +4251,5 @@ static NSOperationQueue *sharedQueue = nil; | ||
4250 | @synthesize cacheStoragePolicy; | 4251 | @synthesize cacheStoragePolicy; |
4251 | @synthesize didUseCachedResponse; | 4252 | @synthesize didUseCachedResponse; |
4252 | @synthesize secondsToCache; | 4253 | @synthesize secondsToCache; |
4254 | +@synthesize clientCertificates; | ||
4253 | @end | 4255 | @end |
@@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
6 | 6 | ||
7 | #import "ASICloudFilesRequest.h" | 7 | #import "ASICloudFilesRequest.h" |
8 | 8 | ||
9 | -#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) | 9 | +#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) |
10 | #import "ASINSXMLParserCompat.h" | 10 | #import "ASINSXMLParserCompat.h" |
11 | #endif | 11 | #endif |
12 | 12 |
@@ -6,7 +6,7 @@ | @@ -6,7 +6,7 @@ | ||
6 | 6 | ||
7 | #import "ASICloudFilesRequest.h" | 7 | #import "ASICloudFilesRequest.h" |
8 | 8 | ||
9 | -#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) | 9 | +#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) |
10 | #import "ASINSXMLParserCompat.h" | 10 | #import "ASINSXMLParserCompat.h" |
11 | #endif | 11 | #endif |
12 | 12 |
@@ -8,7 +8,7 @@ | @@ -8,7 +8,7 @@ | ||
8 | // | 8 | // |
9 | 9 | ||
10 | 10 | ||
11 | -#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED <= __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_4_0) | 11 | +#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_4_0) |
12 | @protocol NSXMLParserDelegate | 12 | @protocol NSXMLParserDelegate |
13 | 13 | ||
14 | @optional | 14 | @optional |
@@ -11,7 +11,7 @@ | @@ -11,7 +11,7 @@ | ||
11 | #import <Foundation/Foundation.h> | 11 | #import <Foundation/Foundation.h> |
12 | #import "ASIHTTPRequest.h" | 12 | #import "ASIHTTPRequest.h" |
13 | 13 | ||
14 | -#if (!TARGET_OS_IPHONE && MAC_OS_X_VERSION_MAX_ALLOWED < __MAC_10_6) || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) | 14 | +#if !TARGET_OS_IPHONE || (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MAX_ALLOWED < __IPHONE_4_0) |
15 | #import "ASINSXMLParserCompat.h" | 15 | #import "ASINSXMLParserCompat.h" |
16 | #endif | 16 | #endif |
17 | 17 |
Classes/Tests/ClientCertificateTests.h
0 → 100644
1 | +// | ||
2 | +// ClientCertificateTests.h | ||
3 | +// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest | ||
4 | +// | ||
5 | +// Created by Ben Copsey on 18/08/2010. | ||
6 | +// Copyright 2010 All-Seeing Interactive. All rights reserved. | ||
7 | +// | ||
8 | + | ||
9 | +// Currently, these tests only work on iOS - it looks like the method for parsing the PKCS12 file would need to be ported | ||
10 | + | ||
11 | +#import <Foundation/Foundation.h> | ||
12 | +#import <Security/Security.h> | ||
13 | +#import "ASITestCase.h" | ||
14 | + | ||
15 | +@interface ClientCertificateTests : ASITestCase { | ||
16 | + | ||
17 | +} | ||
18 | +- (void)testClientCertificate; | ||
19 | ++ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data; | ||
20 | + | ||
21 | +@end |
Classes/Tests/ClientCertificateTests.m
0 → 100644
1 | +// | ||
2 | +// ClientCertificateTests.m | ||
3 | +// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest | ||
4 | +// | ||
5 | +// Created by Ben Copsey on 18/08/2010. | ||
6 | +// Copyright 2010 All-Seeing Interactive. All rights reserved. | ||
7 | +// | ||
8 | + | ||
9 | +#import "ClientCertificateTests.h" | ||
10 | +#import "ASIHTTPRequest.h" | ||
11 | + | ||
12 | +@implementation ClientCertificateTests | ||
13 | + | ||
14 | +- (void)testClientCertificate | ||
15 | +{ | ||
16 | + // This test will fail the second time it is run, I presume the certificate is being cached somewhere | ||
17 | + | ||
18 | + // This url requires we present a client certificate to connect to it | ||
19 | + NSURL *url = [NSURL URLWithString:@"https://clientcertificate.allseeing-i.com:8080/ASIHTTPRequest/tests/first"]; | ||
20 | + | ||
21 | + // First, let's attempt to connect to the url without supplying a certificate | ||
22 | + ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; | ||
23 | + | ||
24 | + // We have to turn off validation for these tests, as the server has a self-signed certificate | ||
25 | + [request setValidatesSecureCertificate:NO]; | ||
26 | + [request startSynchronous]; | ||
27 | + | ||
28 | + GHAssertNotNil([request error],@"Request succeeded even though we presented no certificate, cannot proceed with test"); | ||
29 | + | ||
30 | + // Now, let's grab the certificate (included in the resources of the test app) | ||
31 | + SecIdentityRef identity = NULL; | ||
32 | + SecTrustRef trust = NULL; | ||
33 | + NSData *PKCS12Data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"]]; | ||
34 | + [ClientCertificateTests extractIdentity:&identity andTrust:&trust fromPKCS12Data:PKCS12Data]; | ||
35 | + | ||
36 | + request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:@"https://clientcertificate.allseeing-i.com:8080/ASIHTTPRequest/tests/first"]]; | ||
37 | + | ||
38 | + // In this case, we have no need to add extra certificates, just the one inside the indentity will be used | ||
39 | + [request setClientCertificateIdentity:identity]; | ||
40 | + [request setValidatesSecureCertificate:NO]; | ||
41 | + [request startSynchronous]; | ||
42 | + | ||
43 | + // Make sure the request got the correct content | ||
44 | + GHAssertNil([request error],@"Request failed with error %@",[request error]); | ||
45 | + BOOL success = [[request responseString] isEqualToString:@"This is the expected content for the first string"]; | ||
46 | + GHAssertTrue(success,@"Request failed to download the correct content"); | ||
47 | +} | ||
48 | + | ||
49 | +// Based on code from http://developer.apple.com/mac/library/documentation/Security/Conceptual/CertKeyTrustProgGuide/iPhone_Tasks/iPhone_Tasks.html | ||
50 | + | ||
51 | ++ (BOOL)extractIdentity:(SecIdentityRef *)outIdentity andTrust:(SecTrustRef*)outTrust fromPKCS12Data:(NSData *)inPKCS12Data | ||
52 | +{ | ||
53 | + OSStatus securityError = errSecSuccess; | ||
54 | + | ||
55 | + NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObject:@"" forKey:(id)kSecImportExportPassphrase]; | ||
56 | + | ||
57 | + CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL); | ||
58 | + securityError = SecPKCS12Import((CFDataRef)inPKCS12Data,(CFDictionaryRef)optionsDictionary,&items); | ||
59 | + | ||
60 | + if (securityError == 0) { | ||
61 | + CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex (items, 0); | ||
62 | + const void *tempIdentity = NULL; | ||
63 | + tempIdentity = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemIdentity); | ||
64 | + *outIdentity = (SecIdentityRef)tempIdentity; | ||
65 | + const void *tempTrust = NULL; | ||
66 | + tempTrust = CFDictionaryGetValue (myIdentityAndTrust, kSecImportItemTrust); | ||
67 | + *outTrust = (SecTrustRef)tempTrust; | ||
68 | + } else { | ||
69 | + NSLog(@"Failed with error code %i",securityError); | ||
70 | + return NO; | ||
71 | + } | ||
72 | + return YES; | ||
73 | +} | ||
74 | + | ||
75 | + | ||
76 | +@end |
This diff was suppressed by a .gitattributes entry.
iPhone Sample/Resources/client.p12
0 → 100644
No preview for this file type
This diff was suppressed by a .gitattributes entry.
-
Please register or login to post a comment