Skip to content

Commit 3b8330d

Browse files
deepak1556aduh95
authored andcommitted
crypto: improve system certificate enumeration logic on macOS
1) Fixed macOS default for missing kSecTrustSettingsResult When kSecTrustSettingsResult is absent from a trust settings dictionary, Apple specifies kSecTrustSettingsResultTrustRoot as the default value. Previously, the trust result evaluation (deny check, self-issued check, TrustAsRoot check) was inside the block that only executed when kSecTrustSettingsResult was explicitly present. When the key was absent, the function fell through to return UNSPECIFIED, incorrectly rejecting self-signed certificates that should have been trusted via the default. Move the trust result evaluation outside the conditional block so the default value of kSecTrustSettingsResultTrustRoot flows through the same code path as explicit values. This aligns with Chromium's trust_store_mac.cc implementation. 2) Fix CFRelease leak in IsTrustDictionaryTrustedForPolicy: the CFDictionaryRef returned by SecPolicyCopyProperties(policy_ref) was not released when the policy OID matched kSecPolicyAppleSSL. 3) Deduplicate certificates: SecItemCopyMatching can return the same certificate from multiple keychains. 4) Filter expired certificates. Signed-off-by: deepak1556 <hop2deep@gmail.com> PR-URL: #62576 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
1 parent 6e56f01 commit 3b8330d

7 files changed

Lines changed: 310 additions & 28 deletions

File tree

src/crypto/crypto_context.cc

Lines changed: 87 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,10 @@ TrustStatus IsTrustDictionaryTrustedForPolicy(CFDictionaryRef trust_dict,
342342
CFStringRef policy_oid = reinterpret_cast<CFStringRef>(
343343
const_cast<void*>(CFDictionaryGetValue(policy_dict, kSecPolicyOid)));
344344

345-
if (!CFEqual(policy_oid, kSecPolicyAppleSSL)) {
345+
bool matches_ssl = CFEqual(policy_oid, kSecPolicyAppleSSL);
346+
CFRelease(policy_dict);
347+
348+
if (!matches_ssl) {
346349
return TrustStatus::UNSPECIFIED;
347350
}
348351
}
@@ -359,35 +362,44 @@ TrustStatus IsTrustDictionaryTrustedForPolicy(CFDictionaryRef trust_dict,
359362
&trust_settings_result)) {
360363
return TrustStatus::UNSPECIFIED;
361364
}
365+
}
362366

363-
if (trust_settings_result == kSecTrustSettingsResultDeny) {
364-
return TrustStatus::DISTRUSTED;
365-
}
366-
367-
// This is a bit of a hack: if the cert is self-issued allow either
368-
// kSecTrustSettingsResultTrustRoot or kSecTrustSettingsResultTrustAsRoot on
369-
// the basis that SecTrustSetTrustSettings should not allow creating an
370-
// invalid trust record in the first place. (The spec is that
371-
// kSecTrustSettingsResultTrustRoot can only be applied to root(self-signed)
372-
// certs and kSecTrustSettingsResultTrustAsRoot is used for other certs.)
373-
// This hack avoids having to check the signature on the cert which is slow
374-
// if using the platform APIs, and may require supporting MD5 signature
375-
// algorithms on some older OSX versions or locally added roots, which is
376-
// undesirable in the built-in signature verifier.
377-
if (is_self_issued) {
378-
return trust_settings_result == kSecTrustSettingsResultTrustRoot ||
379-
trust_settings_result == kSecTrustSettingsResultTrustAsRoot
380-
? TrustStatus::TRUSTED
381-
: TrustStatus::UNSPECIFIED;
382-
}
383-
384-
// kSecTrustSettingsResultTrustAsRoot can only be applied to non-root certs.
385-
return (trust_settings_result == kSecTrustSettingsResultTrustAsRoot)
367+
// When kSecTrustSettingsResult is absent from the trust dict,
368+
// Apple docs specify kSecTrustSettingsResultTrustRoot as the default.
369+
// Refs
370+
// https://github.com/apple-oss-distributions/Security/blob/db15acbe6a7f257a859ad9a3bb86097bfe0679d9/trust/headers/SecTrustSettings.h#L119-L122
371+
// This is also enforced at write time for self-signed certs get TrustRoot,
372+
// and non-self-signed certs cannot have an empty settings,
373+
// Refs
374+
// https://github.com/apple-oss-distributions/Security/blob/db15acbe6a7f257a859ad9a3bb86097bfe0679d9/OSX/sec/Security/SecTrustStore.c#L196-L207
375+
376+
if (trust_settings_result == kSecTrustSettingsResultDeny) {
377+
return TrustStatus::DISTRUSTED;
378+
}
379+
380+
// From
381+
// https://source.chromium.org/chromium/chromium/src/+/main:net/cert/internal/trust_store_mac.cc;l=144-146
382+
// This is a bit of a hack: if the cert is self-issued allow either
383+
// kSecTrustSettingsResultTrustRoot or kSecTrustSettingsResultTrustAsRoot on
384+
// the basis that SecTrustSetTrustSettings should not allow creating an
385+
// invalid trust record in the first place. (The spec is that
386+
// kSecTrustSettingsResultTrustRoot can only be applied to root(self-signed)
387+
// certs and kSecTrustSettingsResultTrustAsRoot is used for other certs.)
388+
// This hack avoids having to check the signature on the cert which is slow
389+
// if using the platform APIs, and may require supporting MD5 signature
390+
// algorithms on some older OSX versions or locally added roots, which is
391+
// undesirable in the built-in signature verifier.
392+
if (is_self_issued) {
393+
return (trust_settings_result == kSecTrustSettingsResultTrustRoot ||
394+
trust_settings_result == kSecTrustSettingsResultTrustAsRoot)
386395
? TrustStatus::TRUSTED
387396
: TrustStatus::UNSPECIFIED;
388397
}
389398

