Я пытаюсь подключиться к URL-адресу HTTPS, но мне нужно использовать аутентификацию клиента с сертификатом, размещенным в моей системе сторонним программным обеспечением.
У меня нет ни малейшего представления о том, как я должен либо находить, либо использовать его, и все, что мне нужно, это пример кода С#, который значительно отличается от всех ответов Java, которые я нашел об этом. (например, KeyStore, по-видимому, нуждается в каком-то пароле?)
Это код образца С#, который у меня есть
System.Security.Cryptography.X509Certificates.X509CertificateCollection SSC_Certs =
new System.Security.Cryptography.X509Certificates.X509CertificateCollection();
Microsoft.Web.Services2.Security.X509.X509CertificateStore WS2_store =
Microsoft.Web.Services2.Security.X509.X509CertificateStore.CurrentUserStore(
Microsoft.Web.Services2.Security.X509.X509CertificateStore.MyStore);
WS2_store.OpenRead();
Microsoft.Web.Services2.Security.X509.X509CertificateCollection WS2_store_Certs = WS2_store.Certificates;
И затем он просто выполняет итерацию над WS2_store_Certs CertificateCollection и проверяет их все так. Еще немного дальше, он устанавливает такие сертификаты следующим образом:
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url_string);
httpWebRequest.ClientCertificates = SSC_Certs;
Это выглядит довольно логично, даже если я не знаю, как он находит сертификаты, но я до сих пор не смог найти эквивалент Java.
UPDATE
Соединение, которое я создаю, является частью более крупного приложения, которое зависит от JDK 5, но мне удалось просто использовать банку sunmscapi, чтобы найти сертификат, который я ищу. Это ошибки, когда я пытаюсь подключиться, используя хранилище ключей Windows, хотя я решил, что у меня возникла проблема, получив сертификат, который мне нужен, из хранилища Windows и вставив его в java-версию по умолчанию. Теперь я получаю исключение EOFException, за которым следует SSLHandshakeException, в котором говорится: "Удаленное соединение с узлом удаленного доступа во время рукопожатия". Трассировка отладки ssl не показывает мне непосредственной проблемы, так как необходимый мне сертификат отображается в цепочке сертификатов.
Он делает всю вещь ClientKeyExchange, говорит, что он закончен, а затем последние сообщения, которые я получаю из журнала отладки сразу после этого,
[write] MD5 and SHA1 hashes: len = 16
0000: 14 00 00 0C D3 E1 E7 3D C2 37 2F 41 F9 38 26 CC .......=.7/A.8&.
Padded plaintext before ENCRYPTION: len = 32
0000: 14 00 00 0C D3 E1 E7 3D C2 37 2F 41 F9 38 26 CC .......=.7/A.8&.
0010: CB 10 05 A1 3D C3 13 1C EC 39 ED 93 79 9E 4D B0 ....=....9..y.M.
AWT-EventQueue-1, WRITE: TLSv1 Handshake, length = 32
[Raw write]: length = 37
0000: 16 03 01 00 20 06 B1 D8 8F 9B 70 92 F4 AD 0D 91 .... .....p.....
0010: 25 9C 7D 3E 65 C1 8C A7 F7 DA 09 C0 84 FF F4 4A %..>e..........J
0020: CE FD 4D 65 8D ..Me.
AWT-EventQueue-1, received EOFException: error
и код, который я использую для настройки соединения,
KeyStore jks = KeyStore.getInstance(KeyStore.getDefaultType());
jks.load(null, null);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
jks.setCertificateEntry("alias", cert1); //X509Certificate obtained from windows keystore
kmf.init(jks, new char[0]);
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(kmf.getKeyManagers(), new TrustManager[]{tm}, null);
sslsocketfactory = sslContext.getSocketFactory();
System.setProperty("https.proxyHost", proxyurl);
System.setProperty("https.proxyPort", proxyport);
Authenticator.setDefault(new MyAuthenticator("proxyID", "proxyPassword"));
URL url = new URL(null, urlStr, new sun.net.www.protocol.https.Handler());
HttpsURLConnection uc = (HttpsURLConnection) url.openConnection();
uc.setSSLSocketFactory(sslsocketfactory);
uc.setAllowUserInteraction(true);
uc.setRequestMethod("POST");
uc.connect();
(Я еще не пробовал HttpClient, потому что я понятия не имею, как найти файл сертификата, и я также не уверен, что это будет всегда одинаково для каждой клиентской системы.)
ДРУГОЕ ОБНОВЛЕНИЕ
Я нашел центры сертификации для необходимого мне сертификата в хранилище ключей WINDOWS-ROOT (и проверял с помощью .verify(), чтобы убедиться, что все они проверяют), я добавил их в хранилище ключей java, но все же ничего не меняется. Я предполагаю, что они должны войти в TrustStore, но мне еще предстоит найти способ сделать это программно. (Предпочитаете не полагаться на конечных пользователей, чтобы делать такие вещи, поскольку все, что я могу гарантировать от них, это то, что сертификат и ЦС будут присутствовать из-за программного обеспечения третьей стороны, упомянутого в начале этого смехотворно длинного вопроса.)
ДАЛЕЕ ОБНОВЛЕНИЯ
Добавляя предыдущее обновление, я пришел к выводу, что моя проблема заключается в том, что мои ЦС не находятся в файле Java cacerts, поэтому он получает список доверенных ЦС с сервера, но не делает распознать их и впоследствии не отправлять один сертификат обратно, что приведет к сбою соединения. Таким образом, проблема остается, как я могу заставить Java использовать ее в качестве хранилища доверия или добавлять сертификаты в cacerts программно (без необходимости пути к файлам)? Потому что, если это невозможно, это просто оставляет меня с секретным вариантом C, voodoo. Я начну колоть куклу Duke с помощью игл на всякий случай.