Earlier this week, I got some advice from John Dennis on how to set up the certificates for a Java based web application. The certificates were to be issued by the Dogtag instance in a Red Hat Identity Mangement (RH IdM) install. However, unlike the previous examples I’ve seen, this one did some transforms from the certificate files, into PKCS12 and then finally into the keystore. It Looks like this:
ipa-getcert request -f /etc/pki/tls/certs/rhsso-cert.pem -k /etc/pki/tls/private/rhsso-key.pem -I rhsso -K RHSSO/`hostname` -D `hostname` openssl pkcs12 -export -name rhsso -passout pass:FreeIPA4All -in /etc/pki/tls/certs/rhsso-cert.pem -inkey /etc/pki/tls/private/rhsso-key.pem -out rhsso.p12 keytool -importkeystore -srckeystore rhsso.p12 -srcstoretype PKCS12 -srcstorepass FreeIPA4All -destkeystore keycloak.jks -deststorepass FreeIPA4All -alias rhsso keytool -keystore keycloak.jks -import -file /etc/ipa/ca.crt -alias ipa-ca cp keycloak.jks /etc/opt/rh/rh-sso7/keycloak/standalone/
Aside from the complications of this process, it also means that the application will not be updated when Certmonger automatically renews the certificate, leading to potential down time. I wonder if there is a better option.
Table of contents
Keystore Formats
The latest couple releases of Java have supported a wider array of Keystore formats.
from /usr/lib/jvm/java-1.8.0-openjdk-$VERSION.b14.fc27.x86_64/jre/lib/security/java.security
# # Default keystore type. # keystore.type=jks # # Controls compatibility mode for the JKS keystore type. # # When set to 'true', the JKS keystore type supports loading # keystore files in either JKS or PKCS12 format. When set to 'false' # it supports loading only JKS keystore files. # keystore.type.compat=true
So it appears that one step above is unnecssary: we could use a PKCS-12 file instead of the Native Java KeyStore. However, Certmonger does not mange PKCS-12 files either, so that is not a complete solution.
PKCS-11
But what about PKCS-11?
One thing that is tricky is that you are rarely going to find much about creating PKCS-11 files: instead, you find wasy to work with them via various tools. Why is that? PKCS-11 is not a file format per set, it is a standard.
The PKCS#11 standard specifies an application programming interface (API), called “Cryptoki,†for devices that hold cryptographic information and perform cryptographic functions. Cryptoki follows a simple object based approach, addressing the goals of technology independence (any kind of device) and resource sharing (multiple applications accessing multiple devices), presenting to applications a common, logical view of the device called a “cryptographic tokenâ€.
In other words, PKCS-11 is an API for talking to various forms of storage for cryptographic information, specifically asymmetric keys.
Asymmetric keys is that they come in pairs. One is public, the other is kept private. The PKCS-11 API helps enforce that. Instead of extracting a Private Key from a database in order to encrypt or decrypt data the data is moved into the container and signed internally. The private key never leaves the container.
That is why we have two standards: PKCS-11 and PKCS-12. PKCS-12 Is the standard the way you safely extract a key and transport it to another location.
Ideally, the PKCS-11 token is a hardware device. For example, a Yubikey device. Many computers come with Hardware Security Modules (HSMs) built in for just this purpose.
The Mozilla project developed cryptography to with with these standards. It used to be called Netscape Security Services, but since has been retconned to be Network Security Services. Both, you notice, are the acronym NSS. To be clear, this is separate from the Name Server Switch API, which is also called NSS. I seem to recall having written this all before.
The Firefox Browser, and related programs like Thunderbird, can fetch and store cryptographic certificates and keys in a managed database. This is usually called an NSS database, and it is accessed via PKCS-11, specifically so they have a singe API to use if the site want to do something more locked down, like use an HSM.
OK, so this is a long way of saying that, maybe it is possible to use an NSS database as the Java Keystore.
NSS Database
First, lets create a scratch NSS Database:
[root@sso ~]# cd /etc/opt/rh/rh-sso7/keycloak/standalone/ [root@sso standalone]# mkdir keystore [root@sso standalone]# certutil -d dbm:$PWD/keystore -N Enter a password which will be used to encrypt your keys. The password should be at least 8 characters long, and should contain at least one non-alphabetic character. Enter new password: Re-enter password:
Now lets request a cert. Because this NSS database is in a custom location, SELinx is going to block Certmonger from talking to it. For now, I’ll set the machine in permissive mode to let the request go in.
[root@sso standalone]# setenforce permissive root@sso standalone]# ipa-getcert request -w -d dbm:$PWD/keystore -D $HOSTNAME -K RHSSO/$HOSTNAME -n RHSSO New signing request "20180215041951" added. [root@sso standalone]# getcert list Number of certificates and requests being tracked: 1. Request ID '20180215041951': status: MONITORING stuck: no key pair storage: type=NSSDB,location='dbm:/etc/opt/rh/rh-sso7/keycloak/standalone/keystore',nickname='RHSSO',token='NSS Certificate DB' certificate: type=NSSDB,location='dbm:/etc/opt/rh/rh-sso7/keycloak/standalone/keystore',nickname='RHSSO',token='NSS Certificate DB' CA: IPA issuer: CN=Certificate Authority,O=AYOUNG.RDUSALAB subject: CN=sso.ayoung.rdusalab,O=AYOUNG.RDUSALAB expires: 2020-02-16 04:19:46 UTC dns: sso.ayoung.rdusalab principal name: RHSSO/sso.ayoung.rdusalab@AYOUNG.RDUSALAB key usage: digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment eku: id-kp-serverAuth,id-kp-clientAuth pre-save command: post-save command: track: yes auto-renew: yes
SELinux reworking will come at the end.
OK, we should be able to list the certs in the database:
[root@sso standalone]# certutil -L -d dbm:$PWD/keystore Certificate Nickname Trust Attributes SSL,S/MIME,JAR/XPI RHSSO ,, [root@sso standalone]#
Lets try it in Java. First, I need the Compiler
sudo yum install java-1.8.0-openjdk-devel
Now… the Java libraries it turns out are not default allowed to deal with NSS. We need a configuration file and we can create the provider dynamically. For NSS we need: security.provider.10=sun.security.pkcs11.SunPKCS11. The following code seems to succeed:
import java.security.KeyStore; import java.security.Provider; import java.security.Security; import sun.security.pkcs11.SunPKCS11; public class ReadNSS{ public static char[] password = new char[0]; public static void main(String[] args) throws Exception{ String configName = "/etc/opt/rh/rh-sso7/keycloak/standalone/pkcs11.cfg"; Provider p = new sun.security.pkcs11.SunPKCS11(configName); Security.addProvider(p); KeyStore ks = KeyStore.getInstance("PKCS11", p); //p is the provider created above ks.load(null, password); for (Enumeration aliases = ks.aliases(); aliases.hasMoreElements();){ System.out.println(aliases.nextElement()); } } }
With the corresponding config file:
name = NSScrypto nssModule = keystore nssDbMode = readOnly nssLibraryDirectory = /lib64/ nssSecmodDirectory = /etc/opt/rh/rh-sso7/keycloak/standalone/keystore
Compile and run
[root@sso standalone]# javac ReadNSS.java [root@sso standalone]# java ReadNSS RHSSO
We can list the keys. Ideally, I would pass that provider information on the command line, though.
Conclusion
It does look like there is a way to create a database that Java can use as a KeyStore. The question, now, is whether TOmcat and JBoss based web apps can use this mechanism to manage their HTTPS certificates.
SE Linux
What should the SELinux rule be:
type=AVC msg=audit(1518668385.358:6514): avc: denied { unlink } for pid=15316 comm="certmonger" name="key4.db-journal" dev="vda1" ino=17484326 scontext=system_u:system_r:certmonger_t:s0 tcontext=system_u:object_r:etc_t:s0 tclass=file Was caused by: Missing type enforcement (TE) allow rule. You can use audit2allow to generate a loadable module to allow this access.
But that Generates
#============= certmonger_t ============== #!!!! WARNING: 'etc_t' is a base type. allow certmonger_t etc_t:file { create setattr unlink write };
Which, if I read it right, allows Certmonger to unlink and write and etc file. We want something more targeted.
You can get jboss and tomcat to use an nss db!
https://access.redhat.com/solutions/42301
RedHat test that configuration as part of FIPS compliance and certification.
Ah excellent. I think I was about 2/3rds through the steps of reproducing that. I don’t need or want full FIPS compliance, just to get a format for the Keystore that Cermonger can support. I think there might be a few additions to those commands to use the sql backend instead of dbm, as SQL is now the default.
Thanks for the link. Course, it only helps those of us that can get behind the Red Hat portal authentication.
jar} +# Space-separated list of extra javac options +javac. compilerargs= +javac. deprecation=false +javac. processorpath= + ${javac. classpath} +javac.