Чтение сертификата клиента в сервлете - PullRequest
15 голосов
/ 28 марта 2012

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

1 Ответ

23 голосов
/ 28 марта 2012

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

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

Пример использования 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");
}
...