javapdfpkcs#11iaik-jcesunpkcs11

Document altered/corrupted while attaching IAIK PKCS11 signing Hash


I have a base64 encoded message digest (signing bytes of a pdf), which I want to sign and return PKCS7. Previously, I was using SUNPKCS11 and was able to attach the same to the pdf.

I have started using IAIK PKCS11 Wrapper. Below is the process, I have a IAIKPKCS11ContentSigner defined like:

public class IAIKPKCS11ContentSigner implements ContentSigner {
   private final Session session;
   private final RSAPrivateKey privateKey;
   private final ByteArrayOutputStream outputStream;

   public IAIKPKCS11ContentSigner(Session session, RSAPrivateKey privateKey) {
     this.session = session;
     this.privateKey = privateKey;
     this.outputStream = new ByteArrayOutputStream();
   }

   @Override
   public byte[] getSignature() {
     try {
       AlgorithmIdentifier sha256Aid = new DefaultDigestAlgorithmIdentifierFinder().find("SHA-256");
       DigestInfo digestInfo = new DigestInfo(sha256Aid, this.outputStream.toByteArray());
       byte[] encodedDigestInfo = digestInfo.getEncoded();
       Mechanism signingMechanism = Mechanism.get(PKCS11Constants.CKM_SHA256_RSA_PKCS);
       session.signInit(signingMechanism, privateKey);
       return session.sign(encodedDigestInfo);
       } catch (Exception e) {
        throw new RuntimeException("Error", e);
       }
   }

   @Override
   public org.bouncycastle.asn1.x509.AlgorithmIdentifier getAlgorithmIdentifier() {
      return new org.bouncycastle.asn1.x509.AlgorithmIdentifier(
            org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers.sha256WithRSAEncryption);
   }

   @Override
   public OutputStream getOutputStream() {
      return outputStream;
   }
}

and now I am signing the hash like:

//already initialize session and extracted RSAPrivateKey
//taking current session (iaik.pkcs.pkcs11) and RSAPrivateKey
IAIKPKCS11ContentSigner signer = new IAIKPKCS11ContentSigner(session, pk); 

OutputStream outputStream = signer.getOutputStream();
outputStream.write(hash); //writing the hash of the document to sign 

byte[] signature = signer.getSignature(); //fetching signature from the content signer
ContentInfo contentInfo = new ContentInfo(ContentInfo.DATA_OID, null);
X509Certificate[] certificates; //certificate for the key above;
AlgorithmId[] digestAlgorithmIds; // SHA-256 
SignerInfo si; //creating signer info using cert attributes and signed content signature;
SignerInfo[] signerInfos = {si};
PKCS7 p7 = new PKCS7(digestAlgorithmIds, contentInfo, certificates, signerInfos);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
p7.encodeSignedData(bytes);
output = bytes.toByteArray();

But while attaching this pkcs7 as deferred signature on a pdf, getting document has been altered or corrupted. Is this the right approach to sign? Any pointers if I am doing anything wrong here?


Solution

  • You use the mechanism PKCS11Constants.CKM_SHA256_RSA_PKCS. But that mechanism does calculate the hash of the data, wrap it in a DigestInfo structure, apply PKCS#1 1.5 padding, and encrypt.

    As far as I understand your code, though, you already have calculated the hash and wrapped it in a DigestInfo structure. So you only want PKCS#1 1.5 padding and encryption to be applied.

    Thus, you may want to use the mechanism PKCS11Constants.CKM_RSA_PKCS instead.