SigningMaterial.java

package io.mersel.dss.signer.api.models;

import eu.europa.esig.dss.model.x509.CertificateToken;
import eu.europa.esig.dss.enumerations.SignatureAlgorithm;
import io.mersel.dss.signer.api.services.keystore.iaik.Pkcs11Signer;

import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * İmzalama için gereken kriptografik materyali kapsayan immutable nesne.
 *
 * <p>İki ayrı arka uç desteklenir:</p>
 * <ul>
 *   <li><b>PFX / PKCS#12</b> → {@link #getPrivateKey()} dolu, JCA
 *       {@code Signature.initSign(privateKey)} ile imzalanır.</li>
 *   <li><b>HSM / PKCS#11 (IAIK üzerinden)</b> → {@link #getPkcs11Signer()}
 *       dolu, özel anahtar handle'ı HSM'de kalır;
 *       {@link Pkcs11Signer#sign(byte[], eu.europa.esig.dss.enumerations.SignatureAlgorithm)}
 *       çağrısı C_Sign'e delege eder.</li>
 * </ul>
 *
 * <p>Belge seviyesi servislerin ortak kontratı {@link #sign(byte[], SignatureAlgorithm)}
 * metodudur. Böylece XAdES/CAdES/PAdES/WS-Security katmanları PFX mi HSM mi
 * kullanıldığını bilmek zorunda kalmaz.</p>
 */
public final class SigningMaterial {

    private final SigningBackend signingBackend;
    private final X509Certificate signingCertificate;
    private final List<X509Certificate> certificateChain;
    private final List<CertificateToken> certificateTokens;

    /** PFX yolu için kurucu. */
    public SigningMaterial(PrivateKey privateKey,
                          X509Certificate signingCertificate,
                          List<X509Certificate> certificateChain) {
        this(new JcaSigningBackend(privateKey), signingCertificate, certificateChain);
    }

    /** HSM yolu için kurucu. */
    public SigningMaterial(Pkcs11Signer pkcs11Signer,
                          X509Certificate signingCertificate,
                          List<X509Certificate> certificateChain) {
        this(new Pkcs11SigningBackend(pkcs11Signer), signingCertificate, certificateChain);
    }

    private SigningMaterial(SigningBackend signingBackend,
                            X509Certificate signingCertificate,
                            List<X509Certificate> certificateChain) {
        if (signingBackend == null) {
            throw new IllegalArgumentException("SigningMaterial: signingBackend null olamaz");
        }
        if (signingCertificate == null) {
            throw new IllegalArgumentException("SigningMaterial: signingCertificate null olamaz");
        }
        if (certificateChain == null || certificateChain.isEmpty()) {
            throw new IllegalArgumentException("SigningMaterial: certificateChain boş olamaz");
        }
        this.signingBackend = signingBackend;
        this.signingCertificate = signingCertificate;
        this.certificateChain = Collections.unmodifiableList(new ArrayList<>(certificateChain));
        this.certificateTokens = this.certificateChain.stream()
                .map(CertificateToken::new)
                .collect(Collectors.toList());
    }

    /**
     * JCA özel anahtarı. PFX yolunda dolu, HSM yolunda {@code null}.
     * HSM yolunda imza için {@link #getPkcs11Signer()} kullanılmalıdır.
     */
    public PrivateKey getPrivateKey() {
        if (signingBackend instanceof JcaSigningBackend) {
            return ((JcaSigningBackend) signingBackend).getPrivateKey();
        }
        return null;
    }

    /**
     * HSM (PKCS#11) yolunda imza atan token. PFX yolunda {@code null}.
     */
    public Pkcs11Signer getPkcs11Signer() {
        if (signingBackend instanceof Pkcs11SigningBackend) {
            return ((Pkcs11SigningBackend) signingBackend).getSigner();
        }
        return null;
    }

    /** PKCS#11 yolundayız mi? */
    public boolean isPkcs11() {
        return signingBackend.isPkcs11();
    }

    public String getBackendName() {
        return signingBackend.getName();
    }

    public SigningBackend getSigningBackend() {
        return signingBackend;
    }

    public byte[] sign(byte[] dataToSign, SignatureAlgorithm signatureAlgorithm) {
        return signingBackend.sign(dataToSign, signatureAlgorithm);
    }

    public X509Certificate getSigningCertificate() {
        return signingCertificate;
    }

    public List<X509Certificate> getCertificateChain() {
        return certificateChain;
    }

    public List<CertificateToken> getCertificateTokens() {
        return certificateTokens;
    }

    public CertificateToken getPrimaryCertificateToken() {
        return certificateTokens.get(0);
    }
}