I have used
public static void signContent(String cfgFilePath , String alias ,String tokenPassword , String inputFile , String outputFile){
try {
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
Provider pkcs11 = Security.getProvider("SunPKCS11");
pkcs11 = pkcs11.configure(cfgFilePath);
KeyStore keyStore = KeyStore.getInstance("PKCS11",pkcs11);
keyStore.load(null, tokenPassword.toCharArray());
logger.log(Level.INFO,"Keystore size : "+keyStore.size());
logger.log(Level.INFO, "certificate found for alias given : "+keyStore.getCertificate(alias));
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, tokenPassword.toCharArray());
logger.log(Level.INFO,"pvt key :" + privateKey);
logger.log(Level.INFO,"pvt key algorithm: "+privateKey.getAlgorithm());// RSA
logger.log(Level.INFO,"key format : "+privateKey.getFormat()); // prints null
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
List certList = new ArrayList();
certList.add(cert);
Store certs = new JcaCertStore(certList);
generator.addCertificates(certs);
ContentSigner sha256Signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(privateKey);
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha256Signer, cert));//NO I18N
byte[] content = Files.readAllBytes(Paths.get(inputFile)); // Reading byte content from the input file
CMSProcessableByteArray cmsData = new CMSProcessableByteArray(content);
CMSSignedData signedData = generator.generate(cmsData, true);
// Get the signed JSON as a byte array
byte[] signedJson = signedData.getEncoded();
Files.write(Paths.get(outputFile),signedJson); // writing the signed content to the output file.
}
catch (Exception e) {
logger.log(Level.SEVERE,"Exception Occurred while signing the input file : ## STACKTRACE ##");
e.printStackTrace();
}
}
to sign a file for integrity verification.
But im getting error on
org.bouncycastle.operator.OperatorCreationException: cannot create signer: Supplied key (sun.security.pkcs11.P11Key$P11PrivateKey) is not a RSAPrivateKey instance
at org.bouncycastle.operator.jcajce.JcaContentSignerBuilder.build(Unknown Source)
at com.ems.silentupdate.FileSigningHandler.signContent(FileSigningHandler.java:85)
at com.ems.silentupdate.FileSigningHandler.main(FileSigningHandler.java:115)
Caused by: java.security.InvalidKeyException: Supplied key (sun.security.pkcs11.P11Key$P11PrivateKey) is not a RSAPrivateKey instance
at org.bouncycastle.jcajce.provider.asymmetric.rsa.DigestSignatureSpi.engineInitSign(Unknown Source)
at java.base/java.security.Signature$Delegate.engineInitSign(Signature.java:1351)
at java.base/java.security.Signature.initSign(Signature.java:636)
... 3 more
Whats the problem.. Im also new to HSM related works, if explaining how does HSM works will be appreciated. Could anyone explain how to sign a file with private key that is stored in a HSM format. Im using java 11 to sign , and bouncycastle version - bcpkix-jdk15on.jar , bcprov-jdk15on.jar
Issue : i have used SHA256WithRSA and internally BC converted it to uppercase and with my PKCS11 provider , it cant able to find the signature Algorithm . Thus, i have implemented a custom signer.
here is the code.
static ContentSigner getCustomSigner(String signatureAlgo,Provider prov,PrivateKey key) throws Exception {
AlgorithmIdentifier signerAlgoIdentifier = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgo);
return new ContentSigner() {
final Signature var2 = Signature.getInstance("SHA256withRSA",prov);
@Override
public AlgorithmIdentifier getAlgorithmIdentifier() {
return signerAlgoIdentifier;
}
@Override
public OutputStream getOutputStream() {
try {
var2.initSign(key);
} catch (InvalidKeyException e) {
System.out.println("Exception while initializing sign : # STACK # "+e);
}
return OutputStreamFactory.createStream(var2);
}
@Override
public byte[] getSignature() {
try {
return var2.sign();
} catch (SignatureException e) {
System.out.println("Exception in getSignature() : # STACK # "+e);
}
return new byte[0];
}
};
}