-
-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix buttons and improve handling of certificates when Safari is not t…
…he default browser (#949) * Fix check on buttons returning the correct message * Update certificates regardless of the default browser * Set installCerts when the certificate is installed from previous versions of the Agent regardless of the default browser * Do not set installCerts to false if the default browser is not Safari * Do not ask again to update the certificate if the user refuses once * Fix user script on macOS * Check for the presence of the certificate in the keychain to determine if it is installed * Fix getExpirationDate breaking when the certificate is expired * Fix return value in case of error * getExpirationDate rewritten to use the correct expiration field. * Separate osascript default button from the one to press * Fix leftover buttons * Small text fixes in the "manage certificate" dialog * Simplify error management in getExpirationDate * Fix compiler warnings and move obj-c code into a separate file. * certInKeychain returns a bool * Fix building errors caused by objective-c files on Ubuntu and Windows * Build objective-c files only on Darwin * Remove -ld_classic library because XCode is not up to date on the CI --------- Co-authored-by: Xayton <[email protected]>
- Loading branch information
1 parent
222a505
commit 3190a1a
Showing
8 changed files
with
264 additions
and
228 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
const char *getDefaultBrowserName(); | ||
|
||
const char *installCert(const char *path); | ||
const char *uninstallCert(); | ||
const bool certInKeychain(); | ||
|
||
const char *getExpirationDate(long *expirationDate); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
#import <Foundation/Foundation.h> | ||
#import <AppKit/AppKit.h> | ||
#include "certificates_darwin.h" | ||
|
||
// Used to return error strings (as NSString) as a C-string to the Go code. | ||
const char *toErrorString(NSString *errString) { | ||
NSLog(@"%@", errString); | ||
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; | ||
} | ||
|
||
// Returns a string describing the name of the default browser set for the user, nil in case of error. | ||
const char *getDefaultBrowserName() { | ||
NSURL *defaultBrowserURL = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:[NSURL URLWithString:@"http://"]]; | ||
if (defaultBrowserURL) { | ||
NSBundle *defaultBrowserBundle = [NSBundle bundleWithURL:defaultBrowserURL]; | ||
NSString *defaultBrowser = [defaultBrowserBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]; | ||
|
||
return [defaultBrowser cStringUsingEncoding:[NSString defaultCStringEncoding]]; | ||
} | ||
|
||
return ""; | ||
} | ||
|
||
// inspired by https://stackoverflow.com/questions/12798950/ios-install-ssl-certificate-programmatically | ||
const char *installCert(const char *path) { | ||
NSURL *url = [NSURL fileURLWithPath:@(path) isDirectory:NO]; | ||
NSData *rootCertData = [NSData dataWithContentsOfURL:url]; | ||
|
||
OSStatus err = noErr; | ||
SecCertificateRef rootCert = SecCertificateCreateWithData(kCFAllocatorDefault, (CFDataRef) rootCertData); | ||
|
||
CFTypeRef result; | ||
|
||
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: | ||
(id)kSecClassCertificate, kSecClass, | ||
rootCert, kSecValueRef, | ||
nil]; | ||
|
||
err = SecItemAdd((CFDictionaryRef)dict, &result); | ||
|
||
if (err == noErr) { | ||
NSLog(@"Install root certificate success"); | ||
} else if (err == errSecDuplicateItem) { | ||
NSString *errString = [@"duplicate root certificate entry. Error: " stringByAppendingFormat:@"%d", err]; | ||
NSLog(@"%@", errString); | ||
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; | ||
} else { | ||
NSString *errString = [@"install root certificate failure. Error: " stringByAppendingFormat:@"%d", err]; | ||
NSLog(@"%@", errString); | ||
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; | ||
} | ||
|
||
NSDictionary *newTrustSettings = @{(id)kSecTrustSettingsResult: [NSNumber numberWithInt:kSecTrustSettingsResultTrustRoot]}; | ||
err = SecTrustSettingsSetTrustSettings(rootCert, kSecTrustSettingsDomainUser, (__bridge CFTypeRef)(newTrustSettings)); | ||
if (err != errSecSuccess) { | ||
NSString *errString = [@"Could not change the trust setting for a certificate. Error: " stringByAppendingFormat:@"%d", err]; | ||
NSLog(@"%@", errString); | ||
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; | ||
} | ||
|
||
return ""; | ||
} | ||
|
||
const char *uninstallCert() { | ||
// Each line is a key-value of the dictionary. Note: the the inverted order, value first then key. | ||
NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: | ||
(id)kSecClassCertificate, kSecClass, | ||
CFSTR("Arduino"), kSecAttrLabel, | ||
kSecMatchLimitOne, kSecMatchLimit, | ||
kCFBooleanTrue, kSecReturnAttributes, | ||
nil]; | ||
|
||
OSStatus err = noErr; | ||
// Use this function to check for errors | ||
err = SecItemCopyMatching((CFDictionaryRef)dict, nil); | ||
if (err == noErr) { | ||
err = SecItemDelete((CFDictionaryRef)dict); | ||
if (err != noErr) { | ||
NSString *errString = [@"Could not delete the certificates. Error: " stringByAppendingFormat:@"%d", err]; | ||
NSLog(@"%@", errString); | ||
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; | ||
} | ||
} else if (err != errSecItemNotFound){ | ||
NSString *errString = [@"Error: " stringByAppendingFormat:@"%d", err]; | ||
NSLog(@"%@", errString); | ||
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]]; | ||
} | ||
return ""; | ||
} | ||
|
||
const bool certInKeychain() { | ||
// Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate. | ||
NSDictionary *getquery = @{ | ||
(id)kSecClass: (id)kSecClassCertificate, | ||
(id)kSecAttrLabel: @"Arduino", | ||
(id)kSecReturnRef: @YES, | ||
}; | ||
|
||
OSStatus err = SecItemCopyMatching((CFDictionaryRef)getquery, nil); | ||
return (err == noErr); // No error means the certificate was found, otherwise err will be "errSecItemNotFound". | ||
} | ||
|
||
// Returns the expiration date "kSecOIDX509V1ValidityNotAfter" of the Arduino certificate. | ||
// The value is returned as a CFAbsoluteTime: a long number of seconds from the date of 1 Jan 2001 00:00:00 GMT. | ||
const char *getExpirationDate(long *expirationDate) { | ||
// Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate. | ||
NSDictionary *getquery = @{ | ||
(id)kSecClass: (id)kSecClassCertificate, | ||
(id)kSecAttrLabel: @"Arduino", | ||
(id)kSecReturnRef: @YES, | ||
}; | ||
|
||
SecCertificateRef cert = NULL; | ||
|
||
// Search the keychain for certificates matching the query above. | ||
OSStatus err = SecItemCopyMatching((CFDictionaryRef)getquery, (CFTypeRef *)&cert); | ||
if (err != noErr) return toErrorString([@"Error getting the certificate: " stringByAppendingFormat:@"%d", err]); | ||
|
||
// Get data from the certificate, as a dictionary of properties. We just need the "invalidity not after" property. | ||
CFDictionaryRef certDict = SecCertificateCopyValues(cert, | ||
(__bridge CFArrayRef)@[(__bridge id)kSecOIDX509V1ValidityNotAfter], NULL); | ||
if (certDict == NULL) return toErrorString(@"SecCertificateCopyValues failed"); | ||
|
||
|
||
// Get the "validity not after" property as a dictionary, and get the "value" key (that is a number). | ||
CFDictionaryRef validityNotAfterDict = CFDictionaryGetValue(certDict, kSecOIDX509V1ValidityNotAfter); | ||
if (validityNotAfterDict == NULL) return toErrorString(@"CFDictionaryGetValue (validity) failed"); | ||
|
||
CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(validityNotAfterDict, kSecPropertyKeyValue); | ||
if (number == NULL) return toErrorString(@"CFDictionaryGetValue (keyValue) failed"); | ||
|
||
CFNumberGetValue(number, kCFNumberSInt64Type, expirationDate); | ||
// NSLog(@"Certificate validity not after: %ld", *expirationDate); | ||
|
||
CFRelease(certDict); | ||
return ""; // No error. | ||
} |
Oops, something went wrong.