Skip to content
This repository was archived by the owner on Sep 19, 2023. It is now read-only.
/ jdk21 Public archive

Commit 82c8b28

Browse files
committedJul 12, 2023
8156889: ListKeychainStore.sh fails in some virtualized environments
Reviewed-by: mullan Backport-of: 119cc495fc6c18a29b7484d294c31ad1d478791c
1 parent 72cf3c9 commit 82c8b28

File tree

4 files changed

+202
-247
lines changed

4 files changed

+202
-247
lines changed
 

‎test/jdk/ProblemList.txt

-2
Original file line numberDiff line numberDiff line change
@@ -579,8 +579,6 @@ com/sun/nio/sctp/SctpChannel/SocketOptionTests.java 8141694 linux-al
579579

580580
sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8161536 generic-all
581581

582-
sun/security/tools/keytool/ListKeychainStore.sh 8156889 macosx-all
583-
584582
sun/security/smartcardio/TestChannel.java 8039280 generic-all
585583
sun/security/smartcardio/TestConnect.java 8039280 generic-all
586584
sun/security/smartcardio/TestConnectAgain.java 8039280 generic-all

‎test/jdk/sun/security/tools/keytool/ExportPrivateKeyNoPwd.java

-57
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
* Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 7133495 8062264 8046777 8153005
27+
* @summary KeyChain KeyStore implementation retrieves only one private key entry
28+
* @requires (os.family == "mac")
29+
* @library /test/lib
30+
* @run main/othervm/manual ListKeyChainStore
31+
*/
32+
33+
import jdk.test.lib.SecurityTools;
34+
import jdk.test.lib.process.ProcessTools;
35+
36+
import java.io.*;
37+
import java.nio.file.Files;
38+
import java.nio.file.Paths;
39+
import java.security.Key;
40+
import java.security.KeyStore;
41+
import java.security.PrivateKey;
42+
43+
public class ListKeyChainStore {
44+
private static final String PWD = "xxxxxx";
45+
private static final String DEFAULT_KEYTOOL = "-list -storetype KeychainStore " +
46+
"-keystore NONE -storepass " + PWD;
47+
private static final String USER_DIR = System.getProperty("user.dir", ".");
48+
private static final String FS = System.getProperty("file.separator");
49+
private static final String PKCS12_KEYSTORE = USER_DIR + FS + "7133495.p12";
50+
private static final String KEYCHAIN_FILE = USER_DIR + FS + "7133495.keychain";
51+
private static final String TEMPORARY_FILE = USER_DIR + FS + "7133495.tmp";
52+
private static final String USER_KEYCHAIN_LIST = USER_DIR + FS + "user.keychain.list";
53+
private static final String PRIVATE_KEY_ENTRY = "PrivateKeyEntry";
54+
55+
public static void main(String[] args) throws Throwable {
56+
LOG_MSG("WARNING: This test doesn't work on macOS virtualized environment. " +
57+
"`security list-keychains -s` doesn't update the search order.");
58+
59+
deleteTestTempFilesIfExists();
60+
61+
// Get the old security keychain list to restore later
62+
try (PrintStream printStream = new PrintStream(USER_KEYCHAIN_LIST)) {
63+
ProcessTools.executeCommand("sh", "-c", "security list-keychains")
64+
.shouldHaveExitValue(0).outputTo(printStream);
65+
}
66+
67+
try {
68+
try (PrintStream printStream = new PrintStream(TEMPORARY_FILE)) {
69+
SecurityTools.keytool(DEFAULT_KEYTOOL).shouldHaveExitValue(0)
70+
.outputTo(printStream);
71+
}
72+
int oldPrivateKeyCount = countOccurrences(TEMPORARY_FILE, PRIVATE_KEY_ENTRY);
73+
LOG_MSG("Found " + oldPrivateKeyCount + " private key entries in the " +
74+
"Keychain keystore");
75+
76+
// Create the PKCS12 keystore containing 3 public/private key pairs
77+
LOG_MSG("Creating PKCS12 keystore: " + PKCS12_KEYSTORE);
78+
for (int i = 0; i < 3; i++) {
79+
// Use legacy encryption and MAC algorithms, refer macOS open radar FB8988319
80+
// macOS security framework doesn't work with the latest algorithms
81+
SecurityTools.keytool(String.format("-J-Dkeystore.pkcs12.legacy -genkeypair" +
82+
" -storetype PKCS12 -keystore %s -storepass %s -keyalg rsa -dname " +
83+
"CN=CN%d,OU=OU%d,O=O%d,ST=ST%d,C=US -alias 7133495-%d",
84+
PKCS12_KEYSTORE, PWD, i, i, i, i, i)).shouldHaveExitValue(0);
85+
}
86+
87+
// Create the keychain
88+
LOG_MSG("Creating keychain: " + KEYCHAIN_FILE);
89+
ProcessTools.executeCommand("sh", "-c", String.format("security create-keychain" +
90+
" -p %s %s", PWD, KEYCHAIN_FILE)).shouldHaveExitValue(0);
91+
92+
// Unlock the keychain
93+
LOG_MSG("Unlock keychain: " + KEYCHAIN_FILE);
94+
ProcessTools.executeCommand("sh", "-c", String.format("security unlock-keychain" +
95+
" -p %s %s", PWD, KEYCHAIN_FILE)).shouldHaveExitValue(0);
96+
97+
// Import the key pairs from the PKCS12 keystore into the keychain
98+
// The '-A' option is used to lower the keychain's access controls
99+
LOG_MSG("Importing the key pairs from " + PKCS12_KEYSTORE
100+
+ " to " + KEYCHAIN_FILE);
101+
ProcessTools.executeCommand("sh", "-c", String.format("security import %s -k %s" +
102+
" -f pkcs12 -P %s -A", PKCS12_KEYSTORE, KEYCHAIN_FILE, PWD)).shouldHaveExitValue(0);
103+
104+
// Generate a 2048-bit RSA keypair and import into the keychain
105+
// Its private key is configured with non-default key usage settings
106+
ProcessTools.executeCommand("sh", "-c", String.format("certtool ca k=%s " +
107+
"<<EOF\n" +
108+
"test\n" +
109+
"r\n" +
110+
"2048\n" +
111+
"y\n" +
112+
"b\n" +
113+
"s\n" +
114+
"y\n" +
115+
"A\n" +
116+
"US\n" +
117+
"A\n" +
118+
"A\n" +
119+
"\n" +
120+
"\n" +
121+
"y\n" +
122+
"EOF", KEYCHAIN_FILE)).shouldHaveExitValue(0);
123+
124+
// Adjust the keychain search order to add KEYCHAIN_FILE to top
125+
try (PrintStream printStream = new PrintStream(TEMPORARY_FILE)) {
126+
printStream.println("\"" + KEYCHAIN_FILE + "\"");
127+
printStream.println(ProcessTools.executeCommand("sh", "-c", "security list-keychains")
128+
.shouldHaveExitValue(0).getOutput());
129+
}
130+
ProcessTools.executeCommand("sh", "-c", String.format("security list-keychains -s %s",
131+
ProcessTools.executeCommand("sh", "-c", String.format("xargs < %s",
132+
TEMPORARY_FILE)).getOutput()));
133+
LOG_MSG("Keychain search order:");
134+
ProcessTools.executeCommand("sh", "-c", "security list-keychains");
135+
136+
// Recount the number of private key entries in the Keychain keystore
137+
// 3 private keys imported from PKCS12, 1 private key generated by 'certtool'
138+
Files.deleteIfExists(Paths.get(TEMPORARY_FILE));
139+
try (PrintStream printStream = new PrintStream(TEMPORARY_FILE)) {
140+
SecurityTools.keytool(DEFAULT_KEYTOOL).shouldHaveExitValue(0)
141+
.outputTo(printStream);
142+
}
143+
int newPrivateKeyCount = countOccurrences(TEMPORARY_FILE, PRIVATE_KEY_ENTRY);
144+
LOG_MSG("Found " + newPrivateKeyCount + " private key entries in " +
145+
"the Keychain keystore");
146+
if (newPrivateKeyCount < (oldPrivateKeyCount + 4)) {
147+
throw new RuntimeException("Error: expected more private key entries in the " +
148+
"Keychain keystore");
149+
}
150+
151+
// Export a private key from the keychain (without supplying a password)
152+
// Access controls have already been lowered (see 'security import ... -A' above)
153+
LOG_MSG("Exporting a private key from the keychain");
154+
KeyStore ks = KeyStore.getInstance("KeychainStore");
155+
ks.load(null, null);
156+
Key key = ks.getKey("CN0", null);
157+
if (key instanceof PrivateKey) {
158+
LOG_MSG("Exported " + key.getAlgorithm() + " private key from CN0");
159+
} else {
160+
throw new RuntimeException("Error exporting private key from keychain");
161+
}
162+
} finally {
163+
// Reset earlier keychain list
164+
ProcessTools.executeCommand("sh", "-c", String.format("security list-keychains -s %s",
165+
ProcessTools.executeCommand("sh", "-c", String.format("xargs < %s",
166+
USER_KEYCHAIN_LIST)).getOutput()));
167+
168+
deleteTestTempFilesIfExists();
169+
}
170+
}
171+
172+
private static void deleteTestTempFilesIfExists() throws Throwable {
173+
Files.deleteIfExists(Paths.get(USER_KEYCHAIN_LIST));
174+
Files.deleteIfExists(Paths.get(PKCS12_KEYSTORE));
175+
if (Files.exists(Paths.get(KEYCHAIN_FILE))) {
176+
ProcessTools.executeCommand("sh", "-c", String.format("security delete-keychain" +
177+
" %s", KEYCHAIN_FILE)).shouldHaveExitValue(0);
178+
}
179+
Files.deleteIfExists(Paths.get(TEMPORARY_FILE));
180+
}
181+
182+
private static int countOccurrences(String filePath, String word) throws IOException {
183+
int count = 0;
184+
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
185+
String line;
186+
while ((line = reader.readLine()) != null) {
187+
if (line.contains(word)) {
188+
count++;
189+
}
190+
}
191+
}
192+
193+
return count;
194+
}
195+
196+
private static void LOG_MSG(String msg) {
197+
// ProcessTools and SecurityTools log a lot of messages so pretty format
198+
// messages logged from this test
199+
System.out.println();
200+
System.out.println("==> " + msg);
201+
}
202+
}

‎test/jdk/sun/security/tools/keytool/ListKeychainStore.sh

-188
This file was deleted.

1 commit comments

Comments
 (1)

openjdk-notifier[bot] commented on Jul 12, 2023

@openjdk-notifier[bot]
This repository has been archived.