/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.products.ov.commons.sign;

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.products.ov.commons.beans.domain.model.messaging.CryptolibPayloadSignature;
import com.scytl.products.ov.commons.beans.domain.model.messaging.Payload;
import com.scytl.products.ov.commons.beans.domain.model.messaging.PayloadSignature;
import com.scytl.products.ov.commons.beans.domain.model.messaging.PayloadSignatureException;

import java.io.IOException;
import java.security.PrivateKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.security.cert.X509Certificate;
import java.util.Objects;

/**
 * A service that signs and verifies payloads based on Scytl's CryptoLib.
 */
public class CryptolibPayloadSigner implements PayloadSigner {

	private static final Logger LOG = LoggerFactory.getLogger(CryptolibPayloadSigner.class);

    private final AsymmetricServiceAPI asymmetricService;

    /**
     * Initialises the service with the signing key.
     *
     * @param asymmetricService an instance of the service used for signing
     */
    public CryptolibPayloadSigner(AsymmetricServiceAPI asymmetricService) {
        this.asymmetricService = asymmetricService;
    }

    @Override
    public PayloadSignature sign(Payload payload, PrivateKey signingKey, X509Certificate[] certificateChain)
            throws PayloadSignatureException {
        LOG.info("Signing payload {}...", payload);

        Objects.requireNonNull(payload, "A payload is required for signing");
        Objects.requireNonNull(signingKey, "A signing key is required for signing");
        Objects.requireNonNull(certificateChain, "The verification key's certificate chain is required for signing");

        try {
            byte[] signatureContents = asymmetricService.sign(signingKey, payload.getSignableContent());
            PayloadSignature payloadSignature = new CryptolibPayloadSignature(signatureContents, certificateChain);
            LOG.info("Payload {} signed successfully", payload);

            return payloadSignature;
        } catch (IOException | GeneralCryptoLibException e) {
            LOG.error("Failed signing payload {}!", payload, e);
            throw new PayloadSignatureException(e);
        }
    }
}
