I'm on macOS 10.15.6. My application is 100% Swift right now, but I'm comfortable enough with Objective-C if that is needed.
When I visit a page using a self-signed certificate in Safari, I get the expected "This Connection Is Not Private" message. If I hit Show Details > visit this website > Visit Website, the certificate is added to my Keychain. It has a little blue circle with a white + in it. When I double-click the certificate, it gives me the details. One of them, just under the expiration date at the top, is:
I'm making a tool which talks to an API over HTTPS. Some of the servers running this API use the same certificate for a web UI to manage the application. When I visit the page in Safari and trust the certificate there, my application trusts it with no further fuss. I would like the same behavior in the other direction. If a user happens to connect to the server with my application first, I would like to add the certificate to the Keychain in such a way that Safari would also be able to use it for the same server.
When I visit a page using a self-signed certificate in Safari, I get the expected "This Connection Is Not Private" message. If I hit Show Details > visit this website > Visit Website, the certificate is added to my Keychain. It has a little blue circle with a white + in it. When I double-click the certificate, it gives me the details. One of them, just under the expiration date at the top, is:
Is there a public API to add certificates like this with my own software? Or to add this property to an existing certificate?This certificate is marked as trusted for "<IP address>"
I'm making a tool which talks to an API over HTTPS. Some of the servers running this API use the same certificate for a web UI to manage the application. When I visit the page in Safari and trust the certificate there, my application trusts it with no further fuss. I would like the same behavior in the other direction. If a user happens to connect to the server with my application first, I would like to add the certificate to the Keychain in such a way that Safari would also be able to use it for the same server.
That got me where I needed to be. Thank you!
To save others time, here's what I ended up writing:
Lines 2 through 13 import the certificate into the Keychain. Lines 15 through 38 set the trust overrides. Explicit types because I don't mess around with type inference in even vaguely-security-related code.
CSSMERR_TP_CERT_EXPIRED is error -2147409654 (cssmerr.h). I'm not sure what error -2147408896 is. Haven't found it in an error table yet. I got the two values by examining some existing self-signed certificates I trusted in Safari.
To save others time, here's what I ended up writing:
Code Block Swift func addTrustForCertificate(_ serverCertificate:SecCertificate, host:String) { let serverCertDictionary:CFDictionary = [ kSecClass:kSecClassCertificate, kSecValueRef:serverCertificate ] as [CFString:Any] as CFDictionary let secItemAddError:OSStatus = SecItemAdd(serverCertDictionary, nil) switch secItemAddError { case noErr: break default: let errorMessage:String = SecCopyErrorMessageString(secItemAddError,nil) print("addTrustForCertificate SecItemAdd error: \(String(describing: errorMessage))") } let secPolicyToSet:SecPolicy = SecPolicyCreateSSL(true, nil) let SecTrustDict1:CFDictionary = [ "kSecTrustSettingsAllowedError":CSSMERR_TP_CERT_EXPIRED, "kSecTrustSettingsPolicy":secPolicyToSet, "kSecTrustSettingsPolicyName":"sslServer", "kSecTrustSettingsPolicyString":host, "kSecTrustSettingsResult":1 ] as CFDictionary let SecTrustDict2:CFDictionary = [ "kSecTrustSettingsAllowedError":-2147408896, "kSecTrustSettingsPolicy":secPolicyToSet, "kSecTrustSettingsPolicyName":"sslServer", "kSecTrustSettingsPolicyString":host, "kSecTrustSettingsResult":1 ] as CFDictionary let trustSettings:CFArray = [SecTrustDict1,SecTrustDict2] as CFArray let trustSettingsError:OSStatus = SecTrustSettingsSetTrustSettings(serverCertificate, .user, trustSettings) switch trustSettingsError { case noErr: break default: let errorMessage:String = SecCopyErrorMessageString(trustSettingsError,nil) print("addTrustForCertificate SecTrustSettingsSetTrustSettings error: \(String(describing: errorMessage))") } }
Lines 2 through 13 import the certificate into the Keychain. Lines 15 through 38 set the trust overrides. Explicit types because I don't mess around with type inference in even vaguely-security-related code.
CSSMERR_TP_CERT_EXPIRED is error -2147409654 (cssmerr.h). I'm not sure what error -2147408896 is. Haven't found it in an error table yet. I got the two values by examining some existing self-signed certificates I trusted in Safari.