Чтение сертификата клиента в сервлете

У меня есть сценарий связи с клиентским сервером в JBOSS и браузере как клиент (ПРОГРАММА JAVA). Первоначально, когда соединение выполняется, клиент отправляет свой сертификат на сервер. Сервер извлекает открытый ключ клиента из сертификата и, таким образом, связь будет продолжаться.
Теперь мой вопрос: Как отправить сертификат (.cer) с сервера на сервер?
Как получить сертификат и извлечь его открытый ключ на сервере?

Ответы

Ответ 1

Как отправить сертификат (.cer) с сервера на сервер?

Клиентский сертификат (.cer,.crt,.pem), а соответствующий секретный ключ (.key) должен быть сначала упакован в PKCS # 12 (.p12,.pfx) или JKS (.jks) контейнер (хранилище ключей). Вы также должны иметь сертификат CA CA, упакованный как JKS (truststore).

Пример использования HttpClient 3.x:

HttpClient client = new HttpClient();
// truststore
KeyStore trustStore = KeyStore.getInstance("JKS", "SUN");
trustStore.load(TestSupertype.class.getResourceAsStream("/client-truststore.jks"), "amber%".toCharArray());
String alg = KeyManagerFactory.getDefaultAlgorithm();
TrustManagerFactory fac = TrustManagerFactory.getInstance(alg);
fac.init(trustStore);
// keystore
KeyStore keystore = KeyStore.getInstance("PKCS12", "SunJSSE");
keystore.load(X509Test.class.getResourceAsStream("/etomcat_client.p12"), "etomcat".toCharArray());
String keyAlg = KeyManagerFactory.getDefaultAlgorithm();
KeyManagerFactory keyFac = KeyManagerFactory.getInstance(keyAlg);
keyFac.init(keystore, "etomcat".toCharArray());
// context
SSLContext ctx = SSLContext.getInstance("TLS", "SunJSSE");
ctx.init(keyFac.getKeyManagers(), fac.getTrustManagers(), new SecureRandom());
SslContextedSecureProtocolSocketFactory secureProtocolSocketFactory = new SslContextedSecureProtocolSocketFactory(ctx);
Protocol.registerProtocol("https", new Protocol("https", (ProtocolSocketFactory) secureProtocolSocketFactory, 8443));
// test get
HttpMethod get = new GetMethod("https://127.0.0.1:8443/etomcat_x509");
client.executeMethod(get);
// get response body and do what you need with it
byte[] responseBody = get.getResponseBody();

Вы можете найти рабочий пример в этом проекте в классе X509Test.

С Конфигурация и синтаксис HttpClient 4.x будет немного отличаться:

HttpClient httpclient = new DefaultHttpClient();
// truststore
KeyStore ts = KeyStore.getInstance("JKS", "SUN");
ts.load(PostService.class.getResourceAsStream("/truststore.jks"), "amber%".toCharArray());
// if you remove me, you've got 'javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated' on missing truststore
if(0 == ts.size()) throw new IOException("Error loading truststore");
// tmf
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ts);
// keystore
KeyStore ks = KeyStore.getInstance("PKCS12", "SunJSSE");
ks.load(PostService.class.getResourceAsStream("/" + certName), certPwd.toCharArray());
// if you remove me, you've got 'javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated' on missing keystore
if(0 == ks.size()) throw new IOException("Error loading keystore");
// kmf
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, certPwd.toCharArray());
// SSL
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// socket
SSLSocketFactory socketFactory = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme sch = new Scheme("https", 8443, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(sch);
// request
HttpMethod get = new GetMethod("https://localhost:8443/foo");
client.executeMethod(get);
IOUtils.copy(get.getResponseBodyAsStream(), System.out);

Как получить сертификат и извлечь его открытый ключ на сервере?

Сервер должен быть настроен для проверки подлинности сертификата клиента X.509. Затем в SSL-сервлете контейнер сервлетов получит сертификат, проверит его против доверия и предоставит его приложению в качестве атрибута запроса. В обычном случае с единственным сертификатом вы можете использовать этот метод в среде сервлета для извлечения сертификата:

protected X509Certificate extractCertificate(HttpServletRequest req) {
    X509Certificate[] certs = (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate");
    if (null != certs && certs.length > 0) {
        return certs[0];
    }
    throw new RuntimeException("No X.509 client certificate found in request");
}