IaikContentSigner.java

package io.mersel.dss.signer.api.services.keystore.iaik;

import eu.europa.esig.dss.enumerations.DigestAlgorithm;
import eu.europa.esig.dss.enumerations.EncryptionAlgorithm;
import eu.europa.esig.dss.enumerations.SignatureAlgorithm;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;

/**
 * BouncyCastle {@link ContentSigner} adaptörü — CMS / PKCS#7 imzalama
 * akışlarında JCA {@code PrivateKey} yerine HSM'i kullanır.
 *
 * <p>BC, {@code CMSSignedDataGenerator}, {@code JcaSignerInfoGeneratorBuilder}
 * gibi yapıların imza atan tarafa "ContentSigner" üzerinden bağlandığı
 * pattern'i izler. Pure-software akış {@code JcaContentSignerBuilder} ile
 * {@link java.security.PrivateKey} üretirken bu sınıf aynı interface'i
 * implement eder ama {@link Pkcs11Signer#sign} ile HSM C_Sign'a delege eder.</p>
 *
 * <p>Kullanım: PAdES gibi BC CMS akışlarında
 * {@code generator.addSignerInfoGenerator(builder.build(new IaikContentSigner(...)))}.</p>
 *
 * <p>Thread-safety: bu sınıf state'li ({@code ByteArrayOutputStream} biriktirir);
 * her imzalama için yeni instance oluşturulmalıdır.</p>
 */
public final class IaikContentSigner implements ContentSigner {

    private static final DefaultSignatureAlgorithmIdentifierFinder SIG_ALG_FINDER =
        new DefaultSignatureAlgorithmIdentifierFinder();

    private final Pkcs11Signer signer;
    private final SignatureAlgorithm signatureAlgorithm;
    private final AlgorithmIdentifier algorithmIdentifier;
    private final ByteArrayOutputStream buffer = new ByteArrayOutputStream(4096);

    public IaikContentSigner(Pkcs11Signer signer, DigestAlgorithm digestAlgorithm) {
        this.signer = signer;
        EncryptionAlgorithm encryption = EncryptionAlgorithm.forKey(
            signer.getCertificate().getPublicKey());
        this.signatureAlgorithm = SignatureAlgorithm.getAlgorithm(encryption, digestAlgorithm);
        if (this.signatureAlgorithm == null) {
            throw new IllegalArgumentException(
                "DSS SignatureAlgorithm bulunamadı: enc=" + encryption + ", digest=" + digestAlgorithm);
        }
        this.algorithmIdentifier = SIG_ALG_FINDER.find(signatureAlgorithm.getJCEId());
    }

    @Override
    public AlgorithmIdentifier getAlgorithmIdentifier() {
        return algorithmIdentifier;
    }

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

    @Override
    public byte[] getSignature() {
        return signer.sign(buffer.toByteArray(), signatureAlgorithm);
    }
}