Reputation: 35
I would like to create and store my own root certificate on a smart card using the P-256 ECDSA encryption algorithm (secp256r1).
I managed to open access to the certificates created so far on the card (with using another tool: openssl), and now I would like to do it in Java using the Bouncy Castle library. What is already working:
Unfortunately, in the code block [7] in the setKeyEntry method there is an exception:
KeyStoreException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_USER_NOT_LOGGED_IN
Why is this happening?
Link to the smart card specs I'm using: https://cpl.thalesgroup.com/sites/default/files/content/product_briefs/field_document/2022-02/safenet-id-prime940-pb.pdf
I am not sure if this code is generally correct in terms of creating and saving my own certificate to the smart card, so if you see any irregularities, please point out to me what is wrong.
public void smartCard_Save_Certificate()
{
try
{
//-------------- [1] PKCS#11 configuration ------------------------
Security.addProvider(new BouncyCastleProvider());
String name = "SmartCard";
String library = "C:\\Program Files\\SafeNet\\Authentication\\SAC\\x64\\IDPrimePKCS1164.dll";
String slotListIndex = "0";
String PIN = "1234";
String pkcs11Config = "name=" + name + "\nlibrary=" + library + "\nslot=" + slotListIndex;
ByteArrayInputStream pkcs11ConfigStream = new ByteArrayInputStream(pkcs11Config.getBytes());
Provider provider = new sun.security.pkcs11.SunPKCS11(pkcs11ConfigStream);
Security.addProvider(provider);
//--------------------- [2] Key store open -------------------------
KeyStore keyStore = KeyStore.getInstance("PKCS11", provider);
keyStore.load(null, PIN.toCharArray());
//------------------ [3] listing certificates ---------------------
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements())
{
String alias = aliases.nextElement();
System.out.println(alias);
}
//------------------------ [4] generate key pair (elliptic curves secp256r1) --------------------------
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", provider);
keyGen.initialize(new ECGenParameterSpec("secp256r1"));
KeyPair keyPair = keyGen.generateKeyPair();
//-------------------------- [5] creation my root certificate -----------------------------------------
X509v3CertificateBuilder rootCertificateBuilder = new JcaX509v3CertificateBuilder(
new X500Name("CN=MyRootCertificate"),
new BigInteger(64, new SecureRandom()),
getCurrentDate(),
getCurrentDatePlusDays(7),
new X500Name("CN=MyRootCertificate"),
keyPair.getPublic());
ContentSigner rootSelfSigner = new JcaContentSignerBuilder("SHA256withECDSA").setProvider(provider).build(keyPair.getPrivate());
X509Certificate rootCertificate = new JcaX509CertificateConverter()./*setProvider(provider).*/getCertificate(rootCertificateBuilder.build(rootSelfSigner));
//---------------------------- [6] printing a public key ----------------------------------------------
PublicKey publicKey = rootCertificate.getPublicKey();
System.out.println("PublicKey of \"rootCertificate\": " + convertByteTableToHex(publicKey.getEncoded()));
//-------- [7] Saving the private key and my root certificate to a smart card ------------------------
Certificate[] certificatesChain = new Certificate[1];
certificatesChain[0] = rootCertificate;
keyStore.setKeyEntry("MyRootCertificate", (Key)keyPair.getPrivate(), null, certificatesChain);
keyStore.store(null);
//-------------------------- [8] private Key Verification -----------------------------------
PrivateKey privateKey = (PrivateKey)keyStore.getKey("MyRootCertificate", null);
boolean keyPairMatch = verifyKeyPair(privateKey, keyPair.getPublic(), "SHA256withRSA", provider);
System.out.println("Key pair match: " + keyPairMatch);
//-------------------------- [9] reading my certificate from the card -------------------------
Certificate x509CertificateSaved = keyStore.getCertificate("MyRootCertificate");
if (x509CertificateSaved != null)
{
PublicKey publicKeySaved = x509CertificateSaved.getPublicKey();
System.out.println("publicKeySaved: " + convertByteTableToHex(publicKeySaved.getEncoded()));
//-------------------------- [10] Verifying the public key of the card certificate --------------
rootCertificate.verify(publicKeySaved, provider);
}
}
catch (KeyStoreException ex)
{
Exceptions.printStackTrace(ex);
}
catch (IOException ex)
{
Exceptions.printStackTrace(ex);
}
catch (NoSuchAlgorithmException ex)
{
Exceptions.printStackTrace(ex);
}
catch (CertificateException ex)
{
Exceptions.printStackTrace(ex);
}
catch (InvalidAlgorithmParameterException ex)
{
Exceptions.printStackTrace(ex);
}
catch (OperatorCreationException ex)
{
Exceptions.printStackTrace(ex);
}
catch (InvalidKeyException ex)
{
Exceptions.printStackTrace(ex);
}
catch (SignatureException ex)
{
Exceptions.printStackTrace(ex);
}
catch (UnrecoverableKeyException ex)
{
Exceptions.printStackTrace(ex);
}
catch (ProviderException ex)
{
Exceptions.printStackTrace(ex);
}
}
public String convertByteTableToHex(byte [] bytes)
{
StringBuilder sb = new StringBuilder();
for (byte b : bytes)
{
sb.append(String.format("%02X ", b));
}
return sb.toString();
}
public boolean verifyKeyPair(PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm, Provider provider)
{
try
{
Signature signature = Signature.getInstance(signatureAlgorithm, provider);
try
{
signature.initSign(privateKey);
String testData = "Test data";
try
{
signature.update(testData.getBytes(StandardCharsets.UTF_8));
byte[] digitalSignature = signature.sign();
signature.initVerify(publicKey);
signature.update(testData.getBytes());
boolean keysMatch = signature.verify(digitalSignature);
System.out.println("Key pair match: " + keysMatch);
return keysMatch;
}
catch (SignatureException ex)
{
Exceptions.printStackTrace(ex);
return false;
}
}
catch (InvalidKeyException ex)
{
Exceptions.printStackTrace(ex);
return false;
}
}
catch (NoSuchAlgorithmException ex)
{
Exceptions.printStackTrace(ex);
return false;
}
}
Upvotes: 1
Views: 61
Reputation: 35
I added this fallowing code after the block [3], and in the line:
pkcs11.C_Login(session, CKU_USER, PIN.toCharArray());
occurred an exception:
sun.security.pkcs11.wrapper.PKCS11Exception: CKR_USER_ALREADY_LOGGED_IN
because the instruction:
keyStore.load(null, PIN.toCharArray());
was called earlier.
But the value of the variable session is non-zero, so the session with the card token was probably created, but unfortunately in the line keyStore.setKeyEntry(...) occurred again an exception:
KeyStoreException: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_USER_NOT_LOGGED_IN
that seems to be a negation of the exception raised in the line:
pkcs11.C_Login(session, CKU_USER, PIN.toCharArray());
PKCS11 pkcs11 = null;
long session = 0;
try
{
CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
pkcs11 = PKCS11.getInstance(library, "C_GetFunctionList", initArgs, false);
session = pkcs11.C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, null, null);
pkcs11.C_Login(session, CKU_USER, PIN.toCharArray());
}
catch (PKCS11Exception ex)
{
Exceptions.printStackTrace(ex);
}
Upvotes: 0