Skip to content

Commit cf31546

Browse files
committed
getExpirationDate rewritten to use the correct expiration field.
1 parent 4064541 commit cf31546

File tree

1 file changed

+39
-37
lines changed

1 file changed

+39
-37
lines changed

certificates/install_darwin.go

+39-37
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ package certificates
2424
#cgo LDFLAGS: -framework Cocoa
2525
#import <Cocoa/Cocoa.h>
2626
27+
28+
// Used to return error strings (as NSString) as a C-string to the Go code.
29+
const char *toErrorString(NSString *errString) {
30+
NSLog(@"%@", errString);
31+
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
32+
}
33+
2734
const char *installCert(const char *path) {
2835
NSURL *url = [NSURL fileURLWithPath:@(path) isDirectory:NO];
2936
NSData *rootCertData = [NSData dataWithContentsOfURL:url];
@@ -90,7 +97,9 @@ const char *uninstallCert() {
9097
return "";
9198
}
9299
93-
const char *getExpirationDate(char *expirationDate){
100+
// Returns the expiration date "kSecOIDX509V1ValidityNotAfter" of the Arduino certificate.
101+
// The value is returned as a CFAbsoluteTime: a long number of seconds from the date of 1 Jan 2001 00:00:00 GMT.
102+
const char *getExpirationDate(long *expirationDate) {
94103
// Create a key-value dictionary used to query the Keychain and look for the "Arduino" root certificate.
95104
NSDictionary *getquery = @{
96105
(id)kSecClass: (id)kSecClassCertificate,
@@ -101,42 +110,32 @@ const char *getExpirationDate(char *expirationDate){
101110
OSStatus err = noErr;
102111
SecCertificateRef cert = NULL;
103112
104-
// Use this function to check for errors
113+
// Search the keychain for certificates matching the query above.
105114
err = SecItemCopyMatching((CFDictionaryRef)getquery, (CFTypeRef *)&cert);
106-
107115
if (err != noErr){
108116
NSString *errString = [@"Error: " stringByAppendingFormat:@"%d", err];
109117
NSLog(@"%@", errString);
110118
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
111119
}
112120
113-
// Get data from the certificate. We just need the "invalidity date" property.
114-
CFDictionaryRef valuesDict = SecCertificateCopyValues(cert, (__bridge CFArrayRef)@[(__bridge id)kSecOIDX509V1ValidityNotAfter], NULL);
115-
116-
id expirationDateValue;
117-
if(valuesDict){
118-
CFDictionaryRef invalidityDateDictionaryRef = CFDictionaryGetValue(valuesDict, kSecOIDX509V1ValidityNotAfter);
119-
if(invalidityDateDictionaryRef){
120-
CFTypeRef invalidityRef = CFDictionaryGetValue(invalidityDateDictionaryRef, kSecPropertyKeyValue);
121-
if(invalidityRef){
122-
expirationDateValue = CFBridgingRelease(invalidityRef);
123-
}
124-
}
125-
CFRelease(valuesDict);
126-
}
121+
// Get data from the certificate, as a dictionary of properties. We just need the "invalidity not after" property.
122+
CFDictionaryRef certDict = SecCertificateCopyValues(cert,
123+
(__bridge CFArrayRef)@[(__bridge id)kSecOIDX509V1ValidityNotAfter], NULL);
124+
if (certDict == NULL) return toErrorString(@"SecCertificateCopyValues failed");
127125
128-
NSString *outputString = [@"" stringByAppendingFormat:@"%@", expirationDateValue];
129-
if([outputString isEqualToString:@""]){
130-
NSString *errString = @"Error: the expiration date of the certificate could not be found";
131-
NSLog(@"%@", errString);
132-
return [errString cStringUsingEncoding:[NSString defaultCStringEncoding]];
133-
}
134126
135-
// This workaround allows to obtain the expiration date alongside the error message
136-
strncpy(expirationDate, [outputString cStringUsingEncoding:[NSString defaultCStringEncoding]], 32);
137-
expirationDate[32-1] = 0;
127+
// Get the "validity not after" property as a dictionary, and get the "value" key (that is a number).
128+
CFDictionaryRef validityNotAfterDict = CFDictionaryGetValue(certDict, kSecOIDX509V1ValidityNotAfter);
129+
if (validityNotAfterDict == NULL) return toErrorString(@"CFDictionaryGetValue (validity) failed");
138130
139-
return "";
131+
CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(validityNotAfterDict, kSecPropertyKeyValue);
132+
if (number == NULL) return toErrorString(@"CFDictionaryGetValue (keyValue) failed");
133+
134+
CFNumberGetValue(number, kCFNumberSInt64Type, expirationDate);
135+
// NSLog(@"Certificate validity not after: %ld", *expirationDate);
136+
137+
CFRelease(certDict);
138+
return ""; // No error.
140139
}
141140
142141
const char *getDefaultBrowserName() {
@@ -173,7 +172,6 @@ const char *certInKeychain() {
173172
import "C"
174173
import (
175174
"errors"
176-
"strconv"
177175
"time"
178176
"unsafe"
179177

@@ -215,16 +213,20 @@ func UninstallCertificates() error {
215213
// GetExpirationDate returns the expiration date of a certificate stored in the keychain
216214
func GetExpirationDate() (time.Time, error) {
217215
log.Infof("Retrieving certificate's expiration date")
218-
dateString := C.CString("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") // 32 characters string
219-
defer C.free(unsafe.Pointer(dateString))
220-
p := C.getExpirationDate(dateString)
221-
s := C.GoString(p)
222-
if len(s) != 0 {
223-
utilities.UserPrompt(s, "\"OK\"", "OK", "Arduino Agent: Error retrieving expiration date")
224-
return time.Time{}, errors.New(s)
216+
217+
expirationDateLong := C.long(0)
218+
219+
err := C.getExpirationDate(&expirationDateLong)
220+
errString := C.GoString(err)
221+
if len(errString) > 0 {
222+
utilities.UserPrompt(errString, "\"OK\"", "OK", "Arduino Agent: Error retrieving expiration date")
223+
return time.Time{}, errors.New(errString)
225224
}
226-
dateValue, _ := strconv.ParseInt(C.GoString(dateString), 10, 64)
227-
return time.Unix(dateValue, 0).AddDate(31, 0, 0), nil
225+
226+
// The expirationDate is the number of seconds from the date of 1 Jan 2001 00:00:00 GMT.
227+
// Add 31 years to convert it to Unix Epoch.
228+
expirationDate := int64(expirationDateLong)
229+
return time.Unix(expirationDate, 0).AddDate(31, 0, 0), nil
228230
}
229231

230232
// GetDefaultBrowserName returns the name of the default browser

0 commit comments

Comments
 (0)