Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
117 views
in Technique[技术] by (71.8m points)

java - Reading Client Certificate in Servlet

I have a Client Server Communication scenario in JBOSS and browser as client(JAVA PROGRAM). Initially when the connection is made, Client sends its Certificate to Server. Server extracts the public key of client from certificate and thus communication will continue.
Now my question is
How to send certificate(.cer) from Client to Server?
How to receive the certificate and extract its public key in Server?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

How to send certificate(.cer) from Client to Server?

Client certificate (.cer, .crt, .pem) and it's corresponding private key (.key) should be packaged into PKCS#12 (.p12, .pfx) or JKS (.jks) container first (keystore). You also should have server's CA certicate packaged as JKS (truststore).

Example using 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();

You may find working example in this project see X509Test class.

With HttpClient 4.x configuration and syntax would be slightly different:

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);

How to receive the certificate and extract its public key in Server?

You server must be configurated to require X.509 client certificate authentication. Then during SSL handshake servlet container will recieve certificate, check it against trustore and provide it to application as a request attribute. In usual case with single certificate you could use this method in servlet environment to extract certificate:

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");
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...