Skip to content

Commit f2fd267

Browse files
santactl/doctor: Add checks for syncing, update MOLAuth logs (#448)
1 parent b183c7b commit f2fd267

3 files changed

Lines changed: 101 additions & 10 deletions

File tree

Source/common/MOLAuthenticatingURLSession.m

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ - (void)URLSession:(NSURLSession *)session
131131
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
132132
return;
133133
} else {
134-
[self log:@"Server asked for client authentication but no usable client certificate found."];
134+
[self log:@"[Client Trust] Server asked for authentication but no usable certificate found."];
135135
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil);
136136
return;
137137
}
@@ -141,7 +141,7 @@ - (void)URLSession:(NSURLSession *)session
141141
completionHandler(NSURLSessionAuthChallengeUseCredential, cred);
142142
return;
143143
} else {
144-
[self log:@"Unable to verify server identity."];
144+
[self log:@"[Server Trust] Unable to verify server identity."];
145145
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
146146
return;
147147
}
@@ -203,6 +203,7 @@ - (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)
203203

204204
NSArray *allCerts;
205205
if (self.clientCertFile) {
206+
[self log:@"[Client Trust] Using certificate from file: %@", self.clientCertFile];
206207
foundIdentity = [self identityFromFile:self.clientCertFile password:self.clientCertPassword];
207208
} else {
208209
CFArrayRef cfResults = NULL;
@@ -217,27 +218,34 @@ - (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)
217218
allCerts = [MOLCertificate certificatesFromArray:results];
218219

219220
if (self.clientCertCommonName) {
221+
[self log:@"[Client Trust] Looking for certificate with common name: %@",
222+
self.clientCertCommonName];
220223
foundIdentity = [self identityByFilteringArray:allCerts
221224
commonName:self.clientCertCommonName
222225
issuerCommonName:nil
223226
issuerCountryName:nil
224227
issuerOrgName:nil
225228
issuerOrgUnit:nil];
226229
} else if (self.clientCertIssuerCn) {
230+
[self log:@"[Client Trust] Looking for certificate with issuer common name: %@",
231+
self.clientCertIssuerCn];
227232
foundIdentity = [self identityByFilteringArray:allCerts
228233
commonName:nil
229234
issuerCommonName:self.clientCertIssuerCn
230235
issuerCountryName:nil
231236
issuerOrgName:nil
232237
issuerOrgUnit:nil];
233238
} else {
239+
[self log:@"[Client Trust] Looking for certificate with server-provided CA names"];
234240
for (NSData *allowedIssuer in protectionSpace.distinguishedNames) {
235241
MOLDERDecoder *decoder = [[MOLDERDecoder alloc] initWithData:allowedIssuer];
236242

237243
if (!decoder) {
238244
continue;
239245
}
240246

247+
[self log:@"[Client Trust] Allowed issuer: %@", decoder];
248+
241249
foundIdentity = [self identityByFilteringArray:allCerts
242250
commonName:nil
243251
issuerCommonName:decoder.commonName
@@ -254,7 +262,7 @@ - (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)
254262
SecIdentityCopyCertificate(foundIdentity, &certificate);
255263
MOLCertificate *clientCert = [[MOLCertificate alloc] initWithSecCertificateRef:certificate];
256264
if (certificate) CFRelease(certificate);
257-
if (clientCert) [self log:@"Client Trust: %@", clientCert];
265+
if (clientCert) [self log:@"[Client Trust] Certificate: %@", clientCert];
258266

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

@@ -283,7 +291,7 @@ - (NSURLCredential *)clientCredentialForProtectionSpace:(NSURLProtectionSpace *)
283291
///
284292
- (NSURLCredential *)serverCredentialForProtectionSpace:(NSURLProtectionSpace *)protectionSpace {
285293
if (protectionSpace.serverTrust == NULL) {
286-
[self log:@"Server Trust: No server trust information available"];
294+
[self log:@"[Server Trust] No trust information available"];
287295
return nil;
288296
}
289297

@@ -294,7 +302,7 @@ - (NSURLCredential *)serverCredentialForProtectionSpace:(NSURLProtectionSpace *)
294302
err = SecTrustSetAnchorCertificates(protectionSpace.serverTrust,
295303
(__bridge CFArrayRef)self.anchors);
296304
if (err != errSecSuccess) {
297-
[self log:@"Server Trust: Could not set anchor certificates: %d", err];
305+
[self log:@"[Server Trust] Could not set anchor certificates: %d", err];
298306
return nil;
299307
}
300308
}
@@ -304,7 +312,7 @@ - (NSURLCredential *)serverCredentialForProtectionSpace:(NSURLProtectionSpace *)
304312
if (certChain.firstObject) {
305313
MOLCertificate *cert = [[MOLCertificate alloc]
306314
initWithSecCertificateRef:(__bridge SecCertificateRef)certChain.firstObject];
307-
[self log:@"Server Trust: %@", cert];
315+
[self log:@"[Server Trust] Certificate: %@", cert];
308316
}
309317

310318
// Evaluate the server's cert chain.
@@ -314,7 +322,7 @@ - (NSURLCredential *)serverCredentialForProtectionSpace:(NSURLProtectionSpace *)
314322
NSError *underlyingError = errRef.userInfo[NSUnderlyingErrorKey];
315323
NSString *errMsg =
316324
CFBridgingRelease(SecCopyErrorMessageString((OSStatus)underlyingError.code, NULL));
317-
[self log:@"Server Trust: Unable to evaluate certificate chain for server: %@ (%d)", errMsg,
325+
[self log:@"[Server Trust] Unable to evaluate certificate chain for server: %@ (%d)", errMsg,
318326
underlyingError.code];
319327
return nil;
320328
}
@@ -407,7 +415,7 @@ - (SecIdentityRef)identityFromFile:(NSString *)file password:(NSString *)passwor
407415
NSError *error;
408416
NSData *data = [NSData dataWithContentsOfFile:file options:0 error:&error];
409417
if (error) {
410-
[self log:@"Client Trust: Couldn't open client certificate %@: %@", self.clientCertFile,
418+
[self log:@"[Client Trust] Couldn't open client certificate %@: %@", self.clientCertFile,
411419
[error localizedDescription]];
412420
return nil;
413421
}
@@ -419,7 +427,7 @@ - (SecIdentityRef)identityFromFile:(NSString *)file password:(NSString *)passwor
419427
NSArray *identities = CFBridgingRelease(cfIdentities);
420428

421429
if (err != errSecSuccess) {
422-
[self log:@"Client Trust: Couldn't load client certificate %@: %d", self.clientCertFile, err];
430+
[self log:@"[Client Trust] Couldn't load client certificate %@: %d", self.clientCertFile, err];
423431
return nil;
424432
}
425433

@@ -437,7 +445,7 @@ - (NSArray *)locateIntermediatesForCertificate:(MOLCertificate *)leafCert
437445
OSStatus res = SecTrustCreateWithCertificates(leafCert.certRef, NULL, &t);
438446
if (res != errSecSuccess) {
439447
NSString *errMsg = CFBridgingRelease(SecCopyErrorMessageString(res, NULL));
440-
[self log:@"Failed to create trust for locating intermediate certs: %@", errMsg];
448+
[self log:@"[Client Trust] Failed to create trust for locating intermediate certs: %@", errMsg];
441449
return nil;
442450
}
443451

Source/santactl/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ objc_library(
8585
":SNTCommandTelemetry",
8686
":santactl_cmd",
8787
"//Source/common:CertificateHelpers",
88+
"//Source/common:MOLAuthenticatingURLSession",
8889
"//Source/common:MOLCertificate",
8990
"//Source/common:MOLCodesignChecker",
9091
"//Source/common:MOLXPCConnection",
@@ -108,6 +109,7 @@ objc_library(
108109
"//Source/common:StoredEventHelpers",
109110
"//Source/common:SystemResources",
110111
"@FMDB",
112+
"@abseil-cpp//absl/cleanup:cleanup",
111113
],
112114
)
113115

Source/santactl/Commands/SNTCommandDoctor.mm

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#include <optional>
2121
#include <vector>
2222

23+
#include "absl/cleanup/cleanup.h"
24+
25+
#import "Source/common/MOLAuthenticatingURLSession.h"
2326
#import "Source/common/SNTConfigurator.h"
2427
#import "Source/common/SNTLogging.h"
2528
#import "Source/common/SystemResources.h"
@@ -77,6 +80,7 @@ - (void)runWithArguments:(NSArray *)arguments {
7780
BOOL err = NO;
7881
err |= [self validateProcesses];
7982
err |= [self validateConfiguration];
83+
err |= [self validateSync];
8084
exit(err);
8185
}
8286

@@ -126,6 +130,7 @@ - (BOOL)validateConfiguration {
126130
NSArray *errors = [[SNTConfigurator configurator] validateConfiguration];
127131
if (!errors.count) {
128132
print(@"[+] No configuration errors detected");
133+
print(@"");
129134
return NO;
130135
}
131136

@@ -137,4 +142,80 @@ - (BOOL)validateConfiguration {
137142
return YES;
138143
}
139144

145+
- (BOOL)validateSync {
146+
print(@"=> Validating sync...");
147+
148+
SNTConfigurator *config = [SNTConfigurator configurator];
149+
150+
NSURL *syncBaseURL = config.syncBaseURL;
151+
if (!syncBaseURL) {
152+
print(@"[+] Sync is disabled");
153+
print(@"");
154+
// Don't treat this as an error.
155+
return YES;
156+
}
157+
print(@"[+] Sync is enabled");
158+
159+
if (![syncBaseURL.scheme isEqualToString:@"https"]) {
160+
print(@"[-] Sync is not using HTTPS");
161+
} else {
162+
print(@"[+] Sync is using HTTPS");
163+
}
164+
165+
NSURLSessionConfiguration *sessConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
166+
sessConfig.connectionProxyDictionary = [[SNTConfigurator configurator] syncProxyConfig];
167+
168+
MOLAuthenticatingURLSession *authURLSession =
169+
[[MOLAuthenticatingURLSession alloc] initWithSessionConfiguration:sessConfig];
170+
authURLSession.userAgent = @"santactl-sync/";
171+
NSString *santactlVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
172+
if (santactlVersion) {
173+
authURLSession.userAgent = [authURLSession.userAgent stringByAppendingString:santactlVersion];
174+
}
175+
authURLSession.refusesRedirects = YES;
176+
authURLSession.serverHostname = syncBaseURL.host;
177+
authURLSession.loggingBlock = ^(NSString *line) {
178+
print(@"%s", [line UTF8String]);
179+
};
180+
181+
// Configure server auth
182+
if ([config syncServerAuthRootsFile]) {
183+
authURLSession.serverRootsPemFile = [config syncServerAuthRootsFile];
184+
} else if ([config syncServerAuthRootsData]) {
185+
authURLSession.serverRootsPemData = [config syncServerAuthRootsData];
186+
}
187+
188+
// Configure client auth
189+
if ([config syncClientAuthCertificateFile]) {
190+
NSString *certFile = [config syncClientAuthCertificateFile];
191+
authURLSession.clientCertFile = certFile;
192+
authURLSession.clientCertPassword = [config syncClientAuthCertificatePassword];
193+
} else if ([config syncClientAuthCertificateCn]) {
194+
authURLSession.clientCertCommonName = [config syncClientAuthCertificateCn];
195+
} else if ([config syncClientAuthCertificateIssuer]) {
196+
authURLSession.clientCertIssuerCn = [config syncClientAuthCertificateIssuer];
197+
}
198+
199+
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
200+
NSURLSessionDataTask *task = [[authURLSession session]
201+
dataTaskWithURL:[syncBaseURL URLByAppendingPathComponent:@"/preflight/santactl-doctor-test"]
202+
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
203+
absl::Cleanup cleanup = ^{
204+
dispatch_semaphore_signal(semaphore);
205+
};
206+
207+
if (error) {
208+
print(@"[-] Failed to retrieve preflight data");
209+
return;
210+
}
211+
print(@"[+] Preflight request succeeded");
212+
}];
213+
[task resume];
214+
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
215+
216+
print(@"");
217+
218+
return NO;
219+
}
220+
140221
@end

0 commit comments

Comments
 (0)