forked from arduino/arduino-create-agent
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcertificates_darwin.m
137 lines (112 loc) · 6.19 KB
/
certificates_darwin.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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.
}