Skip to content

Commit

Permalink
Try sending intermediate certificates where available (#16)
Browse files Browse the repository at this point in the history
  • Loading branch information
russellhancox authored Jul 29, 2019
1 parent 90e5f94 commit 1ac8e11
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 5 deletions.
2 changes: 1 addition & 1 deletion MOLAuthenticatingURLSession.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'MOLAuthenticatingURLSession'
s.version = '2.6'
s.version = '2.7'
s.platform = :osx
s.osx.deployment_target = '10.9'
s.license = { :type => 'Apache 2.0', :file => 'LICENSE' }
Expand Down
40 changes: 38 additions & 2 deletions Source/MOLAuthenticatingURLSession/MOLAuthenticatingURLSession.m
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ - (void)URLSession:(NSURLSession *)session
- (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
__block SecIdentityRef foundIdentity = NULL;

NSArray *allCerts;
if (self.clientCertFile) {
foundIdentity = [self identityFromFile:self.clientCertFile password:self.clientCertPassword];
} else {
Expand All @@ -214,7 +215,7 @@ - (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)
}, (CFTypeRef *)&cfResults);
NSArray *results = CFBridgingRelease(cfResults);

NSMutableArray *allCerts = [[MOLCertificate certificatesFromArray:results] mutableCopy];
allCerts = [MOLCertificate certificatesFromArray:results];

if (self.clientCertCommonName) {
foundIdentity = [self identityByFilteringArray:allCerts
Expand Down Expand Up @@ -255,9 +256,12 @@ - (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)
MOLCertificate *clientCert = [[MOLCertificate alloc] initWithSecCertificateRef:certificate];
if (certificate) CFRelease(certificate);
if (clientCert) [self log:@"Client Trust: %@", clientCert];

NSArray *intermediates = [self locateIntermediatesForCertificate:clientCert inArray:allCerts];

NSURLCredential *cred =
[NSURLCredential credentialWithIdentity:foundIdentity
certificates:nil
certificates:intermediates
persistence:NSURLCredentialPersistenceForSession];
if (foundIdentity) CFRelease(foundIdentity);
return cred;
Expand Down Expand Up @@ -409,6 +413,38 @@ - (SecIdentityRef)identityFromFile:(NSString *)file password:(NSString *)passwor
identities.firstObject[(__bridge NSString *)kSecImportItemIdentity]);
}

// For servers that require the intermediate certificate to be presented when
// using a client certificate, this method will attempt to locate those
// intermediates in the keychain. If the intermediate certificate is not in
// the keychain an empty array will be presented instead.
- (NSArray *)locateIntermediatesForCertificate:(MOLCertificate *)leafCert
inArray:(NSArray<MOLCertificate *> *)certs {
SecTrustRef t = NULL;
OSStatus res = SecTrustCreateWithCertificates(leafCert.certRef, NULL, &t);
if (res != errSecSuccess) {
NSString *errMsg = CFBridgingRelease(SecCopyErrorMessageString(res, NULL));
[self log:@"Failed to create trust for locating intermediate certs: %@", errMsg];
return nil;
}

// Evaluate the trust to create the chain, even though we don't
// use the result of the evaluation. The certificates seem to be available
// without calling this but the documentation is clear that
// SecTrustGetCertificateAtIndex shouldn't be called without calling
// SecTrustEvaluate first.
SecTrustResultType _; // unused
SecTrustEvaluate(t, &_);

NSMutableArray *intermediates = [NSMutableArray array];
CFIndex certCount = SecTrustGetCertificateCount(t);
for (int i = 1; i < certCount; ++i) {
[intermediates addObject:(id)SecTrustGetCertificateAtIndex(t, i)];
}
CFRelease(t);

return intermediates;
}

- (void)log:(NSString *)format, ... {
if (self.loggingBlock) {
va_list args;
Expand Down
4 changes: 2 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
git_repository(
name = "build_bazel_rules_apple",
remote = "https://github.com/bazelbuild/rules_apple.git",
tag = "0.6.0",
tag = "0.17.2",
)

load(
Expand All @@ -16,5 +16,5 @@ apple_rules_dependencies()
git_repository(
name = "MOLCertificate",
remote = "https://github.com/google/macops-molcertificate.git",
tag = "v2.0",
tag = "v2.1",
)

0 comments on commit 1ac8e11

Please sign in to comment.