/*
 * 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.domain.model.platform;

import java.security.KeyPair;
import java.security.Security;
import java.util.Calendar;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mockito;

import com.scytl.cryptolib.api.asymmetric.AsymmetricServiceAPI;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.asymmetric.service.AsymmetricService;
import com.scytl.cryptolib.certificates.cryptoapi.CryptoAPIX509Certificate;
import com.scytl.cryptolib.primitives.primes.utils.PemUtils;
import com.scytl.products.ov.commons.beans.domain.model.platform.PlatformInstallationData;
import com.scytl.products.ov.commons.beans.validation.CertificateValidationService;
import com.scytl.products.ov.commons.beans.validation.CertificateValidationServiceImpl;
import com.scytl.products.ov.commons.domain.model.BaseRepository;

public class PlatformInstallationDataHandlerTest {

//  Common Name: Scytl Root CA
//  Organization: Scytl
//  Organization Unit: Online Voting
//  Locality:
//  Country: ES
//  Valid From: Calendar.getInstance()
//  Valid To: Calendar.getInstance() + 1y
//  Issuer: Scytl Root CA, Scytl (self)
	private static String PLATFORM;

//  Common Name: swisspost Root CA
//  Organization: SwissPost
//  Organization Unit: Online Voting
//  Locality:
//  Country: CH
//  Valid From: Calendar.getInstance()
//  Valid To: Calendar.getInstance() + 2y
//  Issuer: VOTE MAEDI QUALIF CERT 1, MINISTERE DES AFFAIRES ETRANGERES (maedi ca)
    private static String PLATFORM_RECERTIFIED;

//  Common Name: VOTE MAEDI QUALIF CERT 1
//  Organization: MINISTERE DES AFFAIRES ETRANGERES
//  Organization Unit: 0002 12000601000025
//  Country: FR
//  Valid From: Calendar.getInstance()
//  Valid To: Calendar.getInstance() + 3y
//  Issuer: AC QUALIF INFRASTRUCTURE 2, MINISTERE DES AFFAIRES ETRANGERES (somebody else)
    private static String MAEDI_CA;

    @SuppressWarnings("unchecked")
    protected BaseRepository<PlatformCAEntity, Long> repository = Mockito.mock(BaseRepository.class);

    private CertificateValidationService certificateValidationService = new CertificateValidationServiceImpl();
    
    @BeforeClass
    public static void setUp() throws GeneralCryptoLibException {
        Security.addProvider(new BouncyCastleProvider());
        
        createCertificates();
    }

	private static void createCertificates() throws GeneralCryptoLibException {
		AsymmetricServiceAPI asymmetricService = new AsymmetricService();
    	Calendar platformNow = Calendar.getInstance();
    	Calendar platformFuture = Calendar.getInstance();
    	platformFuture.add(Calendar.YEAR, 1);
		KeyPair platformKeyPair = asymmetricService.getKeyPairForSigning();
    	CryptoAPIX509Certificate createRootSelfSignedCertificate = CertificateUtil.createRootSelfSignedCertificate("Scytl Root CA", "Scytl", 
    			"Online Voting", "CH", platformNow.getTime(), platformFuture.getTime(), platformKeyPair);
    	PLATFORM = PemUtils.certificateToPem(createRootSelfSignedCertificate.getCertificate());
    	
    	Calendar maintTrustedNow = Calendar.getInstance();
    	Calendar maintTrustedFuture = Calendar.getInstance();
    	maintTrustedFuture.add(Calendar.YEAR, 3);
		KeyPair maintTrustedAuthKeyPair = asymmetricService.getKeyPairForSigning();
    	CryptoAPIX509Certificate maintTrustedAuthSelfSignedCertificate = CertificateUtil.createRootSelfSignedCertificate("AC QUALIF INFRASTRUCTURE 2", 
    			"MINISTERE DES AFFAIRES ETRANGERES",  "MINISTERE DES AFFAIRES ETRANGERES", "FR", maintTrustedNow.getTime(), maintTrustedFuture.getTime(), maintTrustedAuthKeyPair);
    	
    	Calendar maediNow = Calendar.getInstance();
    	Calendar maediFuture = Calendar.getInstance();
    	maediFuture.add(Calendar.YEAR, 2);
		KeyPair maediKeyPair = asymmetricService.getKeyPairForSigning();
    	CryptoAPIX509Certificate maediCert = CertificateUtil.createIntermediateCertificate("VOTE MAEDI QUALIF CERT 1", 
    			"MINISTERE DES AFFAIRES ETRANGERES", "0002 12000601000025", "FR", maediNow.getTime(), maediFuture.getTime(), maediKeyPair, maintTrustedAuthKeyPair, maintTrustedAuthSelfSignedCertificate.getSubjectDn());
    	MAEDI_CA = PemUtils.certificateToPem(maediCert.getCertificate());
    	
    	Calendar platformRecertifiedNow = Calendar.getInstance();
    	Calendar platformRecertifiedFuture = Calendar.getInstance();
    	platformRecertifiedFuture.add(Calendar.YEAR, 1);
		KeyPair platformRecertifiedKeyPair = asymmetricService.getKeyPairForSigning();
    	CryptoAPIX509Certificate platformRecertifiedCert = CertificateUtil.createIntermediateCertificate("swisspost Root CA", "SwissPost", 
    			"Online Voting", "CH", platformRecertifiedNow.getTime(), platformRecertifiedFuture.getTime(), platformRecertifiedKeyPair, maediKeyPair, maediCert.getSubjectDn());
    	PLATFORM_RECERTIFIED = PemUtils.certificateToPem(platformRecertifiedCert.getCertificate());
	}
    
    @Test
    public void testPlatformCertificateChain() {
        PlatformInstallationData data = new PlatformInstallationData();
        try {
            data.setPlatformRootCaPEM(PLATFORM_RECERTIFIED);
            data.setPlatformRootIssuerCaPEM(MAEDI_CA);
            PlatformInstallationDataHandler.savePlatformCertificateChain(data, repository, certificateValidationService,
                new PlatformCAEntity(), new PlatformCAEntity());
        } catch (Exception e) {
            Assert.fail();
        }

    }

    @Test
    public void testInvalidPlatformCertificateChain() {
        PlatformInstallationData data = new PlatformInstallationData();
        try {
            data.setPlatformRootCaPEM(MAEDI_CA);
            data.setPlatformRootIssuerCaPEM(PLATFORM);
            PlatformInstallationDataHandler.savePlatformCertificateChain(data, repository, certificateValidationService,
                new PlatformCAEntity(), new PlatformCAEntity());
            Assert.fail();
        } catch (Exception e) {
            Assert.assertEquals("Certificate validation failed for the following validation types: [SIGNATURE]",
                e.getMessage());
        }

    }

    @Test
    public void testSelfSignedPlatformCertificate() {
        PlatformInstallationData data = new PlatformInstallationData();
        try {
            data.setPlatformRootCaPEM(PLATFORM);
            PlatformInstallationDataHandler.savePlatformCertificateChain(data, repository, certificateValidationService,
                new PlatformCAEntity(), new PlatformCAEntity());
        } catch (Exception e) {
            Assert.fail();
        }

    }

    @Test
    public void testInvalidSelfSignedPlatformCertificate() {
        PlatformInstallationData data = new PlatformInstallationData();
        try {
            data.setPlatformRootCaPEM(PLATFORM_RECERTIFIED);
            PlatformInstallationDataHandler.savePlatformCertificateChain(data, repository, certificateValidationService,
                new PlatformCAEntity(), new PlatformCAEntity());
            Assert.fail();
        } catch (Exception e) {
            Assert.assertEquals("Certificate validation failed for the following validation types: [SIGNATURE]",
                e.getMessage());
        }

    }

}
