Skip to content

Commit 5e5500c

Browse files
macartewangweij
authored andcommitted
6782021: It is not possible to read local computer certificates with the SunMSCAPI provider
Reviewed-by: weijun
1 parent d65fba4 commit 5e5500c

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

@@ -220,7 +235,12 @@ public void delete() throws KeyStoreException {
220235
*/
221236
private final String storeName;
222237

223-
CKeyStore(String storeName) {
238+
/*
239+
* The keystore location.
240+
*/
241+
private final int storeLocation;
242+
243+
CKeyStore(String storeName, int storeLocation) {
224244
// Get the compatibility mode
225245
@SuppressWarnings("removal")
226246
String prop = AccessController.doPrivileged(
@@ -233,6 +253,7 @@ public void delete() throws KeyStoreException {
233253
}
234254

235255
this.storeName = storeName;
256+
this.storeLocation = storeLocation;
236257
}
237258

238259
/**
@@ -259,7 +280,7 @@ public void delete() throws KeyStoreException {
259280
* @exception UnrecoverableKeyException if the key cannot be recovered.
260281
*/
261282
public java.security.Key engineGetKey(String alias, char[] password)
262-
throws NoSuchAlgorithmException, UnrecoverableKeyException {
283+
throws NoSuchAlgorithmException, UnrecoverableKeyException {
263284
if (alias == null) {
264285
return null;
265286
}
@@ -705,7 +726,7 @@ public void engineLoad(InputStream stream, char[] password)
705726
try {
706727

707728
// Load keys and/or certificate chains
708-
loadKeysOrCertificateChains(getName());
729+
loadKeysOrCertificateChains(getName(), getLocation());
709730

710731
} catch (KeyStoreException e) {
711732
throw new IOException(e);
@@ -801,7 +822,7 @@ private void generateKeyAndCertificateChain(boolean isRSA, String alias,
801822
* @param certCollection Collection of certificates.
802823
*/
803824
private void generateCertificate(byte[] data,
804-
Collection<Certificate> certCollection) {
825+
Collection<Certificate> certCollection) {
805826
try {
806827
ByteArrayInputStream bis = new ByteArrayInputStream(data);
807828

@@ -829,12 +850,20 @@ private String getName() {
829850
}
830851

831852
/**
832-
* Load keys and/or certificates from keystore into Collection.
853+
* Returns the location of the keystore.
854+
*/
855+
private int getLocation() {
856+
return storeLocation;
857+
}
858+
859+
/**
860+
* Loads keys and/or certificates from keystore into Collection.
833861
*
834862
* @param name Name of keystore.
863+
* @param location Location of keystore.
835864
*/
836-
private native void loadKeysOrCertificateChains(String name)
837-
throws KeyStoreException;
865+
private native void loadKeysOrCertificateChains(String name,
866+
int location) throws KeyStoreException;
838867

839868
/**
840869
* Stores a DER-encoded certificate into the certificate store
@@ -844,8 +873,8 @@ private native void loadKeysOrCertificateChains(String name)
844873
* @param encoding DER-encoded certificate.
845874
*/
846875
private native void storeCertificate(String name, String alias,
847-
byte[] encoding, int encodingLength, long hCryptProvider,
848-
long hCryptKey) throws CertificateException, KeyStoreException;
876+
byte[] encoding, int encodingLength, long hCryptProvider,
877+
long hCryptKey) throws CertificateException, KeyStoreException;
849878

850879
/**
851880
* Removes the certificate from the certificate store
@@ -855,7 +884,7 @@ private native void storeCertificate(String name, String alias,
855884
* @param encoding DER-encoded certificate.
856885
*/
857886
private native void removeCertificate(String name, String alias,
858-
byte[] encoding, int encodingLength)
887+
byte[] encoding, int encodingLength)
859888
throws CertificateException, KeyStoreException;
860889

861890
/**
@@ -864,7 +893,7 @@ private native void removeCertificate(String name, String alias,
864893
* @param keyContainerName The name of the key container.
865894
*/
866895
private native void destroyKeyContainer(String keyContainerName)
867-
throws KeyStoreException;
896+
throws KeyStoreException;
868897

869898
/**
870899
* Removes a CNG key.
@@ -877,16 +906,16 @@ private native void destroyKeyContainer(String keyContainerName)
877906
* Generates a private-key BLOB from a key's components.
878907
*/
879908
private native byte[] generateRSAPrivateKeyBlob(
880-
int keyBitLength,
881-
byte[] modulus,
882-
byte[] publicExponent,
883-
byte[] privateExponent,
884-
byte[] primeP,
885-
byte[] primeQ,
886-
byte[] exponentP,
887-
byte[] exponentQ,
888-
byte[] crtCoefficient) throws InvalidKeyException;
909+
int keyBitLength,
910+
byte[] modulus,
911+
byte[] publicExponent,
912+
byte[] privateExponent,
913+
byte[] primeP,
914+
byte[] primeQ,
915+
byte[] exponentP,
916+
byte[] exponentQ,
917+
byte[] crtCoefficient) throws InvalidKeyException;
889918

890919
private native CPrivateKey storePrivateKey(String alg, byte[] keyBlob,
891-
String keyContainerName, int keySize) throws KeyStoreException;
920+
String keyContainerName, int keySize) throws KeyStoreException;
892921
}

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)