Helped a collegue yesterday for a few hours configuring his system with TLS certificates and showed code to enable authentication using client certificates. All easy enough if you know how… 🙂 Start by creating keys and certificates for a server and a person and create a Domino KYR keystore using the kyrtool from IBM. The below commands were all executed on Linux.
# change dir
cd /local/notesdata/
# generate key and self-signed cert for server
openssl genrsa -out server.key 4096
cat server.key
openssl req -new -sha256 -key server.key -out server.csr
openssl x509 -req -days 3650 -sha256 -in server.csr -signkey server.key -out server.pem
# use kyrtool to generate kyr-file for Domino (all calls to startup below is actually
# /opt/ibm/domino/bin/tools/startup
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini create
-k ./server.kyr -p password
cat server.key > server.txt
cat server.pem >> server.txt
cat server.txt
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini
verify ./server.txt
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini
import all -k ./server.kyr -i ./server.txt
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini
show keys -k ./server.kyr
startup /opt/ibm/domino/bin/kyrtool =/local/notesdata/notes.ini
show certs -k ./server.kyr
# generate PKCS#12 for a user
openssl genrsa -out person.key 4096
openssl req -new -sha256 -key person.key -out person.csr
openssl x509 -req -days 3650 -sha256 -in person.csr -CA server.pem
-CAkey server.key -out person.pem -CAcreateserial
openssl x509 -in person.pem -text -noout
openssl pkcs12 -export -out person.p12 -inkey person.key -in person.pem -certfile server.pem
Import the the person.p12 file on a person document in Domino Directory. Now copy server.kyr and server.sth to the Domino data dirctory and create an Internet Sites document using the keystore. Also edit the Internet Site document to allow certificate based authentication. The code below uses the PKCS#12 file to do an authenticated request using certificates as authentication.
package demo.intravision.certauth;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class Main {
public static void main(String[] args) {
try {
new Main().run();
} catch (Throwable t) {
t.printStackTrace();
}
}
public void run() throws Exception {
// get url and open connection
URL url = new URL("https://secure.krynn.local/testauth.nsf/username.json?open&login");
HttpURLConnection con = (HttpURLConnection)url.openConnection();
// apply SSL context (sets up the certificate to use for authentication etc)
this.applySSLContext(con);
// read from url
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
StringBuilder b = new StringBuilder();
String line = null;
while (null != (line = reader.readLine())) {
b.append(line).append('n');
}
// show data
System.out.println(b.toString());
// disconnect
con.disconnect();
}
private void applySSLContext(HttpURLConnection con) throws Exception {
// password
final char[] password = "password".toCharArray();
// input stream to pkcs12 file
InputStream certificateInputStream = new FileInputStream("/Users/lekkim/Downloads/aran.p12");
// load key and key manager
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(certificateInputStream, password);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, password);
// get trust manager
X509TrustManager customTrustMgr = this.getTrustManager();
// build ssl context
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(kmf.getKeyManagers(), null == customTrustMgr ? null : new TrustManager[]{customTrustMgr}, null);
// set socket facory if https
if (con instanceof HttpsURLConnection) {
HttpsURLConnection httpsCon = (HttpsURLConnection)con;
httpsCon.setSSLSocketFactory(sc.getSocketFactory());
}
}
private X509TrustManager getTrustManager() throws Exception {
// returning null uses the trust from the JVM cacerts keystore
if ("1".equals("2")) return null;
// define trust manager
X509TrustManager customTrustMgr = new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
};
return customTrustMgr;
}
}