7

I am successfully running Netty with 2-way SSL (see Set up Netty with 2-way SSL Handsake (client and server certificate)).

However, in some of my handlers, I need to know about the user who is using the application. I find that I can't figure out how to get information like the user certificate DN in my handlers.

I would think it would be available in the ChannelHandlerContext somewhere but it is not. Any suggestions?

I know the SSLEngine has access to it somewhere, but I don't see anything about obtaining access in the SSLEngine public API. I know it has access in the handshake operation.... but how do I get it?

Community
  • 1
  • 1
MeowCode
  • 961
  • 2
  • 10
  • 29

3 Answers3

10

The SSLEngine can be fetched through the Pipline/ChannelHandlerContext

ChannelHandlerContext ctx = ...
SslHandler sslhandler = (SslHandler) ctx.channel().pipeline().get("ssl");
sslhandler.engine().getSession().getPeerCertificateChain()[0].getSubjectDN());

This allows you to get the certificates in the Handler Objects. Pay attention, that the SSL-Handshake needs to be finished when you do this. Otherwise you will get a

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

exception. To avoid this, you can listen for a userEvent (in our case HandshakeCompletionEvent) in the handler, which could look the following:

@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
    logger.info("userEventTriggered: {0}, Class: {1}", evt.toString(), evt.getClass());

    if (evt instanceof HandshakeCompletionEvent) {
        fetchCertificate(ctx);
    }
} 
user207421
  • 289,834
  • 37
  • 266
  • 440
geri-m
  • 615
  • 2
  • 12
  • 22
9

SSLEngine.getSession().getPeerCertificateChain(). The zeroth entry is the peer's own certificate.

user207421
  • 289,834
  • 37
  • 266
  • 440
-1

I used the following codes to get the client certificate and certificate's issuer. I hope it helps.

 SslHandler sslHandler = (SslHandler) ctx.channel().pipeline().get("ssl");

 X509Certificate issuer = convert(sslHandler.engine().getSession().getPeerCertificateChain()[sslHandler.engine().getSession().getPeerCertificateChain().length -1]);

 System.out.println("issuer: " + issuer);


  public static java.security.cert.X509Certificate convert(javax.security.cert.X509Certificate cert) {
    try {
        byte[] encoded = cert.getEncoded();
        ByteArrayInputStream bis = new ByteArrayInputStream(encoded);
        java.security.cert.CertificateFactory cf
                = java.security.cert.CertificateFactory.getInstance("X.509");
        return (java.security.cert.X509Certificate)cf.generateCertificate(bis);
    } catch (java.security.cert.CertificateEncodingException e) {
    } catch (javax.security.cert.CertificateEncodingException e) {
    } catch (java.security.cert.CertificateException e) {
    }
    return null;
}
Rahmican
  • 103
  • 1
  • 6
  • Why? You already have the certificate. Why encode it and decode it all over again? The `convert()` method is pointless here. – user207421 Aug 21 '19 at 00:05