6782021: It is not possible to read local computer certificates with the SunMSCAPI provider

Reviewed-by: weijun
This commit is contained in:
Mat Carter 2022-05-17 02:41:36 +00:00 committed by Weijun Wang
parent d65fba412e
commit 5e5500cbd7
5 changed files with 186 additions and 32 deletions
src
java.base/share/classes/sun/security/tools
jdk.crypto.mscapi/windows
classes/sun/security/mscapi
native/libsunmscapi
test/jdk/sun/security/mscapi

@ -91,7 +91,11 @@ public class KeyStoreUtil {
public static boolean isWindowsKeyStore(String storetype) {
return storetype != null
&& (storetype.equalsIgnoreCase("Windows-MY")
|| storetype.equalsIgnoreCase("Windows-ROOT"));
|| storetype.equalsIgnoreCase("Windows-ROOT")
|| storetype.equalsIgnoreCase("Windows-MY-CURRENTUSER")
|| storetype.equalsIgnoreCase("Windows-ROOT-CURRENTUSER")
|| storetype.equalsIgnoreCase("Windows-MY-LOCALMACHINE")
|| storetype.equalsIgnoreCase("Windows-ROOT-LOCALMACHINE"));
}
/**
@ -102,6 +106,14 @@ public class KeyStoreUtil {
return "Windows-MY";
} else if(storetype.equalsIgnoreCase("Windows-ROOT")) {
return "Windows-ROOT";
} else if(storetype.equalsIgnoreCase("Windows-MY-CURRENTUSER")) {
return "Windows-MY-CURRENTUSER";
} else if(storetype.equalsIgnoreCase("Windows-ROOT-CURRENTUSER")) {
return "Windows-ROOT-CURRENTUSER";
} else if(storetype.equalsIgnoreCase("Windows-MY-LOCALMACHINE")) {
return "Windows-MY-LOCALMACHINE";
} else if(storetype.equalsIgnoreCase("Windows-ROOT-LOCALMACHINE")) {
return "Windows-ROOT-LOCALMACHINE";
} else {
return storetype.toUpperCase(Locale.ENGLISH);
}

@ -54,15 +54,30 @@ import sun.security.util.Debug;
*/
abstract class CKeyStore extends KeyStoreSpi {
private static final int LOCATION_CURRENTUSER = 0;
private static final int LOCATION_LOCALMACHINE = 1;
public static final class MY extends CKeyStore {
public MY() {
super("MY");
super("MY", LOCATION_CURRENTUSER);
}
}
public static final class ROOT extends CKeyStore {
public ROOT() {
super("ROOT");
super("ROOT", LOCATION_CURRENTUSER);
}
}
public static final class MYLocalMachine extends CKeyStore {
public MYLocalMachine() {
super("MY", LOCATION_LOCALMACHINE);
}
}
public static final class ROOTLocalMachine extends CKeyStore {
public ROOTLocalMachine() {
super("ROOT", LOCATION_LOCALMACHINE);
}
}
@ -220,7 +235,12 @@ abstract class CKeyStore extends KeyStoreSpi {
*/
private final String storeName;
CKeyStore(String storeName) {
/*
* The keystore location.
*/
private final int storeLocation;
CKeyStore(String storeName, int storeLocation) {
// Get the compatibility mode
@SuppressWarnings("removal")
String prop = AccessController.doPrivileged(
@ -233,6 +253,7 @@ abstract class CKeyStore extends KeyStoreSpi {
}
this.storeName = storeName;
this.storeLocation = storeLocation;
}
/**
@ -259,7 +280,7 @@ abstract class CKeyStore extends KeyStoreSpi {
* @exception UnrecoverableKeyException if the key cannot be recovered.
*/
public java.security.Key engineGetKey(String alias, char[] password)
throws NoSuchAlgorithmException, UnrecoverableKeyException {
throws NoSuchAlgorithmException, UnrecoverableKeyException {
if (alias == null) {
return null;
}
@ -705,7 +726,7 @@ abstract class CKeyStore extends KeyStoreSpi {
try {
// Load keys and/or certificate chains
loadKeysOrCertificateChains(getName());
loadKeysOrCertificateChains(getName(), getLocation());
} catch (KeyStoreException e) {
throw new IOException(e);
@ -801,7 +822,7 @@ abstract class CKeyStore extends KeyStoreSpi {
* @param certCollection Collection of certificates.
*/
private void generateCertificate(byte[] data,
Collection<Certificate> certCollection) {
Collection<Certificate> certCollection) {
try {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
@ -829,12 +850,20 @@ abstract class CKeyStore extends KeyStoreSpi {
}
/**
* Load keys and/or certificates from keystore into Collection.
* Returns the location of the keystore.
*/
private int getLocation() {
return storeLocation;
}
/**
* Loads keys and/or certificates from keystore into Collection.
*
* @param name Name of keystore.
* @param location Location of keystore.
*/
private native void loadKeysOrCertificateChains(String name)
throws KeyStoreException;
private native void loadKeysOrCertificateChains(String name,
int location) throws KeyStoreException;
/**
* Stores a DER-encoded certificate into the certificate store
@ -844,8 +873,8 @@ abstract class CKeyStore extends KeyStoreSpi {
* @param encoding DER-encoded certificate.
*/
private native void storeCertificate(String name, String alias,
byte[] encoding, int encodingLength, long hCryptProvider,
long hCryptKey) throws CertificateException, KeyStoreException;
byte[] encoding, int encodingLength, long hCryptProvider,
long hCryptKey) throws CertificateException, KeyStoreException;
/**
* Removes the certificate from the certificate store
@ -855,7 +884,7 @@ abstract class CKeyStore extends KeyStoreSpi {
* @param encoding DER-encoded certificate.
*/
private native void removeCertificate(String name, String alias,
byte[] encoding, int encodingLength)
byte[] encoding, int encodingLength)
throws CertificateException, KeyStoreException;
/**
@ -864,7 +893,7 @@ abstract class CKeyStore extends KeyStoreSpi {
* @param keyContainerName The name of the key container.
*/
private native void destroyKeyContainer(String keyContainerName)
throws KeyStoreException;
throws KeyStoreException;
/**
* Removes a CNG key.
@ -877,16 +906,16 @@ abstract class CKeyStore extends KeyStoreSpi {
* Generates a private-key BLOB from a key's components.
*/
private native byte[] generateRSAPrivateKeyBlob(
int keyBitLength,
byte[] modulus,
byte[] publicExponent,
byte[] privateExponent,
byte[] primeP,
byte[] primeQ,
byte[] exponentP,
byte[] exponentQ,
byte[] crtCoefficient) throws InvalidKeyException;
int keyBitLength,
byte[] modulus,
byte[] publicExponent,
byte[] privateExponent,
byte[] primeP,
byte[] primeQ,
byte[] exponentP,
byte[] exponentQ,
byte[] crtCoefficient) throws InvalidKeyException;
private native CPrivateKey storePrivateKey(String alg, byte[] keyBlob,
String keyContainerName, int keySize) throws KeyStoreException;
String keyContainerName, int keySize) throws KeyStoreException;
}

@ -91,10 +91,14 @@ public final class SunMSCAPI extends Provider {
return new PRNG();
}
} else if (type.equals("KeyStore")) {
if (algo.equals("Windows-MY")) {
if (algo.equals("Windows-MY") || algo.equals("Windows-MY-CURRENTUSER")) {
return new CKeyStore.MY();
} else if (algo.equals("Windows-ROOT")) {
} else if (algo.equals("Windows-ROOT") || algo.equals("Windows-ROOT-CURRENTUSER")) {
return new CKeyStore.ROOT();
} else if (algo.equals("Windows-MY-LOCALMACHINE")) {
return new CKeyStore.MYLocalMachine();
} else if (algo.equals("Windows-ROOT-LOCALMACHINE")) {
return new CKeyStore.ROOTLocalMachine();
}
} else if (type.equals("Signature")) {
if (algo.equals("NONEwithRSA")) {
@ -165,8 +169,16 @@ public final class SunMSCAPI extends Provider {
*/
putService(new ProviderService(p, "KeyStore",
"Windows-MY", "sun.security.mscapi.CKeyStore$MY"));
putService(new ProviderService(p, "KeyStore",
"Windows-MY-CURRENTUSER", "sun.security.mscapi.CKeyStore$MY"));
putService(new ProviderService(p, "KeyStore",
"Windows-ROOT", "sun.security.mscapi.CKeyStore$ROOT"));
putService(new ProviderService(p, "KeyStore",
"Windows-ROOT-CURRENTUSER", "sun.security.mscapi.CKeyStore$ROOT"));
putService(new ProviderService(p, "KeyStore",
"Windows-MY-LOCALMACHINE", "sun.security.mscapi.CKeyStore$MYLocalMachine"));
putService(new ProviderService(p, "KeyStore",
"Windows-ROOT-LOCALMACHINE", "sun.security.mscapi.CKeyStore$ROOTLocalMachine"));
/*
* Signature engines

@ -59,6 +59,9 @@
#define SIGNATURE_EXCEPTION "java/security/SignatureException"
#define OUT_OF_MEMORY_ERROR "java/lang/OutOfMemoryError"
#define KEYSTORE_LOCATION_CURRENTUSER 0
#define KEYSTORE_LOCATION_LOCALMACHINE 1
#define SS_CHECK(Status) \
if (Status != ERROR_SUCCESS) { \
ThrowException(env, SIGNATURE_EXCEPTION, Status); \
@ -386,10 +389,10 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_PRNG_generateSeed
/*
* Class: sun_security_mscapi_CKeyStore
* Method: loadKeysOrCertificateChains
* Signature: (Ljava/lang/String;)V
* Signature: (Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateChains
(JNIEnv *env, jobject obj, jstring jCertStoreName)
(JNIEnv *env, jobject obj, jstring jCertStoreName, jint jCertStoreLocation)
{
/**
* Certificate in cert store has enhanced key usage extension
@ -407,7 +410,6 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
char* pszNameString = NULL; // certificate's friendly name
DWORD cchNameString = 0;
__try
{
// Open a system certificate store.
@ -415,8 +417,20 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
== NULL) {
__leave;
}
if ((hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName))
== NULL) {
if (jCertStoreLocation == KEYSTORE_LOCATION_CURRENTUSER) {
hCertStore = ::CertOpenSystemStore(NULL, pszCertStoreName);
}
else if (jCertStoreLocation == KEYSTORE_LOCATION_LOCALMACHINE) {
hCertStore = ::CertOpenStore(CERT_STORE_PROV_SYSTEM_A, 0, NULL,
CERT_SYSTEM_STORE_LOCAL_MACHINE, pszCertStoreName);
}
else {
PP("jCertStoreLocation is not a valid value");
__leave;
}
if (hCertStore == NULL) {
ThrowException(env, KEYSTORE_EXCEPTION, GetLastError());
__leave;
@ -469,7 +483,7 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_loadKeysOrCertificateC
PP("--------------------------");
// Check if private key available - client authentication certificate
// must have private key available.
HCRYPTPROV hCryptProv = NULL;
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv = NULL;
DWORD dwKeySpec = 0;
HCRYPTKEY hUserKey = NULL;
BOOL bCallerFreeProv = FALSE;

@ -0,0 +1,87 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.test.lib.Asserts;
import jdk.test.lib.SecurityTools;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/*
* @test
* @bug 6782021
* @requires os.family == "windows"
* @library /test/lib
* @summary More keystore types
*/
public class AllTypes {
public static void main(String[] args) throws Exception {
var nm = test("windows-my");
var nr = test("windows-root");
var nmu = test("windows-my-currentuser");
var nru = test("windows-root-currentuser");
var hasAdminPrivileges = detectIfRunningWithAdminPrivileges();
var nmm = adminTest("windows-my-localmachine", hasAdminPrivileges);
var nrm = adminTest("windows-root-localmachine", hasAdminPrivileges);
Asserts.assertEQ(nm, nmu);
Asserts.assertEQ(nr, nru);
}
private static boolean detectIfRunningWithAdminPrivileges() {
try {
Process p = Runtime.getRuntime().exec("reg query \"HKU\\S-1-5-19\"");
p.waitFor();
return (p.exitValue() == 0);
}
catch (Exception ex) {
System.out.println("Warning: unable to detect admin privileges, assuming none");
return false;
}
}
private static List<String> adminTest(String type, boolean hasAdminPrivileges) throws Exception {
if (hasAdminPrivileges) {
return test(type);
}
System.out.println("Ignoring: " + type + " as it requires admin privileges");
return null;
}
private static List<String> test(String type) throws Exception {
var stdType = "Windows-" + type.substring(8).toUpperCase(Locale.ROOT);
SecurityTools.keytool("-storetype " + type + " -list")
.shouldHaveExitValue(0)
.shouldContain("Keystore provider: SunMSCAPI")
.shouldContain("Keystore type: " + stdType);
KeyStore ks = KeyStore.getInstance(type);
ks.load(null, null);
var content = Collections.list(ks.aliases());
Collections.sort(content);
return content;
}
}