Skip to content

Commit 96702ad

Browse files
committed
macOS: better intermediate cert assertions #3
1 parent 477763d commit 96702ad

File tree

1 file changed

+50
-35
lines changed

1 file changed

+50
-35
lines changed

src/test/java/org/jetbrains/nativecerts/mac/SecurityFrameworkUtilTest.java

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@
1414
import java.security.cert.X509Certificate;
1515
import java.util.Collections;
1616
import java.util.List;
17-
import java.util.stream.Collectors;
1817

1918
import static org.hamcrest.CoreMatchers.hasItem;
20-
import static org.hamcrest.CoreMatchers.is;
19+
import static org.hamcrest.CoreMatchers.not;
2120
import static org.hamcrest.MatcherAssert.assertThat;
22-
import static org.hamcrest.Matchers.greaterThan;
2321
import static org.jetbrains.nativecerts.NativeCertsTestUtil.ExitCodeHandling;
2422
import static org.jetbrains.nativecerts.NativeCertsTestUtil.combineLists;
2523
import static org.jetbrains.nativecerts.NativeCertsTestUtil.executeProcess;
@@ -30,8 +28,6 @@
3028
import static org.jetbrains.nativecerts.NativeCertsTestUtil.getTestCertificatePath;
3129
import static org.jetbrains.nativecerts.NativeCertsTestUtil.isManualTestingEnabled;
3230
import static org.jetbrains.nativecerts.NativeTrustedRootsInternalUtils.isMac;
33-
import static org.jetbrains.nativecerts.NativeTrustedRootsInternalUtils.sha1hex;
34-
import static org.jetbrains.nativecerts.NativeTrustedRootsInternalUtils.sha256hex;
3531
import static org.junit.Assert.assertEquals;
3632
import static org.junit.Assert.assertFalse;
3733
import static org.junit.Assert.assertTrue;
@@ -97,9 +93,16 @@ public void addRealUserTrustedCertificate_deny() throws Exception {
9793
public void supportForIntermediateCertificates() throws InterruptedException {
9894
Assume.assumeTrue(isManualTestingEnabled);
9995

100-
// add root cert
96+
Path intermediatePath = getCertificatePath("/mock-ca/intermediate-ca.pem");
97+
98+
// remove just in case it was not cleaned up before
99+
removeTrustedCert(getTestCertificatePath());
100+
deleteCert("JVM-NATIVE-TRUSTED-ROOTS-MOCK-INTERMEDIATE-CA");
101+
101102
try {
102103
Path loginKeyChain = Path.of(System.getProperty("user.home"), "Library/Keychains/login.keychain-db");
104+
105+
// add root cert
103106
List<String> args = List.of(
104107
"/usr/bin/security",
105108
"add-trusted-cert",
@@ -111,33 +114,31 @@ public void supportForIntermediateCertificates() throws InterruptedException {
111114
Thread.sleep(2000L);
112115

113116
// add intermediate cert
114-
args = List.of(
115-
"/usr/bin/security",
116-
"add-certificates",
117-
"-k", loginKeyChain.toString(),
118-
getCertificatePath("/mock-ca/intermediate-ca.pem").toString()
119-
);
120-
executeProcess(args);
117+
addCertificate(loginKeyChain, intermediatePath);
121118

122-
// verify certs are trusted
123-
List<X509Certificate> rootsAfter = SecurityFrameworkUtil.getTrustedRoots(SecurityFramework.SecTrustSettingsDomain.user);
119+
// verify both certs are trusted
120+
List<X509Certificate> afterAdd = SecurityFrameworkUtil.getTrustedRoots(SecurityFramework.SecTrustSettingsDomain.user);
121+
List<String> afterAddAliases = afterAdd.stream().map(crt -> crt.getSubjectX500Principal().toString()).toList();
122+
assertThat(afterAddAliases, hasItem("CN=JVM-NATIVE-TRUSTED-ROOTS-MOCK-CA, O=JETBRAINS"));
123+
assertThat(afterAddAliases, hasItem("CN=JVM-NATIVE-TRUSTED-ROOTS-MOCK-INTERMEDIATE-CA, O=JETBRAINS"));
124+
assertTrue(verifyCert(intermediatePath, null));
125+
assertTrue(verifyCert(getTestCertificatePath(), null));
126+
127+
// remove root cert. Both root and intermediate should disappear
128+
assertTrue(removeTrustedCert(getTestCertificatePath()));
129+
assertFalse(verifyCert(intermediatePath, null));
130+
assertFalse(verifyCert(getTestCertificatePath(), null));
124131

125-
List<String> aliases = rootsAfter.stream().map(crt -> crt.getSubjectX500Principal().toString())
126-
.collect(Collectors.toList());
127-
assertThat(aliases, hasItem("CN=JVM-NATIVE-TRUSTED-ROOTS-MOCK-CA, O=JETBRAINS"));
128-
assertThat(aliases.size(), is(greaterThan(1)));
129-
assertThat(aliases, hasItem("CN=JVM-NATIVE-TRUSTED-ROOTS-MOCK-INTERMEDIATE-CA, O=JETBRAINS"));
132+
List<X509Certificate> afterRootRemoval = SecurityFrameworkUtil.getTrustedRoots(SecurityFramework.SecTrustSettingsDomain.user);
133+
List<String> afterRootRemovalAliases = afterRootRemoval.stream().map(crt -> crt.getSubjectX500Principal().toString()).toList();
134+
assertThat(afterRootRemovalAliases, not(hasItem("CN=JVM-NATIVE-TRUSTED-ROOTS-MOCK-CA, O=JETBRAINS")));
135+
assertThat(afterRootRemovalAliases, not(hasItem("CN=JVM-NATIVE-TRUSTED-ROOTS-MOCK-INTERMEDIATE-CA, O=JETBRAINS")));
136+
137+
// assert cleanup
138+
assertTrue(deleteCert("JVM-NATIVE-TRUSTED-ROOTS-MOCK-INTERMEDIATE-CA"));
130139
} finally {
131140
removeTrustedCert(getTestCertificatePath());
132-
133-
executeProcess(
134-
List.of(
135-
"/usr/bin/security",
136-
"delete-certificate",
137-
"-c", "JVM-NATIVE-TRUSTED-ROOTS-MOCK-INTERMEDIATE-CA",
138-
"-t"
139-
)
140-
);
141+
deleteCert("JVM-NATIVE-TRUSTED-ROOTS-MOCK-INTERMEDIATE-CA");
141142
}
142143
}
143144

@@ -149,12 +150,6 @@ private void customUserTrustedCertificateTest(@Nullable String policy, String re
149150
Path loginKeyChain = Path.of(System.getProperty("user.home"), "Library/Keychains/login.keychain-db");
150151
assertTrue(Files.isRegularFile(loginKeyChain));
151152

152-
byte[] encoded = getTestCertificate().getEncoded();
153-
String sha1 = sha1hex(encoded);
154-
String sha256 = sha256hex(encoded);
155-
assertEquals("c1969052bc9a106a8a7997b84913e1530215ac45", sha1);
156-
assertEquals("63609373bf25769df2a6e64378872d9d2697c48b53408dd1d0e38b2db4397fc6", sha256);
157-
158153
// cleanup just in case it was imported before
159154
removeTrustedCert(getTestCertificatePath());
160155

@@ -224,4 +219,24 @@ private static boolean removeTrustedCert(Path cert) {
224219
int rc = executeProcessAndGetExitCode(List.of("/usr/bin/security", "remove-trusted-cert", cert.toAbsolutePath().toString()));
225220
return rc == 0;
226221
}
222+
223+
private static void addCertificate(Path loginKeyChain, Path certificatePath) {
224+
executeProcess(List.of(
225+
"/usr/bin/security",
226+
"add-certificates",
227+
"-k", loginKeyChain.toString(),
228+
certificatePath.toString()
229+
));
230+
}
231+
232+
private static boolean deleteCert(String commonName) {
233+
int rc = executeProcessAndGetExitCode(List.of(
234+
"/usr/bin/security",
235+
"delete-certificate",
236+
"-c", commonName,
237+
// Also delete user trust settings for this certificate
238+
"-t"
239+
));
240+
return rc == 0;
241+
}
227242
}

0 commit comments

Comments
 (0)