//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2025 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

// This file shows a sample implementation of PDFNet's SignatureHandler class using
// the Boucy Castle library.

// requires Bouncy Castle library.

import java.io.FileInputStream;
import java.security.cert.Certificate;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.ArrayList;

import com.pdftron.sdf.Obj;
import com.pdftron.sdf.SignatureHandler;

import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.CMSTypedData;
import org.bouncycastle.cms.CMSProcessableByteArray;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.CMSSignedDataGenerator;
import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;

public class BCSignatureHandler extends SignatureHandler
{
    private ArrayList<Byte> m_data;
    private String m_pfx;
    private String m_password;
    
    public BCSignatureHandler(String pfx, String password)
    {
        this.m_pfx = pfx;
        this.m_password = password;
        m_data = new ArrayList<Byte>();
    }
    
    @Override
    public String getName()
    {
        return ("Adobe.PPKLite");
    }

    @Override
    public void appendData(byte[] data)
    {
        for (int i = 0; i < data.length; i++)
            m_data.add(data[i]);
        return;
    }
    
    @Override
    public boolean reset()
    {
        m_data.clear();
        return (true);
    }

    @Override
    public byte[] createSignature()
    {
        try {
            java.security.Security.addProvider(new BouncyCastleProvider());
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            FileInputStream fis = new FileInputStream(m_pfx);
            keyStore.load(fis, m_password.toCharArray());
            String alias = keyStore.aliases().nextElement();
            PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, m_password.toCharArray());
            Certificate[] certChain = keyStore.getCertificateChain(alias);
            fis.close();
    
            Store certStore = new JcaCertStore(Arrays.asList(certChain));
            CMSSignedDataGenerator sigGen = new CMSSignedDataGenerator();
            ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(privateKey);
            sigGen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(signer, (X509Certificate) certChain[0]));
            sigGen.addCertificates(certStore);
            byte[] bdata = new byte[m_data.size()];
            for (int i = 0; i < m_data.size(); i++)
                bdata[i] = m_data.get(i).byteValue();
            CMSTypedData data = new CMSProcessableByteArray(bdata);
            CMSSignedData sigData = sigGen.generate(data, false);
            return (sigData.getEncoded());
        }
        catch (Exception ex) {
            System.err.println(ex.getMessage());
            ex.printStackTrace(System.err);
        }
        return null;
    }
}
