JT400, Proxy and YubiKey

In a previous post (Modern JT400 Proxy) we wrote about our improvement over JT400 TunnelProxy to safely connect JT400 to the IBM i through Green Screens Terminal Services. This time we will present how to write Java apps using JT400 to access the IBM i behind Green Screens Server protected with client-side certificates and security keys as YubiKey.

Before we start, let's first explain what YubiKey is.

YubiKey USB  Device is a multifunctional security key having several standardized security mechanisms such as FIDO (WebAuthn), OTP, PGP, PIV etc. When working with SSL certificates, PIV is what interests us.

So what is PIV?!

PIV (personal identity verification card) or simply put SmartCard. A chip on electronic passports, personal ID documents, or USB based devices containing several slots holding SSL certificates and private keys. There is a standardized way to access PIV data through APDU commands.

If you want to find out technical details about PIV, look here. Or to learn how to handle APDU commands in sample code we wrote in GO.

Java SmartCard

Java itself contains great support for SmartCards and allows you to easily list / access / read / sign / verify and manage data on PIV devices. On top of SmartCard API (javax.smartcardio), various frameworks are written to simplify its usage.

One of them is made for YubiKey allowing you to use SSL client certificates stored on PIV devices for remote authorization.

To use a more low-level approach, use javax.smartcardio or libs as apdu4j.

Java YubiKey

Mentioned Java YubiKey library uses a set of APDU commands through javax.smartcardio to issue commands to YubiKey device such as digital signature signing or to access client certificate stored inside YubiKey etc.

To integrate/activate YubiKey is quite easy. The whole principle is to register a YubiKey security provider into Java SSL Context allowing all remote requests using that SSL Context to be verified with SSL certificate existing on YubiKey PIV device.

Here is a sample SSL Context initialization code:

Security.insertProviderAt(new YkPivSecurityProvider(), 1);

KeyManagerFactory kmf = KeyManagerFactory.getInstance(YkPivKeyManagerFactory.ALGORITHM);
kmf.init(YkPivKeyManagerFactory.initParameters(KeySlot.AUTHENTICATION, null, "123456"));

TrustManager[] trustAllCerts = new TrustManager[] { new TrustAllCerts() };

SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(kmf.getKeyManagers(), trustAllCerts, null);

SSLContext.setDefault(sslContext);

Yes, that's all that is required. Of course, make sure the proper client certificate is installed into YubiKey. It is enough to create SSLContext once and set it as a default context on Java instance level as shown in example code, or use it for network connection instances individually.

Sample code from the previous post (Modern JT400 Proxy) should work out of the box without any changes, which will allow the use of JT400 through Green Screens Proxy protected with SSL client certificates stored on YubiKey.

Here is a very simple example to test standard HTTPS URL protected with client based certificates stored on YubiKey...

HttpsURLConnection connection = (HttpsURLConnection) new URL("https://myserver/index.html").openConnection();
connection.setHostnameVerifier((host, session) -> true);

// optional if YubiKey SSLContext not defined as default
connection.setSSLSocketFactory(sslContext.getSocketFactory());
    	
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));

String inputLine;
while ((inputLine = in.readLine()) != null)
   	System.out.println(inputLine);

in.close();
connection.disconnect();

NOTE: Please note that if your YubiKey is protected with PIN, changes in YubiKey security provider are required to authorize access. Original lib does not support PIN locked YubiKey. You can do a few small changes in the original source as shown below.

Change YkPivX509ExtendedKeyManager constructor inside YkPivKeyManagerFactory.java file.

try {
    this.ykPiv = new YkPiv();
    // add this to allow pin protected access
    if (Objects.nonNull(params.pin)) this.ykPiv.login(params.pin);
 } catch (YkPivException e) {
    throw new IllegalStateException("Unable to establish connection to yubikey", e);
}

Also, add "String pin" field to the YkPivManagerFactoryParameters class located inside YkPivKeyManagerFactory.java file to add support for PIN locked YubiKeys.

Conclusion

With Proxy400 module, part of Green Screens Terminal services HTTPS protected with Client SSL Certificates access control and in combination with security keys as YubiKey brings powerful cloud security to JT400 based applications.

JT400 based applications will connect to the remote IBM i system hidden behind Green Screens, removing the need for installing and setting up VPN, opening additional ports or installing specialized desktop security apps.

No matter how the Java app is distributed, its usage will require YubiKey with a proper client certificate installed to be able to connect to a remote IBM i server.