Introduction
In my previous blog (Reading NSS DB from Java 8 with SunPKCS11) I showed how to read a NSS DB from Java 8 with SunPKCS11. In Java 11 a lot of internal packages is no longer visible and you will get compilation error if you try to access them. The same is true for sun.security.pkcs11.SunPKCS11, since it is a sun class. But SunPKCS11 is still available. What they have done is to make SunPKCS11 always available, i.e. you do not need to add, i.e. Security.addProvider(provider);
Java 8
String configName = "/home/magnuskkarlsson/NetBeansProjects/example-nssdb/pkcs11.cfg";
sun.security.pkcs11.SunPKCS11 provider = new sun.security.pkcs11.SunPKCS11(configName);
Security.addProvider(provider);
Java 11
String configName = "/home/magnuskkarlsson/NetBeansProjects/example-nssdb/pkcs11.cfg";
Provider prototype = Security.getProvider("SunPKCS11");
Provider provider = prototype.configure(configName);
One gotcha with this in Java 11, is that you need to specify the provider when you try to do cryptographic operation like signature, otherwise you will get the following error.
Exception in thread "main" java.security.InvalidKeyException: No installed provider supports this key: sun.security.pkcs11.P11Key$P11PrivateKey
So how have they solved, so that SunPKCS11 is always loaded? Through the java.security which has also moved, due to changes in directory layout in Java 11.
Java 8: $JAVA_HOME/lib/security/java.security
Java 11: $JAVA_HOME/conf/security/java.security
So in Java 11 you can see the following
security.provider.12=SunPKCS11
#security.provider.1=SunPKCS11 ${java.home}/lib/security/nss.cfg
And if you look inside $JAVA_HOME/lib/security/nss.cfg, you see a ready to use EMPTY NSS DB configuration. To read about all SunPKCS11 NSS DB configuration see https://docs.oracle.com/en/java/javase/11/security/pkcs11-reference-guide1.html#GUID-7989F8B4-7260-4908-8203-99056B2D060E
name = NSS
nssLibraryDirectory = /usr/lib64
nssDbMode = noDb
attributes = compatibility
handleStartupErrors = ignoreMultipleInitialisation
Testing Time
Now lets test the SunPKCS11 with Java 11. First lets create a new NSS DB with the new SQLite format (cert9.db, key4.db, and pkcs11.txt) and then add a keypair and a self-signed certificate in the internal token.
$ echo "redhat123" > password.internal
$ mkdir nssdb_sql
$ certutil -N -d sql:nssdb_sql -f password.internal
$ certutil -S -x -d sql:nssdb_sql -f password.internal -n mkk -s 'CN=MKK, O=MKK Consultancy, C=SE' -k rsa -g 2048 -v 24 -Z SHA256 -t ',,'
And don't forget to add an empty secmod.db.
$ touch nssdb_sql/secmod.db
Then create the SunPKCS11 configuration file pkcs11.cfg.
name = NSScrypto
nssLibraryDirectory = /usr/lib64
nssSecmodDirectory = /home/magnuskkarlsson/NetBeansProjects/example-nssdb/nssdb_sql
nssDbMode = readWrite
nssModule = keystore
package se.magnuskkarlsson.example.nssdb;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.Base64;
import java.util.Enumeration;
// https://docs.oracle.com/javase/8/docs/technotes/guides/security/p11guide.html#NSS
// https://docs.oracle.com/en/java/javase/11/security/pkcs11-reference-guide1.html#GUID-85EA1017-E59C-49B9-9207-65B7B2BF171E
// https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Reference/NSS_tools_:_certutil
/*
certutil supports two types of databases: the legacy
security databases (cert8.db, key3.db, and secmod.db)
and new SQLite databases (cert9.db, key4.db, and
pkcs11.txt).
*/
/*
name = NSScrypto
nssLibraryDirectory = /usr/lib64
nssSecmodDirectory = /home/magnuskkarlsson/NetBeansProjects/example-nssdb/nssdb_sql
nssDbMode = readWrite
nssModule = keystore
*/
public class NSSSunPKCS11Tool {
public static char[] password = "redhat123".toCharArray();
public static void main(String[] args) throws Exception {
String configName = "/home/magnuskkarlsson/NetBeansProjects/example-nssdb/pkcs11.cfg";
// Java 8
// sun.security.pkcs11.SunPKCS11 provider = new sun.security.pkcs11.SunPKCS11(configName);
// Security.addProvider(provider);
//
// Java 11
Provider prototype = Security.getProvider("SunPKCS11");
Provider provider = prototype.configure(configName);
KeyStore ks = KeyStore.getInstance("PKCS11", provider);
ks.load(null, password);
System.out.println("Successfully loaded NSS DB.");
System.out.println("------------------------------");
for (Enumeration aliases = ks.aliases(); aliases.hasMoreElements();) {
String alias = aliases.nextElement();
X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
PublicKey publicKey = cert.getPublicKey();
PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password);
System.out.println("alias: " + alias);
System.out.println("privateKey: " + privateKey);
System.out.println("cert subject dn: " + cert.getSubjectX500Principal().toString());
if (privateKey != null) {
String plainText = "HELLO WORLD";
Signature privateSignature = Signature.getInstance("SHA256withRSA", provider);
privateSignature.initSign(privateKey);
privateSignature.update(plainText.getBytes(UTF_8));
byte[] signature = privateSignature.sign();
String signatureBase64 = Base64.getEncoder().encodeToString(signature);
System.out.println(signatureBase64);
Signature publicSignature = Signature.getInstance("SHA256withRSA", provider);
publicSignature.initVerify(publicKey);
publicSignature.update(plainText.getBytes(UTF_8));
boolean verify = publicSignature.verify(signature);
System.out.println("verify: " + verify);
}
System.out.println("------------------------------");
}
}
}
Then lets run it. I have here added the debug flag -Djava.security.debug=sunpkcs11 which is of course not necessary, but useful when running labs to understand things better.
$ mvn clean install; java -cp target/example-nssdb-1.0.0-SNAPSHOT.jar -Djava.security.debug=sunpkcs11 se.magnuskkarlsson.example.nssdb.NSSSunPKCS11Tool
SunPKCS11 loading /home/magnuskkarlsson/NetBeansProjects/example-nssdb/pkcs11.cfg
NSS modules: [NSS Internal PKCS #11 Module (CRYPTO, /usr/lib64/libsoftokn3.so, slot 0), NSS Internal PKCS #11 Module (KEYSTORE, /usr/lib64/libsoftokn3.so, slot 1)]
sunpkcs11: Initializing PKCS#11 library /usr/lib64/libsoftokn3.so
Information for provider SunPKCS11-NSScrypto
Library info:
cryptokiVersion: 2.20
manufacturerID: Mozilla Foundation
flags: 0
libraryDescription: NSS Internal Crypto Services
libraryVersion: 3.46
All slots: 1, 2
Slots with tokens: 1, 2
Slot info for slot 2:
slotDescription: NSS User Private Key and Certificate Services
manufacturerID: Mozilla Foundation
flags: CKF_TOKEN_PRESENT
hardwareVersion: 3.46
firmwareVersion: 0.00
Token info for token in slot 2:
label: NSS Certificate DB
manufacturerID: Mozilla Foundation
model: NSS 3
serialNumber: 0000000000000000
flags: CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_DUAL_CRYPTO_OPERATIONS | CKF_TOKEN_INITIALIZED
ulMaxSessionCount: CK_EFFECTIVELY_INFINITE
ulSessionCount: 1
ulMaxRwSessionCount: CK_EFFECTIVELY_INFINITE
ulRwSessionCount: 0
ulMaxPinLen: 500
ulMinPinLen: 0
ulTotalPublicMemory: 1
ulFreePublicMemory: 1
ulTotalPrivateMemory: 1
ulFreePrivateMemory: 1
hardwareVersion: 0.00
firmwareVersion: 0.00
utcTime: 0000000000000000
...
sunpkcs11: login succeeded
Successfully loaded NSS DB.
------------------------------
alias: mkk
privateKey: SunPKCS11-NSScrypto RSA private key, 2048 bitstoken object, sensitive, extractable)
cert subject dn: CN=MKK, O=MKK Consultancy, C=SE
bKqsRr+exiclVEB1Q59/M/KrElu+dCFKDK9+mertjlj1lJ7LG7Gwrws6CX/m6l3A9bf4nt+yQNYYt/2x3WFITquuBsbMKfyV6J7UHYS7J92+EUNHNXaFR2QVDo5v3Ecy4oPD9ln7LATl1jJnfSs0kiYB7HbOIWjufxfrY65sgQUyR+I3uQaj0+PDJ8WbrUbqCvzdFv3MH+Jv9kDvdp1eBkrPD+yczLdIQy7kDJRmzN34gU6tW85RZ0PpgjZomV3TO3S6hJxeZqH/ijd5yLKlpfQAM2V4dADsnlGmS9KUrZ6JOU/eIFRX6CD0X/eNsCqgUp+vn7JD/SE4NJabUdrVQw==
Demoting session, active: 3
verify: true
------------------------------
No comments:
Post a Comment