mirror of
https://github.com/google/santa.git
synced 2026-04-24 03:00:12 -04:00
added support for using custom pkcs#12 file with password
This commit is contained in:
@@ -46,6 +46,13 @@
|
||||
|
||||
# pragma mark Client Auth Settings
|
||||
|
||||
/// If set, this contains the location of a pkcs#12 certificate to be used for
|
||||
/// sync authentication.
|
||||
@property(readonly) NSString *syncClientAuthCertificateFile;
|
||||
|
||||
/// Contains the password for the pkcs#12 certificate.
|
||||
@property(readonly) NSString *syncClientAuthCertificatePassword;
|
||||
|
||||
/// If set, this is the Common Name of a certificate in the System keychain to be used for
|
||||
/// sync authentication. The corresponding private key must also be in the keychain.
|
||||
@property(readonly) NSString *syncClientAuthCertificateCn;
|
||||
|
||||
@@ -27,6 +27,8 @@ static NSString * const kConfigFilePath = @"/var/db/santa/config.plist";
|
||||
|
||||
/// The keys in the config file
|
||||
static NSString * const kSyncBaseURLKey = @"SyncBaseURL";
|
||||
static NSString * const kClientAuthCertificateFileKey = @"ClientAuthCertificateFile";
|
||||
static NSString * const kClientAuthCertificatePasswordKey = @"ClientAuthCertificatePassword";
|
||||
static NSString * const kClientAuthCertificateCNKey = @"ClientAuthCertificateCN";
|
||||
static NSString * const kClientAuthCertificateIssuerKey = @"ClientAuthCertificateIssuerCN";
|
||||
static NSString * const kServerAuthRootsDataKey = @"ServerAuthRootsData";
|
||||
@@ -68,6 +70,14 @@ static NSString * const kMachineIDPlistKeyKey = @"MachineIDKey";
|
||||
return [NSURL URLWithString:self.configData[kSyncBaseURLKey]];
|
||||
}
|
||||
|
||||
- (NSString *)syncClientAuthCertificateFile {
|
||||
return self.configData[kClientAuthCertificateFileKey];
|
||||
}
|
||||
|
||||
- (NSString *)syncClientAuthCertificatePassword {
|
||||
return self.configData[kClientAuthCertificatePasswordKey];
|
||||
}
|
||||
|
||||
- (NSString *)syncClientAuthCertificateCn {
|
||||
return self.configData[kClientAuthCertificateCNKey];
|
||||
}
|
||||
|
||||
@@ -31,6 +31,14 @@
|
||||
/// certificate chain. This will override the trusted roots in the System Roots.
|
||||
@property(nonatomic) NSData *serverRootsPemData;
|
||||
|
||||
/// If set and client certificate authentication is needed, the pkcs#12 file will be
|
||||
/// loaded
|
||||
@property(nonatomic) NSString *clientCertFile;
|
||||
|
||||
/// If set and client certificate authentication is needed, the password being used for
|
||||
/// loading the clientCertFile
|
||||
@property(nonatomic) NSString *clientCertPassword;
|
||||
|
||||
/// If set and client certificate authentication is needed, will search the keychain for a
|
||||
/// certificate matching this common name and use that for authentication
|
||||
/// @note: Not case sensitive
|
||||
|
||||
@@ -112,31 +112,58 @@
|
||||
/// Handles the process of locating a valid client certificate for authentication.
|
||||
/// Operates in one of three modes, depending on the configuration in config.plist
|
||||
///
|
||||
/// Mode 1: if syncClientAuthCertificateCn is set, look for an identity in the keychain with a
|
||||
/// Mode 1: if syncClientAuthCertificate is set, use the identity in the pkcs file
|
||||
/// Mode 2: if syncClientAuthCertificateCn is set, look for an identity in the keychain with a
|
||||
/// matching common name and return it.
|
||||
/// Mode 2: if syncClientAuthCertificateIssuer is set, look for an identity in the keychain with a
|
||||
/// Mode 3: if syncClientAuthCertificateIssuer is set, look for an identity in the keychain with a
|
||||
/// matching issuer common name and return it.
|
||||
/// Mode 3: use the list of issuer details sent down by the server to find an identity in the
|
||||
/// Mode 4: use the list of issuer details sent down by the server to find an identity in the
|
||||
/// keychain.
|
||||
///
|
||||
/// If a valid identity cannot be found, returns nil.
|
||||
- (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
|
||||
__block OSStatus err = errSecSuccess;
|
||||
__block SecIdentityRef _foundIdentity;
|
||||
|
||||
if (self.clientCertFile) {
|
||||
NSError *error = nil;
|
||||
|
||||
NSData *data = [NSData dataWithContentsOfFile:self.clientCertFile options:0 error:&error];
|
||||
if (error) {
|
||||
LOGE(@"Couldn't open client certificate %@ : %@", self.clientCertFile, [error localizedDescription]);
|
||||
return (nil);
|
||||
}
|
||||
|
||||
CFDataRef inPKCS12Data = (__bridge CFDataRef)data;
|
||||
|
||||
SecTrustRef trust = nil;
|
||||
err = extractIdentityAndTrust(inPKCS12Data, self.clientCertPassword, &_foundIdentity, &trust);
|
||||
if (err != errSecSuccess) {
|
||||
LOGE(@"Couldn't load client certificate %@ : %d", self.clientCertFile, err);
|
||||
return (nil);
|
||||
}
|
||||
|
||||
CFRetain(_foundIdentity);
|
||||
|
||||
return [NSURLCredential credentialWithIdentity:_foundIdentity
|
||||
certificates:nil
|
||||
persistence:NSURLCredentialPersistenceForSession];
|
||||
}
|
||||
|
||||
CFArrayRef cfIdentities = NULL;
|
||||
err = SecItemCopyMatching((__bridge CFDictionaryRef)@{
|
||||
(id)kSecClass : (id)kSecClassIdentity,
|
||||
(id)kSecReturnRef : @YES,
|
||||
(id)kSecMatchLimit : (id)kSecMatchLimitAll }, (CFTypeRef *)&cfIdentities);
|
||||
|
||||
(id)kSecClass : (id)kSecClassIdentity,
|
||||
(id)kSecReturnRef : @YES,
|
||||
(id)kSecMatchLimit : (id)kSecMatchLimitAll }, (CFTypeRef *)&cfIdentities);
|
||||
|
||||
if (err != noErr) {
|
||||
LOGD(@"Client Trust: Failed to load client identities, SecItemCopyMatching returned: %d",
|
||||
(int)err);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSArray *identities = CFBridgingRelease(cfIdentities);
|
||||
|
||||
__block SecIdentityRef _foundIdentity;
|
||||
|
||||
// Manually iterate through available identities to find one with an allowed issuer.
|
||||
[identities enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
||||
SecIdentityRef identityRef = (__bridge SecIdentityRef)obj;
|
||||
@@ -197,6 +224,24 @@
|
||||
persistence:NSURLCredentialPersistenceForSession];
|
||||
}
|
||||
|
||||
OSStatus extractIdentityAndTrust(CFDataRef inP12data, NSString* password, SecIdentityRef *identity, SecTrustRef *trust)
|
||||
{
|
||||
NSDictionary *options = (password ? @{(__bridge id)kSecImportExportPassphrase: password} : @{});
|
||||
|
||||
CFArrayRef items = nil;
|
||||
|
||||
OSStatus err = SecPKCS12Import(inP12data, (__bridge CFDictionaryRef) options, &items);
|
||||
|
||||
if (err == errSecSuccess) {
|
||||
CFDictionaryRef myIdentityAndTrust = CFArrayGetValueAtIndex(items, 0);
|
||||
*identity = (SecIdentityRef) CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemIdentity);
|
||||
*trust = (SecTrustRef)CFDictionaryGetValue(myIdentityAndTrust, kSecImportItemTrust);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/// Handles the process of evaluating the server's certificate chain.
|
||||
/// Operates in one of three modes, depending on the configuration in config.plist
|
||||
///
|
||||
|
||||
@@ -91,7 +91,10 @@ REGISTER_COMMAND_NAME(@"sync");
|
||||
}
|
||||
|
||||
// Configure client auth
|
||||
if ([config syncClientAuthCertificateCn]) {
|
||||
if ([config syncClientAuthCertificateFile]) {
|
||||
authURLSession.clientCertFile = [config syncClientAuthCertificateFile];
|
||||
authURLSession.clientCertPassword = [config syncClientAuthCertificatePassword];
|
||||
} else if ([config syncClientAuthCertificateCn]) {
|
||||
authURLSession.clientCertCommonName = [config syncClientAuthCertificateCn];
|
||||
} else if ([config syncClientAuthCertificateIssuer]) {
|
||||
authURLSession.clientCertIssuerCn = [config syncClientAuthCertificateIssuer];
|
||||
|
||||
Reference in New Issue
Block a user