/*
 * 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.config.utils;

import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.certificates.bean.X509CertificateType;
import com.scytl.cryptolib.certificates.bean.X509DistinguishedName;
import com.scytl.cryptolib.certificates.factory.CryptoX509Certificate;
import com.scytl.cryptolib.certificates.utils.X509CertificateChainValidator;

public class ChainValidator {

    public static void validateChain(Certificate rootCertificate, Certificate subjectCertificate,
            X509CertificateType type) throws GeneralCryptoLibException, CertificateException {
        // Trusted certificate -> Plattform Root CA
        // Get X509 certificate
        X509Certificate plattformRootCA = (X509Certificate) rootCertificate;
        X509DistinguishedName distinguishedPlatformRootCA = getDistinguishName(plattformRootCA);

        // Root vs Root chain validation
        X509Certificate[] certificateChainRoot = {};
        X509DistinguishedName[] subjectDnsRoot = {};

        // Validate
        boolean validateCertRootResult = validateCert(plattformRootCA, distinguishedPlatformRootCA,
            X509CertificateType.CERTIFICATE_AUTHORITY, certificateChainRoot, subjectDnsRoot, plattformRootCA);

        if (validateCertRootResult) {
            // Get X509 certificate
            X509Certificate tenantCA = (X509Certificate) subjectCertificate;
            X509DistinguishedName subjectDnTenantCA = getDistinguishName(tenantCA);

            X509Certificate[] certificateChain = {};
            X509DistinguishedName[] subjectDns = {};

            // Validate
            if (!validateCert(tenantCA, subjectDnTenantCA, type, certificateChain, subjectDns, plattformRootCA)) {
                throw new RuntimeException("The chain of certificates hasn't been validated correctly");
            }

        }

    }

    private static X509DistinguishedName getDistinguishName(X509Certificate x509Cert) throws GeneralCryptoLibException {
        CryptoX509Certificate wrappedCertificate = new CryptoX509Certificate(x509Cert);
        return wrappedCertificate.getSubjectDn();
    }

    private static boolean validateCert(X509Certificate certLeaf, X509DistinguishedName subjectDnsLeaf,
            X509CertificateType certType, X509Certificate[] certChain, X509DistinguishedName[] subjectDns,
            X509Certificate certTrusted) throws GeneralCryptoLibException {
        X509CertificateChainValidator certificateChainValidator =
            createCertificateChainValidator(certLeaf, subjectDnsLeaf, certType, certChain, subjectDns, certTrusted);
        List<String> failedValidations = certificateChainValidator.validate();
        return (failedValidations == null || failedValidations.isEmpty());
    }

    private static X509CertificateChainValidator createCertificateChainValidator(X509Certificate certLeaf,
            X509DistinguishedName subjectDnsLeaf, X509CertificateType certType, X509Certificate[] certChain,
            X509DistinguishedName[] subjectDns, X509Certificate certTrusted) throws GeneralCryptoLibException {

        return new X509CertificateChainValidator(certLeaf, certType, subjectDnsLeaf, certChain, subjectDns,
            certTrusted);
    }
}
