Skip to content

Commit 52b3b14

Browse files
kariannaRealCLanger
authored andcommitted
6782021: It is not possible to read local computer certificates with the SunMSCAPI provider
Backport-of: 5e5500cbd79b40a32c20547ea0cdb81ef6904a3d
1 parent c12d5a8 commit 52b3b14

File tree

5 files changed

+186
-32
lines changed

5 files changed

+186
-32
lines changed

src/java.base/share/classes/sun/security/tools/KeyStoreUtil.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,11 @@ public static boolean signedBy(X509Certificate end, X509Certificate ca) {
9191
public static boolean isWindowsKeyStore(String storetype) {
9292
return storetype != null
9393
&& (storetype.equalsIgnoreCase("Windows-MY")
94-
|| storetype.equalsIgnoreCase("Windows-ROOT"));
94+
|| storetype.equalsIgnoreCase("Windows-ROOT")
95+
|| storetype.equalsIgnoreCase("Windows-MY-CURRENTUSER")
96+
|| storetype.equalsIgnoreCase("Windows-ROOT-CURRENTUSER")
97+
|| storetype.equalsIgnoreCase("Windows-MY-LOCALMACHINE")
98+
|| storetype.equalsIgnoreCase("Windows-ROOT-LOCALMACHINE"));
9599
}
96100

