This document was updated on 12 May 2016.
Introduction
P6R sells a PKCS 11 Version 2.40 Provider with a KMIP token. The KMIP token translates each PKCS 11 API function into and out of the KMIP protocol. The user of the PKCS 11 KMIP token does not even know they are talking to a KMIP server. Java supports PKCS 11 as a possible security provider via the SunPKCS11 wrapper. Also JCE provider products also directly support PKCS 11 wrappers (e.g., IAIK).
The significant benefit of using KMIP via a Java security provider is that a Java programmer can use KMIP without having to learn anything about KMIP. No company specific KMIP APIs to learn. Its even possible that existing Java programs can be converted (with the occasional tweak) to use KMIP this way. All that is required to make this work is some straightforward configuration.
Testing Environment
We have tested out our PKCS 11 library as a Java security provider both on Centos 6 and Windows using the following:
To build our Java examples we used:
jdk1.8.0_65, language level 8.0, IntelliJ IDEA 2016.1.1
JVM: Java HotSpot(TM) 64-Bit Server VM by Oracle Corporation
Systems tested on:
[1] Windows 7 Ultimate, 64 bit
C:\....>java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
64 bit p6pkcs11.dll library
[2] Centos6 Linux
[...... ~]$ cat /etc/redhat-release
CentOS release 6.7 (Final)
[....... ~]$ java -version
openjdk version "1.8.0_77"
OpenJDK Runtime Environment (build 1.8.0_77-b03)
OpenJDK 64-Bit Server VM (build 25.77-b03, mixed mode)
64 bit libp6pkcs11.so
Java Examples
Below are just a few code snippets that we have taken out of several of our Java test programs.
Code example 1:
KeyGenerator keyGen = KeyGenerator.getInstance("AES", "SunPKCS11-P6RPKCS11");
keyGen.init(128);
Key key = keyGen.generateKey();
// replace an older key
if (ks.containsAlias("symmetric_aes_128_key")) ks.deleteEntry("symmetric_aes_128_key");
ks.setKeyEntry("symmetric_aes_128_key", key, null, null);
Don’t see any KMIP calls here right? The magic is in the specification of the provider:
“SunPKCS11-P6RPKCS11″. The result is that the above code calls the KMIP server to generate the AES key. Then that key can be found later by calls to the keystore.
Code example 2:
// the "12345678" is the keystore's password (i.e., the PKCS#11 token's PIN)
KeyStore ks = KeyStore.getInstance("PKCS11", "SunPKCS11-P6RPKCS11");
ks.load(null, "12345678".toCharArray());
Key secretKey = ks.getKey("symmetric_aes_128_key", null);
The three lines above actually do a KMIP Locate call for a key with a custom KMIP attribute set to “symmetric_aes_128_key”. In Java, “symmetric_aes_128_key” is referred to as the
alias. (Actually the code above first makes PKCS#11 C_FindObjects() calls which our KMIP token maps to KMIP Locate. Still all that is done for the Java programmer and totally hidden from them.)
Code example 3:
private static byte[] encryptData(Key secretKey, byte[] iv, String handling, byte[] clearText) {
byte[] cipherText = null;
try {
// with a security provider do the encrypt on the remote server
Cipher encryptCipher = Cipher.getInstance(handling, "SunPKCS11-P6RPKCS11");
IvParameterSpec IV = new IvParameterSpec(iv);
encryptCipher.init(Cipher.ENCRYPT_MODE, secretKey, IV);
cipherText = encryptCipher.doFinal(clearText);
} catch (Exception e) {
e.printStackTrace();
}
return cipherText;
}
Again see any KMIP calls here? The parameter “secretKey” was created in example 1 above. This code example shows that the encryption will be done on the KMIP server. We have also tested streaming encryption (requiring KMIP 1.3), with the call sequence encryptCipher.init(), encryptCipher.update() multiple calls of updates, and then encryptCipher.doFinal(), allowing encryption (and decryption) of large chunks of data. We have also done testing with public/private keys.
Code example 4:
SecureRandom sr = SecureRandom.getInstance("PKCS11", "SunPKCS11-P6RPKCS11");
sr.setSeed("778373644".getBytes());
byte[] randomBytes = new byte[128];
sr.nextBytes(randomBytes);
Code example 4 shows how to use the random number generator on the KMIP server. The Java statement “sr.setSeed()” maps to the KMIP operation RNGSeed, and the statement “sr.nextBytes()” maps to the KMIP operation RNGRetrieve. Of course this mapping is done by the P6R PKCS#11 library. The trick in the above example is to make sure that the first parameter in the getInstance() call is “PKCS11″ and not the “SHA1PRNG” that appears in may Java examples of SecureRandom.
KMIP Server Capabilities
Well the above is all fine and good but how do I know what my KMIP server is capable of? Does my KMIP server support encryption, streaming encryption, what protocol version does it support? These are all basic questions and we provide the answer via our KMIP command line tool. Our command line tool, p6kmiptool, runs on Linux and Windows and provides scriptable access to many KMIP operations (e.g., one being KMIP Query).
>p6kmiptool -serverinfo -server {fully qualified host name}
KMIP server information:
server address: {fully qualified host name}:5696
using protocol version: 1.3
-------------------------
supported object: Certificate
supported object: SymmetricKey
supported object: SecretData
supported object: PublicKey
supported object: PrivateKey
supported object: Template
supported object: OpaqueObject
supported object: SplitKey
supported object: PGPKey
-------------------------
supported operation: Query
supported operation: Locate
supported operation: Destroy
supported operation: Get
supported operation: Create
supported operation: Register
supported operation: GetAttributes
supported operation: GetAttributeList
supported operation: AddAttribute
supported operation: ModifyAttribute
supported operation: DeleteAttribute
supported operation: Activate
supported operation: Revoke
supported operation: Poll
supported operation: Cancel
supported operation: Check
supported operation: GetUsageAllocation
supported operation: CreateKeyPair
supported operation: ReKey
supported operation: Archive
supported operation: Recover
supported operation: ObtainLease
supported operation: ReKeyKeyPair
supported operation: Certify
supported operation: ReCertify
supported operation: DiscoverVersions
supported operation: Notify
supported operation: Put
supported operation: RNGRetrieve
supported operation: RNGSeed
supported operation: Encrypt
supported operations: Decrypt
supported operations: Sign
supported operation: SignatureVerify
supported operation: MAC
supported operation: MACVerify
supported operation: Hash
supported operation: CreateSplitKey
supported operation: JoinSplitKey
-------------------------
vendor: {company name} KMIP Server {version}
-------------------------
capability: streaming is supported
capability: asynchronous command processing is supported
capability: attestation is supported
capability: unwrap mode is not processed
capability: destroy action is key material deleted
capability: shredding algorithm is unsupported
capability: RNG mode is unspecified
Given the information above, we can conclude that the above server can handle all the functions of our Java Security provider (e.g., streaming encryption: C_EncryptInit(), C_EncryptUpdate() … multiple calls, and finally C_EncryptFinal().
Our PKCS 11 library also comes with an equally powerful command line tool of its own that lets the user see what is stored on a token (also runs on Linux and Windows).
>p6pkcs11tool -list 0 -p 12345678
----- Object List (slotId: 0) -----
1> Type: Certificate, Alias: [rsa_private_key] ID: [rsa_private_key], Token
2> Type: Secret Key , Alias: [symmetric_aes_128_key] ID: [], AES Token
3> Type: Private Key, Alias: [C6AC22B2-5330-48CE-A950-47CA883C03F6] ID: [rsa_private_key], RSA Token
The above syntax is p6pkcs11tool {operation} {slotid} -p {User PIN}.
The PKCS 11 command line tool is also feature rich including functions to clean up after applications that do not call C_CloseSession(), create keys, delete keys, import and export keys and certificates, etc.