Project: Athenz (Provisioning / Key Management)
File: server_side_x509_credentials.md

In order to authenticate x.509 client certificates on Athenz enabled services, your server needs to be configured to authenticate TLS client certificates along with updated trust store with Athenz CA certificates. This section contains some examples how to setup your server to enable TLS client certificate authentication. First, get the CA Certificates of your Athenz instances and place them in a truststore. For our example, the truststore will be named `athenzcertificatebundle.jks`. You must configure your container to recognize this truststure. If you are using other containers, you can set the SSL properties at the JVM level via system properties. ``` -Djavax.net.ssl.trustStore=/home/example/athenzcertificatebundle.jks ``` If you are using your own application server, you would need to set setNeedClientAuth to true. For example: ```java SSLServerSocketFactory ssf = sc.getServerSocketFactory(); SSLServerSocket sslserversocket = (SSLServerSocket) ssf.createServerSocket(4443); sslserversocket.setNeedClientAuth(true); ``` Please follow specific documentations provided by your container vendor on how to require client side TLS authentication. If your trust store only has Athenz CA certificates, no need to extract and verify the issuer. If not, please follow below code example for verification. The client certificate is accessible from `jakarta.servlet.request.X509Certificate` HttpServletRequest attribute. Here is how you can get access to the TLS certificate: ```java import java.security.cert.X509Certificate; import jakarta.servlet.http.HttpServletRequest; public static final String JAVAXCERTATTR = "jakarta.servlet.request.X509Certificate"; X509Certificate[] certs = (X509Certificate[]) servletRequest.getAttribute(JAVAXCERTATTR); X509Certificate x509cert = null; if (null != certs && certs.length != 0) { for (X509Certificate cert: certs) { if (null != cert) { //find the first occurrence of non-null certificate x509cert = cert; break; } } } ``` Then, validate the certificate issuers against a pre-configured set of Athenz CA issuers. Here is an example of how you may build the list of valid certificates from a truststore and then check that the issuer is valid. ```java private static final String DEFAULTISSUERSFILENAME = "/home/example/athenzcertificate_bundle.jks"; private static Set<String> X509_ISSUERS = new HashSet<>(); X509Certificate[] certs = (X509Certificate[]) request.getAttribute(JAVAXCERTATTR); X509Certificate x509cert = null; if (null != certs && certs.length != 0) { for (X509Certificate cert: certs) { if (null != cert) { //find the first occurrence of none null certificate x509cert = cert; if (LOG.isDebugEnabled()) { LOG.debug("Found x509 cert"); } break; } } } if (null == x509cert) { // fail as x509cert is missing LOG.error("x509 certificate is missing"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return; } // validate the certificate against CAs X500Principal issuerx500Principal = x509cert.getIssuerX500Principal(); String issuer = issuerx500Principal.getName(); if (LOG.isDebugEnabled()) { LOG.debug("Found x509 cert issuer: {}", issuer); } if (issuer == null || issuer.isEmpty() || !X509_ISSUERS.contains(issuer)) { //fail LOG.error("Issuer is missing or not apart of authorized Athenz CA"); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return; } private final void setX509CAIssuers(final String issuersFileName) { if (issuersFileName == null || issuersFileName.isEmpty()) { return; } try { Path path = Paths.get(issuersFileName); if (!path.isAbsolute()) { path = Paths.get(getClass().getClassLoader().getResource(issuersFileName).toURI()); } KeyStore ks = null; try (InputStream in = new FileInputStream(path.toString())) { ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, null); } for (Enumeration<?> e = ks.aliases(); e.hasMoreElements(); ) { String alias = (String)e.nextElement(); X509Certificate cert = (X509Certificate)ks.getCertificate(alias); X500Principal issuerx500Principal = cert.getIssuerX500Principal(); String issuer = issuerx500Principal.getName(); X509_ISSUERS.add(issuer); if (LOG.isDebugEnabled()) { LOG.debug("issuer: {} " , issuer); } } } catch (Throwable e) { LOG.error("Unable to set issuers from file " + issuersFileName, e); } } ```