97101
/**
@@ -102,6 +106,14 @@ public static String niceStoreTypeName(String storetype) {
102106
return "Windows-MY";
103107
} else if(storetype.equalsIgnoreCase("Windows-ROOT")) {
104108
return "Windows-ROOT";
109+
} else if(storetype.equalsIgnoreCase("Windows-MY-CURRENTUSER")) {
110+
return "Windows-MY-CURRENTUSER";
111+
} else if(storetype.equalsIgnoreCase("Windows-ROOT-CURRENTUSER")) {
112+
return "Windows-ROOT-CURRENTUSER";
113+
} else if(storetype.equalsIgnoreCase("Windows-MY-LOCALMACHINE")) {
114+
return "Windows-MY-LOCALMACHINE";
115+
} else if(storetype.equalsIgnoreCase("Windows-ROOT-LOCALMACHINE")) {
116+
return "Windows-ROOT-LOCALMACHINE";
105117
} else {
106118
return storetype.toUpperCase(Locale.ENGLISH);
107119
}

src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKeyStore.java

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,30 @@
5454
*/
5555
abstract class CKeyStore extends KeyStoreSpi {
5656

57+
private static final int LOCATION_CURRENTUSER = 0;
58+
private static final int LOCATION_LOCALMACHINE = 1;
59+
5760
public static final class MY extends CKeyStore {
5861
public MY() {
59-
super("MY");
62+
super("MY", LOCATION_CURRENTUSER);
6063
}
6164
}
6265

6366
public static final class ROOT extends CKeyStore {
6467
public ROOT() {
65-
super("ROOT");
68+
super("ROOT", LOCATION_CURRENTUSER);
69+
}
70+
}
71+
72+
public static final class MYLocalMachine extends CKeyStore {
73+
public MYLocalMachine() {
74+
super("MY", LOCATION_LOCALMACHINE);
75+
}
76+
}
77+
78+
public static final class ROOTLocalMachine extends CKeyStore {
79+
public ROOTLocalMachine() {
80+
super("ROOT", LOCATION_LOCALMACHINE);
6681
}
6782
}
6883

@@ -197,7 +212,12 @@ void setCertificateChain(X509Certificate[] chain)
197212
*/
198213
private final String storeName;
199214

200-
CKeyStore(String storeName) {
215+
/*
216+
* The keystore location.
217+
*/
218+
private final int storeLocation;
219+
220+
CKeyStore(String storeName, int storeLocation) {
201221
// Get the compatibility mode
202222
@SuppressWarnings("removal")
203223
String prop = AccessController.doPrivileged(
@@ -210,6 +230,7 @@ void setCertificateChain(X509Certificate[] chain)
210230
}
211231

212232
this.storeName = storeName;
233+
this.storeLocation = storeLocation;
213234
}
214235

215236
/**
@@ -236,7 +257,7 @@ void setCertificateChain(X509Certificate[] chain)
236257
* @exception UnrecoverableKeyException if the key cannot be recovered.
237258
*/
238259
public java.security.Key engineGetKey(String alias, char[] password)
239-
throws NoSuchAlgorithmException, UnrecoverableKeyException {
260+
throws NoSuchAlgorithmException, UnrecoverableKeyException {
240261
if (alias == null) {
241262
return null;
242263
}
@@ -710,7 +731,7 @@ public void engineLoad(InputStream stream, char[] password)
710731
try {
711732

712733
// Load keys and/or certificate chains
713-
loadKeysOrCertificateChains(getName());
734+
loadKeysOrCertificateChains(getName(), getLocation());
714735

715736
} catch (KeyStoreException e) {
716737
throw new IOException(e);
@@ -806,7 +827,7 @@ private void generateKeyAndCertificateChain(boolean isRSA, String alias,
806827
* @param certCollection Collection of certificates.
807828
*/
808829
private void generateCertificate(byte[] data,
809-
Collection<Certificate> certCollection) {
830+
Collection<Certificate> certCollection) {
810831
try {
811832
ByteArrayInputStream bis = new ByteArrayInputStream(data);
812833

@@ -840,12 +861,20 @@ private String getName() {
840861
}
841862

842863
/**
843-
* Load keys and/or certificates from keystore into Collection.
864+
* Returns the location of the keystore.
865+
*/
866+
private int getLocation() {
867+
return storeLocation;
868+
}
869+
870+
/**
871+
* Loads keys and/or certificates from keystore into Collection.
844872
*
845873
* @param name Name of keystore.
874+
* @param location Location of keystore.
846875
*/
847-
private native void loadKeysOrCertificateChains(String name)
848-
throws KeyStoreException;
876+
private native void loadKeysOrCertificateChains(String name,
877+
int location) throws KeyStoreException;
849878

850879
/**
851880
* Stores a DER-encoded certificate into the certificate store
@@ -855,8 +884,8 @@ private native void loadKeysOrCertificateChains(String name)
855884
* @param encoding DER-encoded certificate.
856885
*/
857886
private native void storeCertificate(String name, String alias,
858-
byte[] encoding, int encodingLength, long hCryptProvider,
859-
long hCryptKey) throws CertificateException, KeyStoreException;
887+
byte[] encoding, int encodingLength, long hCryptProvider,
888+
long hCryptKey) throws CertificateException, KeyStoreException;
860889

861890
/**
862891
* Removes the certificate from the certificate store
@@ -866,7 +895,7 @@ private native void storeCertificate(String name, String alias,
866895
* @param encoding DER-encoded certificate.
867896
*/
868897
private native void removeCertificate(String name, String alias,
869-
byte[] encoding, int encodingLength)
898+
byte[] encoding, int encodingLength)
870899
throws CertificateException, KeyStoreException;
871900

872901
/**
@@ -875,22 +904,22 @@ private native void removeCertificate(String name, String alias,
875904
* @param keyContainerName The name of the key container.
876905
*/
877906
private native void destroyKeyContainer(String keyContainerName)
878-
throws KeyStoreException;
907+
throws KeyStoreException;
879908

880909
/**
881910
* Generates a private-key BLOB from a key's components.
882911
*/
883912
private native byte[] generateRSAPrivateKeyBlob(
884-
int keyBitLength,
885-
byte[] modulus,
886-
byte[] publicExponent,
887-
byte[] privateExponent,
888-
byte[] primeP,
889-
byte[] primeQ,
890-
byte[] exponentP,
891-
byte[] exponentQ,
892-
byte[] crtCoefficient) throws InvalidKeyException;
913+
int keyBitLength,
914+
byte[] modulus,
915+
byte[] publicExponent,
916+
byte[] privateExponent,
917+
byte[] primeP,
918+
byte[] primeQ,
919+
byte[] exponentP,
920+
byte[] exponentQ,
921+
byte[] crtCoefficient) throws InvalidKeyException;
893922

894923
private native CPrivateKey storePrivateKey(String alg, byte[] keyBlob,
895-
String keyContainerName, int keySize) throws KeyStoreException;
924+
String keyContainerName, int keySize) throws KeyStoreException;
896925
}

src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,14 @@ public Object newInstance(Object ctrParamObj)
9191
return new PRNG();
9292
}
9393
} else if (type.equals("KeyStore")) {
94-
if (algo.equals("Windows-MY")) {
94+
if (algo.equals("Windows-MY") || algo.equals("Windows-MY-CURRENTUSER")) {
9595
return new CKeyStore.MY();
96-
} else if (algo.equals("Windows-ROOT")) {
96+
} else if (algo.equals("Windows-ROOT") || algo.equals("Windows-ROOT-CURRENTUSER")) {
9797
return new CKeyStore.ROOT();
98+
} else if (algo.equals("Windows-MY-LOCALMACHINE")) {
99+
return new CKeyStore.MYLocalMachine();
100+
} else if (algo.equals("Windows-ROOT-LOCALMACHINE")) {
101+
return new CKeyStore.ROOTLocalMachine();
98102
}
99103
} else if (type.equals("Signature")) {
100104
if (algo.equals("NONEwithRSA")) {
@@ -165,8 +169,16 @@ public Void run() {
165169
*/
166170
putService(new ProviderService(p, "KeyStore",
167171
"Windows-MY", "sun.security.mscapi.CKeyStore$MY"));
172+
putService(new ProviderService(p, "KeyStore",
173+
"Windows-MY-CURRENTUSER", "sun.security.mscapi.CKeyStore$MY"));
168174
putService(new ProviderService(p, "KeyStore",
169175
"Windows-ROOT", "sun.security.mscapi.CKeyStore$ROOT"));
176+
putService(new ProviderService(p, "KeyStore",
177+
"Windows-ROOT-CURRENTUSER", "sun.security.mscapi.CKeyStore$ROOT"));
178+
putService(new ProviderService(p, "KeyStore",
179+
"Windows-MY-LOCALMACHINE", "sun.security.mscapi.CKeyStore$MYLocalMachine"));
180+
putService(new ProviderService(p, "KeyStore",
181+
"Windows-ROOT-LOCALMACHINE", "sun.security.mscapi.CKeyStore$ROOTLocalMachine"));
170182

171183
/*
172184
* Signature engines

src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
#define SIGNATURE_EXCEPTION "java/security/SignatureException"
6060
#define OUT_OF_MEMORY_ERROR "java/lang/OutOfMemoryError"
6161

62+
#define KEYSTORE_LOCATION_CURRENTUSER 0
63+
#define KEYSTORE_LOCATION_LOCALMACHINE 1
64+
6265
#define SS_CHECK(Status) \
6366
if (Status != ERROR_SUCCESS) { \
6467
ThrowException(env, SIGNATURE_EXCEPTION, Status); \
@@ -386,10 +389,10 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed
386389
/*
387390
* Class: sun_security_mscapi_CKeyStore
388391
* Method: loadKeysOrCertificateChains
389-
* Signature: (Ljava/lang/String;)V
392+
* Signature: (Ljava/lang/String;I)V
390393
*/
391394
JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateChains
392-
(JNIEnv *env, jobject obj, jstring jCertStoreName)
395+
(JNIEnv *env, jobject obj, jstring jCertStoreName, jint jCertStoreLocation)
393396
{
394397
/**
395398
* Certificate in cert store has enhanced key usage extension
@@ -407,16 +410,27 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
407410
char* pszNameString = NULL; // certificate's friendly name
408411
DWORD cchNameString = 0;
409412

410-
411413
__try
412414
{
413415
// Open a system certificate store.
414416
if ((pszCertStoreName = env->GetStringUTFChars(jCertStoreName, NULL))
415417
== NULL) {
416418
__leave;
417419
}
418-
if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName))
419-
== NULL) {
420+
421+
if (jCertStoreLocation == KEYSTORE_LOCATION_CURRENTUSER) {
422+
hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName);
423+
}
424+
else if (jCertStoreLocation == KEYSTORE_LOCATION_LOCALMACHINE) {
425+
hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, NULL,
426+
CERT_SYSTEM_STORE_LOCAL_MACHINE, pszCertStoreName);
427+
}
428+
else {
429+
PP("jCertStoreLocation is not a valid value");
430+
__leave;
431+
}
432+
433+
if (hCertStore == NULL) {
420434

421435
ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
422436
__leave;
@@ -469,7 +483,7 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
469483
PP("--------------------------");
470484
// Check if private key available - client authentication certificate
471485
// must have private key available.
472-
HCRYPTPROV hCryptProv = NULL;
486+
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv = NULL;
473487
DWORD dwKeySpec = 0;
474488
HCRYPTKEY hUserKey = NULL;
475489
BOOL bCallerFreeProv = FALSE;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* Copyright (c) 2022, 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+
import jdk.test.lib.Asserts;
25+
import jdk.test.lib.SecurityTools;
26+
27+
import java.io.IOException;
28+
import java.security.KeyStore;
29+
import java.security.KeyStoreException;
30+
import java.util.Collections;
31+
import java.util.List;
32+
import java.util.Locale;
33+
34+
/*
35+
* @test
36+
* @bug 6782021
37+
* @requires os.family == "windows"
38+
* @library /test/lib
39+
* @summary More keystore types
40+
*/
41+
public class AllTypes {
42+
43+
public static void main(String[] args) throws Exception {
44+
var nm = test("windows-my");
45+
var nr = test("windows-root");
46+
var nmu = test("windows-my-currentuser");
47+
var nru = test("windows-root-currentuser");
48+
var hasAdminPrivileges = detectIfRunningWithAdminPrivileges();
49+
var nmm = adminTest("windows-my-localmachine", hasAdminPrivileges);
50+
var nrm = adminTest("windows-root-localmachine", hasAdminPrivileges);
51+
Asserts.assertEQ(nm, nmu);
52+
Asserts.assertEQ(nr, nru);
53+
}
54+
55+
private static boolean detectIfRunningWithAdminPrivileges() {
56+
try {
57+
Process p = Runtime.getRuntime().exec("reg query \"HKU\\S-1-5-19\"");
58+
p.waitFor();
59+
return (p.exitValue() == 0);
60+
}
61+
catch (Exception ex) {
62+
System.out.println("Warning: unable to detect admin privileges, assuming none");
63+
return false;
64+
}
65+
}
66+
67+
private static List<String> adminTest(String type, boolean hasAdminPrivileges) throws Exception {
68+
if (hasAdminPrivileges) {
69+
return test(type);
70+
}
71+
System.out.println("Ignoring: " + type + " as it requires admin privileges");
72+
return null;
73+
}
74+
75+
private static List<String> test(String type) throws Exception {
76+
var stdType = "Windows-" + type.substring(8).toUpperCase(Locale.ROOT);
77+
SecurityTools.keytool("-storetype " + type + " -list")
78+
.shouldHaveExitValue(0)
79+
.shouldContain("Keystore provider: SunMSCAPI")
80+
.shouldContain("Keystore type: " + stdType);
81+
KeyStore ks = KeyStore.getInstance(type);
82+
ks.load(null, null);
83+
var content = Collections.list(ks.aliases());
84+
Collections.sort(content);
85+
return content;
86+
}
87+
}

0 commit comments

Comments
 (0)