390-
return TrustStatus::UNSPECIFIED;
399+
// kSecTrustSettingsResultTrustAsRoot can only be applied to non-root certs.
400+
return (trust_settings_result == kSecTrustSettingsResultTrustAsRoot)
401+
? TrustStatus::TRUSTED
402+
: TrustStatus::UNSPECIFIED;
391403
}
392404

393405
TrustStatus IsTrustSettingsTrustedForPolicy(CFArrayRef trust_settings,
@@ -420,6 +432,17 @@ bool IsCertificateTrustValid(SecCertificateRef ref) {
420432
CFArrayCreateMutable(nullptr, 1, &kCFTypeArrayCallBacks);
421433
CFArraySetValueAtIndex(subj_certs, 0, ref);
422434

435+
// SecTrustEvaluateWithError is used to check whether an individual
436+
// certificate is trusted by the system — not to validate it for a
437+
// specific role (server, intermediate, etc.). We just need a minimal
438+
// policy that guarantees the certificate can be chained to a known
439+
// trust anchor while filtering out irrelevant certificates.
440+
//
441+
// Refs
442+
// https://github.com/apple-oss-distributions/Security/blob/db15acbe6a7f257a859ad9a3bb86097bfe0679d9/OSX/sec/Security/SecPolicy.c#L1855-L1890
443+
// SecPolicyCreateSSL (both mark EKU optional):
444+
// server=true -> BasicX509 + serverAuth + anyExtendedKeyUsage + SGC
445+
// server=false -> BasicX509 + clientAuth + anyExtendedKeyUsage
423446
SecPolicyRef policy = SecPolicyCreateSSL(false, nullptr);
424447
OSStatus ortn =
425448
SecTrustCreateWithCertificates(subj_certs, policy, &sec_trust);
@@ -489,6 +512,21 @@ bool IsCertificateTrustedForPolicy(X509* cert, SecCertificateRef ref) {
489512
return false;
490513
}
491514

515+
// Checks if a certificate has expired.
516+
// Returns true if the certificate's notAfter date is in the past.
517+
static bool IsCertificateExpired(X509* cert) {
518+
// X509_cmp_current_time returns:
519+
// -1 if the time is in the past (expired)
520+
// 0 if there was an error
521+
// 1 if the time is in the future (not yet expired)
522+
ASN1_TIME* not_after = X509_get_notAfter(cert);
523+
if (not_after == nullptr) {
524+
return false;
525+
}
526+
int cmp = X509_cmp_current_time(not_after);
527+
return cmp < 0;
528+
}
529+
492530
void ReadMacOSKeychainCertificates(
493531
std::vector<X509*>* system_root_certificates_X509) {
494532
CFTypeRef search_keys[] = {kSecClass, kSecMatchLimit, kSecReturnRef};
@@ -516,6 +554,10 @@ void ReadMacOSKeychainCertificates(
516554

517555
CFIndex count = CFArrayGetCount(curr_anchors);
518556

557+
// Track seen certificates to detect duplicates (same cert in multiple
558+
// keychains).
559+
std::set<X509*, X509Less> seen_certs;
560+
519561
for (int i = 0; i < count; ++i) {
520562
SecCertificateRef cert_ref = reinterpret_cast<SecCertificateRef>(
521563
const_cast<void*>(CFArrayGetValueAtIndex(curr_anchors, i)));
@@ -541,11 +583,28 @@ void ReadMacOSKeychainCertificates(
541583
}
542584

543585
bool is_valid = IsCertificateTrustedForPolicy(cert, cert_ref);
544-
if (is_valid) {
545-
system_root_certificates_X509->emplace_back(cert);
546-
} else {
586+
if (!is_valid) {
587+
X509_free(cert);
588+
continue;
589+
}
590+
591+
// Skip duplicate certificates.
592+
auto [it, inserted] = seen_certs.insert(cert);
593+
if (!inserted) {
594+
X509_free(cert);
595+
continue;
596+
}
597+
598+
// Skip expired certificates.
599+
if (IsCertificateExpired(cert)) {
600+
per_process::Debug(DebugCategory::CRYPTO,
601+
"Skipping expired system certificate\n");
602+
seen_certs.erase(it);
547603
X509_free(cert);
604+
continue;
548605
}
606+
607+
system_root_certificates_X509->emplace_back(cert);
549608
}
550609
CFRelease(curr_anchors);
551610
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDSzCCAjOgAwIBAgIUJmC4/h9L3c8Arrxyo/+O73Owt9AwDQYJKoZIhvcNAQEL
3+
BQAwNTEhMB8GA1UEAwwYTm9kZUpTLVRlc3QtRXhwaXJlZC1Sb290MRAwDgYDVQQK
4+
DAdOb2RlLmpzMB4XDTIwMDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowNTEhMB8G
5+
A1UEAwwYTm9kZUpTLVRlc3QtRXhwaXJlZC1Sb290MRAwDgYDVQQKDAdOb2RlLmpz
6+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArkeWKdWP/YG89KiMCTYe
7+
9Q3DSMwzKeYrjtK5FeVxSHqo5za01VYCYsHpmTZFTM5P6nU6c889vZ0+C5lS1QAa
8+
JLgkUYpMMTk7ycAO0VKYugB9vHI3mQUH3Fkk7cilq5r1KyR1RqaGx7xhe49iFyXo
9+
zIE7C9fAQ4/DhqkuZlCnFg9PQLzKikgRdUUZsR/kvEAK30YyCcVs5po5oTGZB1VB
10+
gRoNYLPqSBCUtgfHEw2EIqRNQtgVwEuJVEclwbijkgIm4NFDCFKixbVE8KQFAuxr
11+
SFO8msDonubXJhCXZkNeh+diBMl7lglZEQU8o6ax0lqrV8mCPselXc0ipR/eD6aG
12+
XQIDAQABo1MwUTAdBgNVHQ4EFgQUN+lQVSG+5zPWNm/XiMcDMk9GVnowHwYDVR0j
13+
BBgwFoAUN+lQVSG+5zPWNm/XiMcDMk9GVnowDwYDVR0TAQH/BAUwAwEB/zANBgkq
14+
hkiG9w0BAQsFAAOCAQEASj1j/atg8qr3aZEsukmFaBf7eu4c0O0WwogTwCaSAEtn
15+
6et9G9rbg++X3JDHBv2PKiYdhSKTz2Kdsaau0fw0fmDkrFB5fwvzi6JU+LZ0Q8Ur
16+
jPlcks8sIdByX9mAbmf0Hur1qkPBoOm4BQNHrhEA+ExD8jbTAUukAOwH0mZV9ZzC
17+
B/7qVXwV6JmvdLXKDeinScnu1AIcYJVPUFEO2ZSkl+4XsdFogN+t4ryisosgFCtL
18+
AWkxA2/InBPBncDOUiceagJQdkGiyhsySxj/niLe8XUUo0p6/bYgqV7loJV6qkDA
19+
6KPH1RyigZMJ0SxNvj5oW1wcS3N2i/uX5csq9/w2nA==
20+
-----END CERTIFICATE-----
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCuR5Yp1Y/9gbz0
3+
qIwJNh71DcNIzDMp5iuO0rkV5XFIeqjnNrTVVgJiwemZNkVMzk/qdTpzzz29nT4L
4+
mVLVABokuCRRikwxOTvJwA7RUpi6AH28cjeZBQfcWSTtyKWrmvUrJHVGpobHvGF7
5+
j2IXJejMgTsL18BDj8OGqS5mUKcWD09AvMqKSBF1RRmxH+S8QArfRjIJxWzmmjmh
6+
MZkHVUGBGg1gs+pIEJS2B8cTDYQipE1C2BXAS4lURyXBuKOSAibg0UMIUqLFtUTw
7+
pAUC7GtIU7yawOie5tcmEJdmQ16H52IEyXuWCVkRBTyjprHSWqtXyYI+x6VdzSKl
8+
H94PpoZdAgMBAAECggEAAoFI6UUGktBAlQuvJ5q9iywteGhm+90xFxZ0TppDrJUG
9+
xHwG0WIxGpZK80bSbC4y+92/f1alPop6D9SeWi1sMsbqzrk8KyD1eQrnq56ST2oe
10+
ZI0Hu41U9ZfabgiKSRMrHvmhLejK2ygcBpijAk4rMHVTEfKB8vaoCtF3t0TFgg2k
11+
MkliPU9hCkrr17aYZSw8R2HiTM8hqixm7GrTihZzGFUa+N4NHZEbVkLQpCnifBly
12+
1ZyNL03FDSBClYRGvp2W6qO8uUi3cQuXyfXhoeHZx5AW+pVsmmZsxhNnyeJwCDcU
13+
+WgxU9uNeHWEYwVg3fTP3LLgRhnVBr3UuYI4GtWBiQKBgQDhRC9cTlOG9SrgHPZT
14+
reZNDQ9hhrcb1kbo1yJBIHFTihv0UIS6S36PmN+OgshbF5+G8Y8fvJJ8vuzMpDfC
15+
GNR53F6DHH/bngv3lgws/6F0X41TrzOA6+MkA4D6s5uGscSODCGuxkwjuZuKQzwo
16+
zAhx8t6RX/w1k4uXFPfYgX5vBwKBgQDGDppVCyRGpijdAdXVmmiQz/7q9M6YdFDX
17+
53pt8CIdCfYiT3+iOwPqHAddQdwVewC3WrEZ7S3PdxpKgDDpYkJ0+NtHhlYdGLR9
18+
Ti6Cvmfc+r8yYnmEAqIXAeac5A4MYYTh+FadgtzqVPhp8Q61xkXFwajo/tV1EcSt
19+
/A+rC0XiewKBgQCqniBZA6JUJ8FvucAApUg3t9qcfZKW7PcMSFXTiiULpyGBLLM6
20+
/w8+6AT7RadHB192r+M9oHA7N8jXPtJUmsXj/rs/Bwj4aH6b6fQS6RN6txyt85dI
21+
4GFL17OLLxpvLJm5FQs1+0+UB3L9h+s64z7KP6+/4DmAwt4JcoI+Y+ZFZQKBgHbE
22+
YwAEgmhrU63UX+qLgZD1aaRz0T/S4HfYM66hhZNsWdERYzRht2M4E6J00AmBjVhm
23+
ZjVp6UKz5WwvmyUY60lBwh0ODa29Ft7ddz6n95ioNOd97eifu5uYZDZI+7Oo9wqa
24+
5TXnN5q+AYlmKLAQid6g1y2BQ3fEg/DhanPjerDpAoGBAM7Sm4E4UMOCzHFCHehh
25+
bTzfz8oNGpkWI+5UctXZOkzQ3YVtTwB/+b5nuG7D5EI8mRGHmhXerkM2uAmShmWl
26+
a9Xyo9nswhDjanBcji+ZWIXFqOodclK4/3VE+VnbzlZMqpGnxUl88wWeBXEualZ0
27+
Z3lq9DNf/Fywlcl69thCNXQs
28+
-----END PRIVATE KEY-----
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDUTCCAjmgAwIBAgIUapTwHjAOdsC1qQUcKRKprxW7GvswDQYJKoZIhvcNAQEL
3+
BQAwNzEjMCEGA1UEAwwaTm9kZUpTLVRlc3QtTm8tUmVzdWx0LVJvb3QxEDAOBgNV
4+
BAoMB05vZGUuanMwIBcNMjYwNDA0MTgzMjUyWhgPMjEyNjAzMTExODMyNTJaMDcx
5+
IzAhBgNVBAMMGk5vZGVKUy1UZXN0LU5vLVJlc3VsdC1Sb290MRAwDgYDVQQKDAdO
6+
b2RlLmpzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAomij2nGU2Lg0
7+
sD9OitlQlIAC6QEm3ziS8c3yX+wIhV/sZ/mRFt1cvFfIX7LFYl6zzDMI0Wgho422
8+
H9T4I5RRZ2Ms6IZ1e6+ERlqWDm3pS2nFglOR3AA1QUDt0pSfrtQjIc2yxeTMP7EO
9+
/LRZuGp1VOrR2kDP9JZC0+WLBBvtz/yFUICdrfDnm2d9b632Gl3CU/GiotMvt+oZ
10+
8J3WEh4y0vVdIwzMLV/jhoIgi0e9sZzSkB4ZmHCBOwl4asj8Yj8PS4q4AvXH2jms
11+
HmrsxUezsRrw9seccisexcC+akrJ4s1cqGXmi6MxqP3FO6yhSBdge6fMSNAETZ70
12+
qKL/Kk1t6QIDAQABo1MwUTAdBgNVHQ4EFgQULJNqn+YwH/flAsr8460+8ej1XQkw
13+
HwYDVR0jBBgwFoAULJNqn+YwH/flAsr8460+8ej1XQkwDwYDVR0TAQH/BAUwAwEB
14+
/zANBgkqhkiG9w0BAQsFAAOCAQEAMl8+Y1xRagBBKOluPcvTyV5BTleXLtF95wsj
15+
6SCTsSzmJiYQtBZA/pSoTS8+gEQb9hjN6dbYRDVY2pGyLrEVI/YE4zr4+Ug8vBXw
16+
UnZx4a76bUiT8iC7rBsqSeui7R56lbPQlxYjEKyX3oZgW9WzZ9NT3z9/u3mfTrW/
17+
TculuifSQHAi1X5r9IXFFABMyD8gDtQSfG+0e1E9KLyCMO3p8H/snz1hXIAUFnBD
18+
2b5QYiQRxUN2aO4PqJakxhDN844Vv6O+vQX618Fn+MqaL6qyPzJRo9qJe70/5xIu
19+
4Xs3ajp8Y3c5bb9vGtgLWsb3eUJ+AcZ2kttaBaIgiKqk4hTrDA==
20+
-----END CERTIFICATE-----
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCiaKPacZTYuDSw
3+
P06K2VCUgALpASbfOJLxzfJf7AiFX+xn+ZEW3Vy8V8hfssViXrPMMwjRaCGjjbYf
4+
1PgjlFFnYyzohnV7r4RGWpYObelLacWCU5HcADVBQO3SlJ+u1CMhzbLF5Mw/sQ78
5+
tFm4anVU6tHaQM/0lkLT5YsEG+3P/IVQgJ2t8OebZ31vrfYaXcJT8aKi0y+36hnw
6+
ndYSHjLS9V0jDMwtX+OGgiCLR72xnNKQHhmYcIE7CXhqyPxiPw9LirgC9cfaOawe
7+
auzFR7OxGvD2x5xyKx7FwL5qSsnizVyoZeaLozGo/cU7rKFIF2B7p8xI0ARNnvSo
8+
ov8qTW3pAgMBAAECggEAFFg1W7zqCh1GhGQ5y4zzhNa7BpiIAmMiN+Y2RtaDhBRY
9+
bKHyZJcwRxZcBG5EPvwMBo1yEla6uAlILO6kcu3hJf63dnK5hC1KzaFgC3NbS9Yh
10+
JsqfNUcAD3+PCy0RCnk1OXEnbut9ZpEghn7Kf8kzj4Km7RySBa/5CSBHwikEKQ85
11+
jO4dvtx0wDYbbvTrIcCKS74KoM10hioR3478m/6sx3sYau1bOUAUgvBBQc4WmdwJ
12+
Mxxz2ZqTQp4IyTGLIIS7vhyJLG9dcb1fapuMXjRYUn9i2ku9mbB+p/n514RLS+2W
13+
iS9IokYY2NwYv5Ue2cxvtmE5uVqx7Hkm4FEeFQJCHQKBgQDWLaT5mWRZaIMGyoas
14+
lmqqYM0gLlb9E9mxyPMc/BV9flV/8dTzSVarvGDJtefVQB4LHBOCXQYj9ZiqUsND
15+
5b7ZH/sVBNBfm/FR6rebKYXc0HOzhmCsoiuVSMRmpLZsWVpeX2BzCVJzES5ejm0o
16+
t3nGFzzLyOwWxrvp5zcGLwsNWwKBgQDCHyMHQ052QBujBs6PICd6pQ+VtcTSmXbX
17+
TUcUFptzdRRIZdnuM2r2ZhUcBV1RSrHFfpzeyMuTW1+sU4I+ggOeM15ui1XRJjHI
18+
FId6Ahj35QR/Jqrlyhde5g/xElY7/4Vlvw27DlrqrSa8QzsM32J8RoQB3SppuPlz
19+
lnZoB5uBCwKBgBuYbfUq6l8KtDcfyRJbnwqsxkErN1IMSLQ7a/eEE1DEAkgl5IYk
20+
IOKntuDGa0RyqmxMBcd6LNxdPHpVh4ssAtb+497la+OluAYR8+4t/21f/khXPAWC
21+
L5NgeM2w00BKkvYt28N2pATnZc4RE8d3PF1liRPIo4KbwIJ2pARL82SZAoGAW8cu
22+
33sx+HR83IoWVNLl93VctfJ3eP53knmF1niNzHuZOFV3QMhslMxUxKfAo/OFsxMW
23+
hbo3jZbQ1/+vf3Am17//sJIN49GEDc2u879UILfVdWxJtlTi0cpB1T9PKBS59A3t
24+
Jvg1geiVfMLog0CGJq2MMfln2Q5MWhrUJoEaQ1sCgYBGIrbT0Tpb/09w1qZ21kDk
25+
4iBAnKiy3KAeXlq3bVpfV+u/Ah6K7nvKIFtende/FoKFhiIu7YAFkOhIWRvBsRZ0
26+
KWt2rlHfjlk+iZN9NqaWQqfmUvemiuBxie7ddFmMJwK2YYmmSI1hnTQlVLHuqMs6
27+
fDfGqsm1Edj00rLA7f6ylg==
28+
-----END PRIVATE KEY-----

test/system-ca/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,34 @@ security add-certificates \
1818
security add-certificates \
1919
-k /Users/$USER/Library/Keychains/login.keychain-db \
2020
test/fixtures/keys/non-trusted-intermediate-ca.pem
21+
security add-trusted-cert \
22+
-k /Users/$USER/Library/Keychains/login.keychain-db \
23+
test/fixtures/keys/expired-root-cert.pem
24+
# Self-signed cert with trust settings that lack kSecTrustSettingsResult.
25+
security add-trusted-cert \
26+
-k /Users/$USER/Library/Keychains/login.keychain-db \
27+
test/fixtures/keys/selfsigned-no-result-root-cert.pem
28+
security trust-settings-export /tmp/node-trust-settings.plist
29+
CERT_SHA1=$(openssl x509 \
30+
-in test/fixtures/keys/selfsigned-no-result-root-cert.pem \
31+
-fingerprint -sha1 -noout | sed 's/.*=//;s/://g')
32+
/usr/libexec/PlistBuddy \
33+
-c "Delete :trustList:${CERT_SHA1}:trustSettings" \
34+
/tmp/node-trust-settings.plist
35+
/usr/libexec/PlistBuddy \
36+
-c "Add :trustList:${CERT_SHA1}:trustSettings array" \
37+
/tmp/node-trust-settings.plist
38+
/usr/libexec/PlistBuddy \
39+
-c "Add :trustList:${CERT_SHA1}:trustSettings:0 dict" \
40+
/tmp/node-trust-settings.plist
41+
security trust-settings-import /tmp/node-trust-settings.plist
42+
rm /tmp/node-trust-settings.plist
43+
# Duplicate cert in a second keychain
44+
security create-keychain -p "test" /tmp/node-test-dup.keychain
45+
security add-certificates \
46+
-k /tmp/node-test-dup.keychain \
47+
test/fixtures/keys/fake-startcom-root-cert.pem
48+
security list-keychains -d user -s login.keychain-db /tmp/node-test-dup.keychain
2149
```
2250

2351
**Removing the certificate**
@@ -29,6 +57,12 @@ security delete-certificate -c 'NodeJS-Test-Intermediate-CA' \
2957
-t /Users/$USER/Library/Keychains/login.keychain-db
3058
security delete-certificate -c 'NodeJS-Non-Trusted-Test-Intermediate-CA' \
3159
-t /Users/$USER/Library/Keychains/login.keychain-db
60+
security delete-certificate -c 'NodeJS-Test-Expired-Root' \
61+
-t /Users/$USER/Library/Keychains/login.keychain-db
62+
security delete-certificate -c 'NodeJS-Test-No-Result-Root' \
63+
-t /Users/$USER/Library/Keychains/login.keychain-db
64+
security list-keychains -d user -s login.keychain-db
65+
security delete-keychain /tmp/node-test-dup.keychain
3266
```
3367

3468
## Windows

0 commit comments

Comments
 (0)