package model;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;


import org.bouncycastle.jce.provider.BouncyCastleProvider;

import sun.misc.BASE64Encoder;
import sun.security.x509.AlgorithmId;
import sun.security.x509.CertificateAlgorithmId;
import sun.security.x509.CertificateIssuerName;
import sun.security.x509.CertificateSerialNumber;
import sun.security.x509.CertificateSubjectName;
import sun.security.x509.CertificateValidity;
import sun.security.x509.CertificateVersion;
import sun.security.x509.CertificateX509Key;
import sun.security.x509.X500Name;
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;

public class MyCA {
	private static String PRIVATE_KEY;
	private static ArrayList<String> SERIALNUMBER_LIST;
	
	public MyCA() {
		Security.addProvider(new BouncyCastleProvider());
		PRIVATE_KEY = "D:/priCA.key";
		SERIALNUMBER_LIST = new ArrayList<String>();
		SERIALNUMBER_LIST.add("1354445180");
		SERIALNUMBER_LIST.add("1354445208");
	}


	public void createCertificate(X500Name subject, PublicKey publicKey, String path)
			throws CertificateException, IOException, InvalidKeyException,
			NoSuchAlgorithmException, NoSuchProviderException,
			SignatureException, ClassNotFoundException {
		// CertInfo
		X509CertInfo certInfo = new X509CertInfo();
		certInfo.set(X509CertInfo.VERSION, new CertificateVersion(2));
		certInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(
				(int) (System.currentTimeMillis() / 1000)));
		certInfo.set(CertificateAlgorithmId.NAME, new CertificateAlgorithmId(
				new AlgorithmId(AlgorithmId.md2WithRSAEncryption_oid)));
		certInfo.set(X509CertInfo.ISSUER, new CertificateIssuerName(
				new X500Name(
						"CN=NongLamUniversity, OU=JavaSoft, O=Sun Microsystems, C=US")));
		certInfo.set(X509CertInfo.VALIDITY, new CertificateValidity(new Date(),
				new Date(System.currentTimeMillis() + 365L * 24L * 60L * 60L
						* 1000L)));
		certInfo.set(X509CertInfo.SUBJECT, new CertificateSubjectName(subject));
		certInfo.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));

		X509CertImpl certImpl = new X509CertImpl(certInfo);
		
		//Get Private Key from file
		FileInputStream fis = new FileInputStream(PRIVATE_KEY);
		ObjectInputStream ois = new ObjectInputStream(fis);
		PrivateKey priKeyObject =  (PrivateKey) ois.readObject();
		ois.close();
		fis.close();
		// End
		
		certImpl.sign(priKeyObject, "MD5WithRSA");
		FileOutputStream fos = new FileOutputStream(path);
		fos.write(certImpl.getEncoded());
		fos.close();
	}

	public boolean verifyCertificate(String cerUser, String cerUserInCA) throws CertificateException, IOException, ClassNotFoundException, InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException{
		boolean result = false;
		// Load File CertUser
		FileInputStream cerIn1 = new FileInputStream(cerUser);
		BouncyCastleProvider provider1 = new BouncyCastleProvider();
		CertificateFactory cf1 = CertificateFactory.getInstance("X.509" , provider1);
		X509Certificate cert1= (X509Certificate) cf1.generateCertificate(cerIn1);
		// End
		
		String cerSerial = cert1.getSerialNumber().toString();
		for (String serial : SERIALNUMBER_LIST) {
			if (cerSerial.equals(serial)){
				result = true;
				break;
			}
		}
		if (!result) return false;
		
		// Load File CertUserInCA
		FileInputStream cerIn2 = new FileInputStream(cerUserInCA);
		BouncyCastleProvider provider2 = new BouncyCastleProvider();
		CertificateFactory cf2 = CertificateFactory.getInstance("X.509" , provider2);
		X509Certificate cert2= (X509Certificate) cf2.generateCertificate(cerIn2);
		// End
		
		String sign1 = new BASE64Encoder().encode(cert1.getSignature());
		String sign2 = new BASE64Encoder().encode(cert2.getSignature());
		if (sign1.equals(sign2)) result = true;
		else result = false;
		cerIn1.close();
		cerIn2.close();
		
		return result;
	}
	
	public static void main(String[] args) throws CertificateException,
			KeyStoreException, NoSuchAlgorithmException, IOException,
			InvalidKeyException, NoSuchProviderException, SignatureException, ClassNotFoundException {
		MyCA lc = new MyCA();
		
		//Get Public Key from file
		FileInputStream fis = new FileInputStream("D:/pub.key");
		ObjectInputStream ois = new ObjectInputStream(fis);
		PublicKey pubKeyObject =  (PublicKey) ois.readObject();
		ois.close();
		fis.close();
		// End
		
		lc.createCertificate(new X500Name("CN=Luan Nguyen, OU=ATBMT, O=Nong Lam, C=Vietnam"), pubKeyObject, "D:/lxt.cer");
		
		System.out.println(lc.verifyCertificate("D:/lxt.cer", "D:/lxt.cer"));
	}
}
