Доступ к хранилищу сертификатов локального компьютера на Java?
Можно ли получить доступ к сертификатам, хранящимся в хранилище локального компьютера (а не к текущему пользователю) из сервлета Java? Я пытался использовать поставщик MSCAPI, открывая хранилища "Windows-MY" и "Windows-ROOT", но ни один из них не содержит сертификатов из хранилища "Локальный компьютер".
4 ответа
Я использовал JNA для доступа к сертификатам с помощью того же диалогового окна Windows, которое появляется, если вы собираетесь использовать какую-либо специальную программу для Windows - это может не дать ответа на ваш вопрос, но, безусловно, позволит вам предоставить доступ к чему-либо "способом Windows":
NativeLibrary cryptUI = NativeLibrary.getInstance("Cryptui");
NativeLibrary crypt32 = NativeLibrary.getInstance("Crypt32");
Function functionCertOpenSystemStore = crypt32.getFunction("CertOpenSystemStoreA");
Object[] argsCertOpenSystemStore = new Object[] { 0, "CA"};
HANDLE h = (HANDLE) functionCertOpenSystemStore.invoke(HANDLE.class, argsCertOpenSystemStore);
Function functionCryptUIDlgSelectCertificateFromStore = cryptUI.getFunction("CryptUIDlgSelectCertificateFromStore");
System.out.println(functionCryptUIDlgSelectCertificateFromStore.getName());
Object[] argsCryptUIDlgSelectCertificateFromStore = new Object[] { h, 0, 0, 0, 16, 0, 0};
Pointer ptrCertContext = (Pointer) functionCryptUIDlgSelectCertificateFromStore.invoke(Pointer.class, argsCryptUIDlgSelectCertificateFromStore);
Function functionCertGetNameString = crypt32.getFunction("CertGetNameStringW");
char[] ptrName = new char[128];
Object[] argsCertGetNameString = new Object[] { ptrCertContext, 5, 0, 0, ptrName, 128};
functionCertGetNameString.invoke(argsCertGetNameString);
System.out.println("Selected certificate is " + new String(ptrName));
Function functionCertFreeCertificateContext = crypt32.getFunction("CertFreeCertificateContext");
Object[] argsCertFreeCertificateContext = new Object[] { ptrCertContext};
functionCertFreeCertificateContext.invoke(argsCertFreeCertificateContext);
Function functionCertCloseStore = crypt32.getFunction("CertCloseStore");
Object[] argsCertCloseStore = new Object[] { h, 0};
functionCertCloseStore.invoke(argsCertCloseStore);
Это просто кусок кода, который работает; не стесняйтесь применять свои методы кодирования.
Реализация JDK по умолчанию довольно ограничена. AFAIK он вернет только ключи и сертификаты RSA. Это не универсальный адаптер для MSCAPI. Мне удалось вернуть некоторые сертификаты, используя описанный вами механизм.
Как уже упоминалось, поставщик MSCAPI не предоставляет доступ к сертификатам и ключам, хранящимся в хранилище сертификатов "Локальный компьютер". Причина этого заключается в том, что MSCAPI использует функцию Microsoft CryptoAPI CertOpenSystemStore
получить доступ к сертификатам и ключам. В документации для этой функции прямо указано, что "с помощью этого метода доступны только сертификаты текущего пользователя, а не хранилище локального компьютера". Вы можете следить за этой ошибкой OpenJDK, если хотите отслеживать прогресс в этом вопросе.
Если вы хотите найти правильное решение проблемы, вы можете приобрести коммерческую библиотеку Pheox JCAPI.
Если вы можете жить со взломом, я создал простую утилиту, которая перехватывает вызов JDKs CertOpenSystemStore
и возвращает дескриптор виртуального хранилища сертификатов, позволяющего доступ только для чтения к сертификатам и ключам в хранилищах сертификатов "Текущий пользователь" и "Локальный компьютер". Это решило мою проблему, но помните об ограничениях этой утилиты.
Сертификаты, которые вы ищете, находятся в файле хранилища ключей Java или передаются в Tomcat при запуске сервера
http://tomcat.apache.org/tomcat-4.0-doc/ssl-howto.html
если вы пытаетесь загрузить их в свое приложение, то ищите здесь HTTPS-запросы, тогда документация HTTPClient поможет вам начать
Не уверен, что это поможет вам, но если вы можете предоставить более подробную информацию, то вы могли бы получить более конкретный ответ
public class KeyStoreLookup {
public static void main(String args[]) {
try {
KeyStore ks =
KeyStore.getInstance(KeyStore.getDefaultType());
String fname = System.getProperty("user.home") +
File.separator + ".keystore";
FileInputStream fis = new FileInputStream(fname);
ks.load(fis, null);
if (ks.isKeyEntry(args[0])) {
System.out.println(args[0] +
" is a key entry in the keystore");
char c[] = new char[args[1].length()];
args[1].getChars(0, c.length, c, 0);
System.out.println("The private key for" + args[0] +
" is " + ks.getKey(args[0], c));
Certificate certs[] = ks.getCertificateChain(args[0]);
if (certs[0] instanceof X509Certificate) {
X509Certificate x509 = (X509Certificate) certs[0];
System.out.println(args[0] + " is really " +
x509.getSubjectDN());
}
if (certs[certs.length - 1] instanceof
X509Certificate) {
X509Certificate x509 = (X509Certificate)
certs[certs.length - 1];
System.out.println(args[0] + " was verified by " +
x509.getIssuerDN());
}
}
else if (ks.isCertificateEntry(args[0])) {
System.out.println(args[0] +
" is a certificate entry in the keystore");
Certificate c = ks.getCertificate(args[0]);
if (c instanceof X509Certificate) {
X509Certificate x509 = (X509Certificate) c;
System.out.println(args[0] + " is really " +
x509.getSubjectDN());
System.out.println(args[0] + " was verified by " +
x509.getIssuerDN());
}
}
else {
System.out.println(args[0] +
" is unknown to this keystore");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}