mirror of
https://github.com/datatheorem/TrustKit.git
synced 2026-06-16 12:54:30 +00:00
412 lines
25 KiB
Objective-C
412 lines
25 KiB
Objective-C
/*
|
|
|
|
TSKPinConfigurationTests.m
|
|
TrustKit
|
|
|
|
Copyright 2015 The TrustKit Project Authors
|
|
Licensed under the MIT license, see associated LICENSE file for terms.
|
|
See AUTHORS file for the list of project authors.
|
|
|
|
*/
|
|
|
|
#import <XCTest/XCTest.h>
|
|
|
|
#import "../TrustKit/public/TrustKit.h"
|
|
#import "../TrustKit/public/TSKTrustKitConfig.h"
|
|
#import "../TrustKit/Pinning/ssl_pin_verifier.h"
|
|
#import "../TrustKit/parse_configuration.h"
|
|
#import "../TrustKit/configuration_utils.h"
|
|
#import "TSKCertificateUtils.h"
|
|
|
|
@interface TSKPinConfigurationTests : XCTestCase
|
|
@end
|
|
|
|
@implementation TSKPinConfigurationTests
|
|
|
|
- (void)setUp
|
|
{
|
|
[super setUp];
|
|
}
|
|
|
|
- (void)tearDown
|
|
{
|
|
[super tearDown];
|
|
}
|
|
|
|
|
|
// Pin to only one key and ensure it fails; TrustKit requires at least two pins (which should include a backup pin)
|
|
- (void)testPinOnePublicKey
|
|
{
|
|
XCTAssertThrows(parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"www.good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
]}}}),
|
|
@"Configuration with one pin only must be rejected");
|
|
}
|
|
|
|
|
|
- (void)testDisablePinningForSubdomainAndNoPublicKey
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
],
|
|
kTSKIncludeSubdomains: @YES},
|
|
@"unsecured.good.com": @{
|
|
// When using this option, TrustKit should accept an empty policy for the domain
|
|
kTSKExcludeSubdomainFromParentPolicy: @YES
|
|
}
|
|
}
|
|
});
|
|
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"unsecured.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"unsecured.good.com", @"Did not receive a configuration for pinned subdomain");
|
|
}
|
|
|
|
- (void)testExplicitNotDisablePinningForSubdomainAdditionalDomainKeys
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
],
|
|
kTSKIncludeSubdomains: @YES},
|
|
@"unsecured.good.com": @{
|
|
// When using this option, TrustKit should allow/require a policy for the subdomain
|
|
kTSKExcludeSubdomainFromParentPolicy: @NO,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
],
|
|
}
|
|
}
|
|
});
|
|
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"unsecured.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"unsecured.good.com", @"Did not receive a configuration for pinned subdomain");
|
|
}
|
|
|
|
- (void)testDisablePinningForSubdomainWithoutParentAndNoPublicKey
|
|
{
|
|
XCTAssertThrows(parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
],
|
|
// IncludeSubdomains set to NO so the configuration here is invalid
|
|
kTSKIncludeSubdomains: @NO},
|
|
@"unsecured.good.com": @{
|
|
kTSKExcludeSubdomainFromParentPolicy: @YES
|
|
}
|
|
}
|
|
}),
|
|
@"Configuration with kTSKExcludeSubdomainFromParentPolicy must have a parent");
|
|
}
|
|
|
|
|
|
- (void)testDisablePinningForSubdomainAdditionalDomainKeys
|
|
{
|
|
XCTAssertThrows(parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
],
|
|
kTSKIncludeSubdomains: @YES},
|
|
@"unsecured.good.com": @{
|
|
// When using this option, TrustKit should reject additional keys for the domain
|
|
kTSKExcludeSubdomainFromParentPolicy: @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
],
|
|
}
|
|
}
|
|
}),
|
|
@"Configuration with kTSKExcludeSubdomainFromParentPolicy must reject additional domain keys");
|
|
}
|
|
|
|
- (void)testNokTSKSwizzleNetworkDelegates
|
|
{
|
|
XCTAssertThrows(parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"www.good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
]}}}),
|
|
@"Configuration that does not specify kTSKSwizzleNetworkDelegates must be rejected");
|
|
}
|
|
|
|
|
|
- (void)testGetConfigurationPinningEnabled
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"www.good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"www.good.com", @"Did not receive a configuration for a pinned domain");
|
|
|
|
// Validate the content of the config
|
|
NSDictionary *serverConfig = trustKitConfig[kTSKPinnedDomains][serverConfigKey];
|
|
XCTAssertNil(serverConfig[kTSKExpirationDate]);
|
|
XCTAssertEqual([serverConfig[kTSKPublicKeyHashes] count], (unsigned long) 2);
|
|
}
|
|
|
|
|
|
- (void)testGetConfigurationPinningEnabledWithExpirationDate
|
|
{
|
|
NSString *expirationDateStr = @"2015-01-01";
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"www.good.com" : @{
|
|
kTSKExpirationDate: expirationDateStr,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"www.good.com", @"Did not receive a configuration for a pinned domain");
|
|
|
|
// Validate the content of the config
|
|
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
|
|
dateFormat.dateFormat = @"yyyy-MM-dd";
|
|
dateFormat.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
|
|
NSDate *expirationDate = [dateFormat dateFromString:expirationDateStr];
|
|
|
|
NSDictionary *serverConfig = trustKitConfig[kTSKPinnedDomains][serverConfigKey];
|
|
XCTAssertEqualObjects(expirationDate, serverConfig[kTSKExpirationDate]);
|
|
XCTAssertEqual([serverConfig[kTSKPublicKeyHashes] count], (unsigned long)2);
|
|
}
|
|
|
|
|
|
- (void)testGetConfigurationPinningDisabled
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Ensure www.datatheorem.com gets no configuration
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.datatheorem.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertNil(serverConfigKey, @"Received a configuration a non-pinned domain");
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabled
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Ensure www.good.com gets the configuration set for good.com as includeSubdomains is enabled
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"good.com", @"IncludeSubdomains did not work");
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabledSameDomain
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{@"good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Ensure good.com gets the configuration set for good.com as includeSubdomains is enabled
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"good.com", @"IncludeSubdomains did not work");
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabledSubSubDomain
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains :
|
|
@{@"www.good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"sub.www.good.com.www.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"www.good.com", @"IncludeSubdomains did not work");
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabledNotSubdomain
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains :
|
|
@{@"good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Corner case to ensure two different domains with similar strings don't get returned as subdomains
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"good.com.otherdomaingood.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertNil(serverConfigKey);
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabledNotSubdomainDifferentTld
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains :
|
|
@{@"good.net" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Corner case to ensure two different domains (because different TLD) with similar strings don't get returned as subdomains
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"test.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertNil(serverConfigKey);
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabledForSuffix
|
|
{
|
|
XCTAssertThrows(parseTrustKitConfiguration(@{kTSKSwizzleNetworkDelegates: @NO,
|
|
kTSKPinnedDomains :
|
|
@{@"com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}}),
|
|
@"Configuration that pins *.com must be rejected");
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsDisabled
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains :
|
|
@{@"good.com" : @{
|
|
kTSKIncludeSubdomains : @NO,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Ensure www.good.com does not get the configuration set for good.com
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertNil(serverConfigKey, @"IncludeSubdomains did not work");
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabledAndSpecificConfiguration
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains :
|
|
@{@"good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]},
|
|
@"www.good.com": @{
|
|
kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Ensure the configuration specific to www.good.com takes precedence over the more general config for good.com
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"www.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"www.good.com",
|
|
@"IncludeSubdomains took precedence over a more specialized configuration");
|
|
}
|
|
|
|
|
|
- (void)testIncludeSubdomainsEnabledAndOverlap
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains :
|
|
@{@"good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]},
|
|
@"www.good.com": @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"iQMk4onrJJz/nwW1wCUR0Ycsh3omhbM+PqMEwNof/K0=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Ensure the configuration of www.good.com with a longer match takes precedence over the more general config for good.com
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"foo.www.good.com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertEqualObjects(serverConfigKey, @"www.good.com",
|
|
@"Overlapping configurations with IncludeSubdomains did not use the most specific (longest) matching configuration");
|
|
}
|
|
|
|
|
|
- (void)testNoPinnedDomains
|
|
{
|
|
XCTAssertThrows(parseTrustKitConfiguration(@{kTSKSwizzleNetworkDelegates : @YES}),
|
|
@"Configuration with no pinned domains must be rejected");
|
|
}
|
|
|
|
|
|
- (void)testGlobalSettings
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains :
|
|
@{@"good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}});
|
|
|
|
// Ensure the kTSKSwizzleNetworkDelegates setting was saved
|
|
XCTAssertFalse([trustKitConfig[kTSKSwizzleNetworkDelegates] boolValue],
|
|
@"kTSKSwizzleNetworkDelegates was not saved in the configuration");
|
|
}
|
|
|
|
|
|
- (void)testSwizzleNetworkDelegatesInLocalInstance
|
|
{
|
|
NSDictionary *trustKitConfig;
|
|
// Swizzling can only be enabled in the shared instance
|
|
trustKitConfig = @{kTSKSwizzleNetworkDelegates: @YES,
|
|
kTSKPinnedDomains :
|
|
@{@"good.com" : @{
|
|
kTSKIncludeSubdomains : @YES,
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" // Fake key
|
|
]}}};
|
|
|
|
|
|
XCTAssertThrows([[TrustKit alloc] initWithConfiguration:trustKitConfig]);
|
|
}
|
|
|
|
|
|
- (void)testDomainTldAndParentFromServerConfigDoesNotCrash
|
|
{
|
|
// For https://github.com/datatheorem/TrustKit/issues/210
|
|
// Given a TrustKit config for a domain
|
|
NSDictionary *trustKitConfig;
|
|
trustKitConfig = parseTrustKitConfiguration(@{kTSKPinnedDomains : @{
|
|
@"good.com" : @{
|
|
kTSKPublicKeyHashes : @[@"TQEtdMbmwFgYUifM4LDF+xgEtd0z69mPGmkp014d6ZY=",
|
|
@"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
|
|
],
|
|
kTSKIncludeSubdomains: @YES},
|
|
}
|
|
});
|
|
|
|
// When trying to connect to an invalid domain that is a TLD and also a parent domain of the configured domain
|
|
// TrustKit does not crash and does not return the subdomain's configuration
|
|
NSString *serverConfigKey = getPinningConfigurationKeyForDomain(@"com", trustKitConfig[kTSKPinnedDomains]);
|
|
XCTAssertNil(serverConfigKey, @"IncludeSubdomains did not work");
|
|
}
|
|
|
|
@end
|