// // Copyright 2017 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only // #import "OWSHTTPSecurityPolicy.h" #import NS_ASSUME_NONNULL_BEGIN @implementation OWSHTTPSecurityPolicy + (instancetype)sharedPolicy { static OWSHTTPSecurityPolicy *httpSecurityPolicy = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ httpSecurityPolicy = [[self alloc] initWithPinnedCertificates:[NSSet setWithArray:@[ [self certificateDataForService:@"signal-messenger"] ]]]; }); return httpSecurityPolicy; } + (instancetype)systemDefault { return [[self alloc] initWithPinnedCertificates:[NSSet set]]; } - (instancetype)initWithPinnedCertificates:(NSSet *)certificates { self = [super init]; if (self) { _pinnedCertificates = [certificates copy]; } return self; } + (NSData *)dataFromCertificateFileForService:(NSString *)service { NSBundle *bundle = [NSBundle bundleForClass:self.class]; NSString *path = [bundle pathForResource:service ofType:@"cer"]; if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { OWSFail(@"Missing signing certificate for service %@", service); } NSData *data = [NSData dataWithContentsOfFile:path]; OWSAssert(data.length > 0); return data; } + (NSData *)certificateDataForService:(NSString *)service { SecCertificateRef certRef = [self newCertificateForService:service]; NSData *result = (__bridge_transfer NSData *)SecCertificateCopyData(certRef); CFRelease(certRef); return result; } + (SecCertificateRef)newCertificateForService:(NSString *)service CF_RETURNS_RETAINED { NSData *certificateData = [self dataFromCertificateFileForService:service]; SecCertificateRef certRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certificateData)); OWSAssert(certRef); return certRef; } - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust forDomain:(nullable NSString *)domain { NSMutableArray *policies = [NSMutableArray array]; [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; if (SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies) != errSecSuccess) { OWSLogError(@"The trust policy couldn't be set."); return NO; } if ([self.pinnedCertificates count] > 0) { NSMutableArray *pinnedCertificates = [NSMutableArray array]; for (NSData *certificateData in self.pinnedCertificates) { [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData( NULL, (__bridge CFDataRef)certificateData)]; } if (SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates) != errSecSuccess) { OWSLogError(@"The anchor certificates couldn't be set."); return NO; } } else { // Use SecTrust's default set of anchor certificates. } return AFServerTrustIsValid(serverTrust); } static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) { BOOL isValid = NO; SecTrustResultType result; __Require_Quiet(SecTrustEvaluateWithError(serverTrust, nil), _out); // Assert in debug if SecTrustGetTrustResult() somehow fails after // SecTrustEvaluateWithError() succeeds. __Require_noErr(SecTrustGetTrustResult(serverTrust, &result), _out); isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); _out: return isValid; } @end NS_ASSUME_NONNULL_END