From 37c8b3f7c00f2d30d941fcb5d93308aefad37662 Mon Sep 17 00:00:00 2001 From: Ewan Mellor Date: Wed, 17 Jul 2013 00:52:24 -0700 Subject: [PATCH] Added MKNetworkOperation.serverTrustDelegate. If set, this delegate will be called whenever a server presents an SSL certificate that is not immediately trusted. The delegate can then make the trust decision (e.g. by asking the user). The delegate must implement the new MKServerTrustDelegate protocol. It has one method, handleServerCertificate. --- MKNetworkKit/MKNetworkOperation.h | 39 +++++++++++++++++++++++++++++++ MKNetworkKit/MKNetworkOperation.m | 7 ++++++ 2 files changed, 46 insertions(+) diff --git a/MKNetworkKit/MKNetworkOperation.h b/MKNetworkKit/MKNetworkOperation.h index 3aad141..355c249 100644 --- a/MKNetworkKit/MKNetworkOperation.h +++ b/MKNetworkKit/MKNetworkOperation.h @@ -54,6 +54,36 @@ typedef enum { MKNKPostDataEncodingTypePlist, MKNKPostDataEncodingTypeCustom } MKNKPostDataEncodingType; + + +@class NSURLAuthenticationChallenge; +@protocol MKServerTrustDelegate + +@required + +/*! + * @abstract This function is called when a server presents an SSL certificate and the certificate is not + * immediately trusted. + * + * @discussion + * This gives you an opportunity to present the certificate to the user for a decision, or however else you + * would like to make the trust decision. + * + * You should call either [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge] or + * [challenge.sender useCredential:[NSURLCredential credentialForTrust:trustRef] forAuthenticationChallenge:challenge] + * when the decision is made. + * + * SecTrustEvaluate has already been called on the given trustRef. + * + * @param trustRef The SecTrustRef object for this challenge (i.e. challenge.protectionSpace.serverTrust). + * @param trustResult One of the valid SecTrustResultType values, except for kSecTrustResultProceed and + * kSecTrustResultUnspecified. This is the result from SecTrustEvaluate(trustRef). + */ +-(void)handleServerCertificate:(MKNetworkOperation*)op challenge:(NSURLAuthenticationChallenge*)challenge trustRef:(SecTrustRef)trustRef trustResult:(SecTrustResultType)trustResult; + +@end + + /*! @header MKNetworkOperation.h @abstract Represents a single unique network operation. @@ -241,6 +271,15 @@ typedef enum { */ @property (nonatomic, assign) BOOL shouldContinueWithInvalidCertificate; +/*! + * @abstract A delegate used when a server presents an SSL certificate and the certificate is not immediately trusted. + * + * @discussion + * See MKServerTrustDelegate for more details. self.shouldContinueWithInvalidCertificate takes precedence over serverTrustDelegate. + * If this is nil, then any invalid or untrusted certificate is rejected. + */ +@property (nonatomic, weak) id serverTrustDelegate; + /*! * @abstract Boolean variable that states whether the request should automatically include an Accept-Language header. * @property shouldSendAcceptLanguageHeader diff --git a/MKNetworkKit/MKNetworkOperation.m b/MKNetworkKit/MKNetworkOperation.m index 5708193..074d2ca 100644 --- a/MKNetworkKit/MKNetworkOperation.m +++ b/MKNetworkKit/MKNetworkOperation.m @@ -1146,6 +1146,10 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio // Cert not trusted, but user is OK with that DLog(@"Certificate is not trusted, but self.shouldContinueWithInvalidCertificate is YES"); [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; + } else if (self.serverTrustDelegate != nil) { + + DLog(@"Certificate is not trusted, calling self.serverTrustDelegate to proceed."); + [self.serverTrustDelegate handleServerCertificate:self challenge:challenge trustRef:self.serverTrust trustResult:result]; } else { DLog(@"Certificate is not trusted, continuing without credentials. Might result in 401 Unauthorized"); @@ -1158,6 +1162,9 @@ - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticatio if(self.shouldContinueWithInvalidCertificate) { DLog(@"Certificate is invalid, but self.shouldContinueWithInvalidCertificate is YES"); [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; + } else if (self.serverTrustDelegate != nil) { + DLog(@"Certificate is invalid, calling self.serverTrustDelegate to proceed."); + [self.serverTrustDelegate handleServerCertificate:self challenge:challenge trustRef:self.serverTrust trustResult:result]; } else { DLog(@"Certificate is invalid, continuing without credentials. Might result in 401 Unauthorized"); [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];