Question

I have method in order to sign document.

public static void sign(String src, String dest,
            java.security.cert.Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, CryptoStandard subfilter,
            String reason, String location) throws GeneralSecurityException,
            IOException, DocumentException, com.itextpdf.text.DocumentException {

        // Creating the reader and the stamper
        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(dest);
        PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');

        // Creating the appearance
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setVisibleSignature(new Rectangle(0, 100, 50, 300), 1, "sig");

        // Creating the signature
        ExternalDigest digest = new BouncyCastleDigest();
        ExternalSignature signature = new PrivateKeySignature(pk, digestAlgorithm, provider);     
        MakeSignature.signDetached(appearance, digest, signature, chain, null,null, null, 0, subfilter);


    }

When I use BouncyCastleProvider everything works well.

BouncyCastleProvider provider = new BouncyCastleProvider();
        Security.addProvider(provider);
        KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
        ks.load(new FileInputStream(KEYSTORE), PASSWORD);
        String alias = (String) ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey) ks.getKey(alias, PASSWORD);
        java.security.cert.Certificate[] chain = ks.getCertificateChain(alias);

        for (int i = 0; i < chain.length; i++) {
            System.out.println(("Public Key"+chain[i].getPublicKey()));
        }
        System.out.println("Priate Key:"+       Arrays.toString(pk.getEncoded()));
        System.out.println("Lengh of key is:"+       Arrays.toString(pk.getEncoded()).length());


        sign(SRC, String.format(DEST, 1), chain, pk,DigestAlgorithms.SHA256, provider.getName(),CryptoStandard.CMS, "Test 1", "Ghent" );

it signs well, and the result is that:

Public Key Sun RSA public key, 2048 bits. I have only Self Sign sertificate here. Created By Key tool.
  modulus: 19757623340732442247234242 ... and etc
  public exponent: 65537
Priate Key:[48, -126, 4, -66, 2, 1, ... and etc ]
Lengh of key is:5618

Wen I use My provider. I have No Runtime Error or exceptipon but when i open pdf file , I have singature error. adobe reader have that allert ":At least one signature is invalid:. When I try to see the certificate, I have that alert "Error during signature verification. Error encountered while validating. Internal Cryptographic library error. Error Code: 0x2726""

A is root CA. B is Children of A. C is signer certificate. I have also T certificate, Children of A A

  MyProvider provider= newMyProvider();


    CallbackHandler console= new com.sun.security.auth.callback.TextCallbackHandler();
    provider.setCallbackHandler(console);    

    Security.addProvider(provider);
    KeyStore ks = KeyStore.getInstance("KeyStore");
    ks.load(null, new char[] {});


    List < java.security.cert.Certificate  > chainList = new ArrayList< java.security.cert.Certificate>();

    System.out.println("My Certificates in chain:");
      Enumeration<String> aliases = ks.aliases();
        while (aliases.hasMoreElements()) {
            String alias = aliases.nextElement();

                  if( alias.equalsIgnoreCase("T")
                 continue;

            if (ks.isCertificateEntry(alias)) {
                X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
                if(!chainList.contains(ks.getCertificate(alias))){
                    chainList.add(ks.getCertificate(alias));
                }
                System.out.println("Public Key"+(cert.getPublicKey()));
            }
        }
        java.security.cert.Certificate[]  chain =  new   java.security.cert.Certificate[chainList.size()];
        chainList.toArray(chain);
enter code here




    PrivateKey pk = (PrivateKey) ks.getKey("C", null);
    System.out.println("Priate Key:"+       Arrays.toString(pk.getEncoded()));
    System.out.println("Lengh of key is:"+       Arrays.toString(pk.getEncoded()).length());     
    sign(SRC, String.format(DEST, 1), chain,  pk, DigestAlgorithms.SHA256, provider.getName(), CryptoStandard.CMS, "Test sign", "testing");

Result of command line is that:

  My Certificates in chain.  First is Main CA .
Public Key Sun RSA public key, 4096 bits
  modulus: 7233349847339212226486269.... and etc
  public exponent: 65537

Public Key Sun RSA public key, 4096 bits
  modulus: 8191375554227623097382171... and etc
  public exponent: 65537

Public Key  Sun RSA public key, 4096 bits
  modulus: 8221477538578824228200634... and etc
  public exponent: 65537

Priate Key:[66, 69, 105, 106, 105, 192 ... and etc]
Lengh of key is:306

When I open PDF file, I have singature error, if I use my provider.

:At least one signature is invalid:.
When I try to see the certificate, I have that alert "Error during signature verification. Error encountered while validating. Internal Cryptographic library error. Error Code: 0x2726"

Was it helpful?

Solution

Looking into the signature (using an ASN.1 dump) reveals that:

  1. It includes in its certificates CertificateSet the certificates issued for
    • C = GE,O = Ministry of Justice of Georgia,OU = Civil Registry Agency,CN = GEO Root CA
    • C = GE,O = Ministry of Justice of Georgia,OU = Civil Registry Agency,CN = GEO Signing CA
    • C = GE,O = Ministry of Justice of Georgia,OU = Civil Registry Agency,CN = GEO Authentication CA
  2. It claims in its SignerInfo's sid SignerIdentifier to have used the private key associated with the "GEO Root CA" certificate to sign

Looking at your code, issue 1 indicates that your key store contents are different from what you think. On the one hand "GEO Authentication CA" is present in it at least once with an alias not equal to "T", and on the other hand your signer certificate does not seem to be included (or has alias "T" and is ignored due to that). Your private key is included, though, as "C".

Issue 2 is due to the fact that iText expects the first entry of the certificates array to be the signer certificate. As "GEO Root CA" seems to be the first certificate found in your key store, it is the first certificate in your chainList, so also in your chain, and therefore assumed by iText to be the signer certificate.

To resolve your issue you have to

  1. inspect your key store and make sure it also contains your signer certificate, not merely the associated private key, and
  2. make sure your signer certificate is first in your chain certificate array.

BTW, have you yet tried using

Certificate[] chain = ks.getCertificateChain("C");

to retrieve the certificate chain? This is generally used in Digital Signatures for PDF documents...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top