package HttpsServerAndClient;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.concurrent.atomic.AtomicInteger;
import java.security.Security;
import javax.net.ServerSocketFactory;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManagerFactory;

/**
 * Mimic a Test HTTP(S) based server.
 */
public class Server extends Thread {

	public static void main(String[] args) throws Exception {

		Security.setProperty("jdk.tls.disabledAlgorithms", "DH keySize < 2048");
		System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
		System.setProperty("jdk.tls.allowUnsafeServerCertChange", "true");
		Server server = Server.getInstance("TLSv1.2", KeyType.RSA2048_SHA256, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256");
		server.start();

		//server.stopServer();
	}

	private static final AtomicInteger NUM_OF_REQ = new AtomicInteger();
	private ServerSocket serverSocket = null;
	private volatile boolean ready = false;
	private String url;
	private int port;
	private final String protocol;
	private final KeyType keyType;
	private final String[] ciphers;

	private Server(String protocol, KeyType keyType, String... ciphers) {
		this.protocol = protocol;
		this.keyType = keyType;
		this.ciphers = ciphers;
	}

	/**
	 * Creates a SSL server instance based on protocol, keyType and ciphers.
	 */
	public static Server getInstance(String protocol, KeyType keyType, String... ciphers) {
		return new Server(protocol, keyType, ciphers);
	}

	/**
	 * Creates a HTTP server instance based on protocol, keyType and ciphers.
	 */
	public static Server getInstance() {
		return new Server(null, null, (String[])null);
	}

	@Override
	public void run() {
		try {
			String hostName = InetAddress.getLocalHost().getHostAddress();
			//Use proper keytypes to be configured with the server instance.
			serverSocket = (keyType == null) ? createServerSocket() : createSSLServerSocket(keyType);
			this.port = serverSocket.getLocalPort();
			this.url = String.format("http%s://%s:%s/", ((keyType == null) ? "" : "s"), hostName, serverSocket.getLocalPort());
			System.out.printf("Server URL: %s%n", this.url);
			ready = true;
			addShutDownHook();
			handleRequest(serverSocket);
		} catch (Exception e) {
			ready = false;
			throw new RuntimeException(e);
		}
	}

	public int gePort() {
		return this.port;
	}

	protected ServerSocket createServerSocket()
			throws Exception {
		ServerSocketFactory sFactory = ServerSocketFactory.getDefault();
		ServerSocket sSocket = sFactory.createServerSocket(0);
		return sSocket;
	}

	protected ServerSocket createSSLServerSocket(KeyType keyType)
			throws Exception {
		SSLContext context = createSSLContext(null, keyType.getEndCert(),
				keyType.getPrivateKey(), keyType.getKeyType());
		SSLServerSocketFactory sFactory = context.getServerSocketFactory();
		SSLServerSocket sSocket = (SSLServerSocket) sFactory.createServerSocket(0);
		if(this.ciphers != null) {
			sSocket.setEnabledCipherSuites(this.ciphers);
		}
		sSocket.setEnabledProtocols(new String[]{this.protocol});
		// This is a manual Test and it is possible that one might forget to
		// stop the server after using this Test and due to that ports will
		// be occupied un-necessarily. To avoid the situation the server
		// socket is enabled for 10 minute for idle case only.
		sSocket.setSoTimeout(10 * 60 * 60 * 1000);
		return sSocket;
	}

	/*
	 * Create an instance of SSLContext.
	 */
	protected SSLContext createSSLContext(
			String trustedCertStr,
			String keyCertStr,
			String privateKey,
			String keyType) throws Exception {

		KeyStore ts = null;     // trust store
		KeyStore ks = null;     // key store
		char passphrase[] = "passphrase".toCharArray();

		// Generate certificate from cert string.
		CertificateFactory cf = CertificateFactory.getInstance("X.509");
		// Import the trusted certs.
		if (trustedCertStr != null) {
			ts = KeyStore.getInstance("JKS");
			ts.load(null, null);

			Certificate trustedCert = null;
			try (ByteArrayInputStream is
					= new ByteArrayInputStream(trustedCertStr.getBytes())) {
				trustedCert = cf.generateCertificate(is);
			} finally {
				// It is no harm to ignore this Exception.
			}
			ts.setCertificateEntry("trusted-cert-" + keyType, trustedCert);
		}

		// Import the key materials.
		// Note that certification path bigger than one are not supported yet.
		boolean hasKeyMaterials
		= keyCertStr != null && privateKey != null;
		if (hasKeyMaterials) {
			ks = KeyStore.getInstance("JKS");
			ks.load(null, null);
			// Generate the private key.
			PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
					Base64.getMimeDecoder().decode(privateKey));
			KeyFactory kf = KeyFactory.getInstance(keyType);
			PrivateKey priKey = kf.generatePrivate(priKeySpec);

			Certificate keyCert = null;
			try (ByteArrayInputStream is
					= new ByteArrayInputStream(keyCertStr.getBytes())) {
				keyCert = cf.generateCertificate(is);
			} finally {
				// It is no harm to ignore this Exception.
			}
			Certificate[] chain = new Certificate[1];
			chain[0] = keyCert;
			// Import the key entry.
			ks.setKeyEntry("cert-" + keyType, priKey, passphrase, chain);

		}
		TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
		tmf.init(ts);
		// Create an SSLContext object.
		SSLContext context = SSLContext.getInstance(this.protocol);
		if (hasKeyMaterials && ks != null) {
			KeyManagerFactory kmf
			= KeyManagerFactory.getInstance("NewSunX509");
			kmf.init(ks, passphrase);
			context.init(
					kmf.getKeyManagers(), tmf.getTrustManagers(), null);
		} else {
			context.init(null, tmf.getTrustManagers(), null);
		}
		return context;
	}

	/**
	 * Handle each client request in different threads.
	 */
	protected static void handleRequest(ServerSocket serverSocket)
			throws Exception {
		while (!serverSocket.isClosed()) {
			try {
				final Socket socket = serverSocket.accept();
				Runnable task = new Runnable() {
					@Override
					public void run() {
						try {
							// Nothing cared, just pretend to read something
							BufferedReader reader = new BufferedReader(
									new InputStreamReader(
											socket.getInputStream()));
							reader.readLine();
							handleHTTPResponse(socket);
						} catch (Exception e) {
							// Nothing to do, the socket is one time use only. 
							e.printStackTrace(System.out);
						} finally {
							try {
								socket.close();
							} catch (IOException e) {
								// It is no harm to ignore this Exception.
							}
						}

					}
				};
				new Thread(task).start();
			} catch(SocketException e) {
				System.out.println("Server Socket closed.");
				return;
			}
		}
	}

	protected static void handleHTTPResponse(Socket socket) {
		try {
			sendSimpleResponse(socket, 200, "OK",
					"OK-Try: " + NUM_OF_REQ.incrementAndGet());
		} catch (IOException ioe) {
			throw new RuntimeException(ioe);
		}
	}

	/**
	 * Send simple HTTP response to client.
	 */
	protected static void sendSimpleResponse(Socket socket, int code,
			String tag, String content) throws IOException {

		PrintStream out = new PrintStream(socket.getOutputStream());
		out.print("HTTP/1.1 " + code + " " + tag + "\r\n");
		out.print("Connection: close\r\n");
		out.print("Content-Type: text/html; charset=UTF-8\r\n");
		out.print("Content-Length: " + (content.length() + 2) + "\r\n");
		out.print("\r\n");
		out.print(content + "\r\n");
		out.flush();
	}

	protected void addShutDownHook() {
		Runtime.getRuntime().addShutdownHook(
				new Thread(new Runnable() {
					public void run() {
						try {
							stopServer();
						} catch (Exception e) {
							// It is no harm to ignore this Exception.
							// e.printStackTrace();
						}
					}
				}));
	}

	public void stopServer() throws Exception {
		if (serverSocket != null) {
			ready = false;
			serverSocket.close();
		}
		System.out.println("Server Stopped..");
	}

	public boolean isReady() {
		return ready;
	}

	public String getUrl() {	
		String url = null;
		do {
			url = this.url;
		} while (!this.isReady());
		return url;
	}


	public enum KeyType {

		EC256_SHA256(
				"EC",
				// Put the entries in order of 
				// trustedCert, endCert, privateKey, Ciphers
				//
				// SHA256withECDSA, curve prime256v1
				// Validity
				//     Not Before: Nov  9 03:24:05 2016 GMT
				//     Not After : Oct 20 03:24:05 2037 GMT
				"-----BEGIN CERTIFICATE-----\n"
				+ "MIICHDCCAcGgAwIBAgIJAM83C/MVp9F5MAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n"
				+ "AlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZj\n"
				+ "ZTAeFw0xNjExMDkwMzI0MDVaFw0zNzEwMjAwMzI0MDVaMDsxCzAJBgNVBAYTAlVT\n"
				+ "MQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZjZTBZ\n"
				+ "MBMGByqGSM49AgEGCCqGSM49AwEHA0IABGeQXwyeNyU4UAATfwUbMO5zaREI21Wh\n"
				+ "bds6WDu+PmfK8SWsTgsgpYxBRui+fZtYqSmbdjkurvAQ3j2fvN++BtWjga0wgaow\n"
				+ "HQYDVR0OBBYEFDF/OeJ82qBSRkAm1rdZUPbWfDzyMGsGA1UdIwRkMGKAFDF/OeJ8\n"
				+ "2qBSRkAm1rdZUPbWfDzyoT+kPTA7MQswCQYDVQQGEwJVUzENMAsGA1UEChMESmF2\n"
				+ "YTEdMBsGA1UECxMUU3VuSlNTRSBUZXN0IFNlcml2Y2WCCQDPNwvzFafReTAPBgNV\n"
				+ "HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAKBggqhkjOPQQDAgNJADBGAiEAlHQY\n"
				+ "QFPlODOsjLVQYSxgeSUvYzMp0vP8naeVB9bfFG8CIQCFfrKZvhq9z3bOtlYKxs2a\n"
				+ "EWUjUZ82a1JTqkP+lgHY5A==\n"
				+ "-----END CERTIFICATE-----",
				// SHA256withECDSA, curve prime256v1
				// Validity
				//     Not Before: Nov  9 03:24:05 2016 GMT
				//     Not After : Jul 27 03:24:05 2036 GMT
				"-----BEGIN CERTIFICATE-----\n"
				+ "MIIB1DCCAXmgAwIBAgIJAKVa+4dIUjaLMAoGCCqGSM49BAMCMDsxCzAJBgNVBAYT\n"
				+ "AlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZj\n"
				+ "ZTAeFw0xNjExMDkwMzI0MDVaFw0zNjA3MjcwMzI0MDVaMFIxCzAJBgNVBAYTAlVT\n"
				+ "MQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZjZTEV\n"
				+ "MBMGA1UEAwwMSW50ZXJPcCBUZXN0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE\n"
				+ "h4vXNUJzULq4e7fAOvF0WiWU6cllOAMus1GqTFvcnRPOChl8suZsvksO0CpZqL3h\n"
				+ "jXmVX9dp1FV/rUBGLo1aG6NPME0wCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBSO8V5+\n"
				+ "bj0ik0T9BtJc4jLJt7m6wjAfBgNVHSMEGDAWgBQxfznifNqgUkZAJta3WVD21nw8\n"
				+ "8jAKBggqhkjOPQQDAgNJADBGAiEAk7MF+L9bFRwUsbPsBCbCqH9DMdzBQR+kFDNf\n"
				+ "lfn8Rs4CIQD9qWvBXd+EJqwraxiX6cftaFchn+T2HpvMboy+irMFow==\n"
				+ "-----END CERTIFICATE-----",
				//
				// EC private key related to cert endEntityCertStrs[0].
				//
				"MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgA3pmS+OrIjGyUv2F\n"
				+ "K/PkyayJIePM2RTFYxNoQqmJGnihRANCAASHi9c1QnNQurh7t8A68XRaJZTpyWU4\n"
				+ "Ay6zUapMW9ydE84KGXyy5my+Sw7QKlmoveGNeZVf12nUVX+tQEYujVob"                
				),
		RSA2048_SHA256(
				"RSA",
				// Put the entries in order of 
				// trustedCert, endCert, privateKey, Ciphers
				//
				// SHA256withRSA, 2048 bits
				// Validity
				//     Not Before: Nov  9 03:24:16 2016 GMT
				//     Not After : Oct 20 03:24:16 2037 GMT
				"-----BEGIN CERTIFICATE-----\n"
				+ "MIIDpzCCAo+gAwIBAgIJAJAYpR2aIlA1MA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n"
				+ "BAYTAlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2Vy\n"
				+ "aXZjZTAeFw0xNjExMDkwMzI0MTZaFw0zNzEwMjAwMzI0MTZaMDsxCzAJBgNVBAYT\n"
				+ "AlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZj\n"
				+ "ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL+F/FTPODYzsU0Pakfp\n"
				+ "lsh88YoQWZPjABhCU+HPsCTMYc8UBkaiduUzregwwVBW3D7kmec2K408krGQsxdy\n"
				+ "oKJA12GL/XX1YgzDEsyBRk/gvex5lPaBIZiJ5IZlUfjLuRDGxPjtRelBTpZ7SUet\n"
				+ "PJVZz6zV6hMPGO6kQzCtbzzET515EE0okIS40LkAmtWoOmVm3gRldomaZTrZ0V2L\n"
				+ "MMaJGzrXYqk0SX+PYul8v+2EEHeMuaXG/XpK5xsg9gZvzpKqFQcBOdENoJHB07go\n"
				+ "jCmRC328ALqr+bMyktKAuYfB+mhjmN2AU8TQx72WPpvNTXxFDYcwo+8254cCAVKB\n"
				+ "e98CAwEAAaOBrTCBqjAdBgNVHQ4EFgQUlJQlQTbi8YIyiNf+SqF7LtH+gicwawYD\n"
				+ "VR0jBGQwYoAUlJQlQTbi8YIyiNf+SqF7LtH+giehP6Q9MDsxCzAJBgNVBAYTAlVT\n"
				+ "MQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2VyaXZjZYIJ\n"
				+ "AJAYpR2aIlA1MA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMA0GCSqGSIb3\n"
				+ "DQEBCwUAA4IBAQAI0lTY0YAKQ2VdoIQ6dnqolphLVWdNGiC9drHEYSn7+hmAD2r2\n"
				+ "v1U/9m752TkcT74a65xKbEVuVtleD/w6i+QjALW2PYt6ivjOnnY0a9Y9a9UCa00j\n"
				+ "C9415sCw84Tp9VoKtuYqzhN87bBUeABOw5dsW3z32C2N/YhprkqeF/vdx4JxulPr\n"
				+ "PKze5BREXnKLA1ISoDioCPphvNMKrSpkAofb1rTCwtgt5V/WFls283L52ORmpRGO\n"
				+ "Ja88ztXOz00ZGu0RQLwlmpN7m8tNgA/5MPrldyYIwegP4RSkkJlF/8+hxvvqfJhK\n"
				+ "FFDa0HHQSJfR2b9628Iniw1UHOMMT6qx5EHr\n"
				+ "-----END CERTIFICATE-----",
				// SHA256withRSA, 2048 bits
				// Validity
				//     Not Before: Nov  9 03:24:16 2016 GMT
				//     Not After : Jul 27 03:24:16 2036 GMT
				"-----BEGIN CERTIFICATE-----\n"
				+ "MIIDczCCAlugAwIBAgIJAPhM2oUKx0aJMA0GCSqGSIb3DQEBCwUAMDsxCzAJBgNV\n"
				+ "BAYTAlVTMQ0wCwYDVQQKEwRKYXZhMR0wGwYDVQQLExRTdW5KU1NFIFRlc3QgU2Vy\n"
				+ "aXZjZTAeFw0xNjExMDkwMzI0MTZaFw0zNjA3MjcwMzI0MTZaMFIxCzAJBgNVBAYT\n"
				+ "AlVTMQ0wCwYDVQQKDARKYXZhMR0wGwYDVQQLDBRTdW5KU1NFIFRlc3QgU2VyaXZj\n"
				+ "ZTEVMBMGA1UEAwwMSW50ZXJPcCBUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"
				+ "MIIBCgKCAQEA36tJaXfJ2B/AFvES+tnueyQPSNABVu9nfMdU+NEPamJ+FH7cEF8Z\n"
				+ "1Spr1vlQgNzCpDUVrfnmT75rCapgz5ldA9+y+3hdfUyHjZBzzfx+6GHXLB4u6eU2\n"
				+ "NATa7vqSLNbcLcfZ7/QmkFqg4JRJbX4F42kKkRJrWdKZ8UoCYC8WXWvDaZ3nUs05\n"
				+ "XHe+mBJ8qMNPTbYST1jpzXPyH5CljlFGYi2mKJDTImDhwht7mu2+zvwvbJ81Gj2X\n"
				+ "JUSTSf9fu0zxFcCk6RmJPw9nSVqePVlOwtNNBodfKN+k4yr+gOz1v8NmMtmEtklV\n"
				+ "Sulr/J4QxI+E2Zar/C+4XjxkvstIS+PNKQIDAQABo2MwYTALBgNVHQ8EBAMCA+gw\n"
				+ "HQYDVR0OBBYEFHt19CItAz0VOF0WKGWwaT4DtEsSMB8GA1UdIwQYMBaAFJSUJUE2\n"
				+ "4vGCMojX/kqhey7R/oInMBIGA1UdEQEB/wQIMAaHBH8AAAEwDQYJKoZIhvcNAQEL\n"
				+ "BQADggEBACKYZWvo9B9IEpCCdBba2sNo4X1NI/VEY3fyUx1lkw+Kna+1d2Ab+RCZ\n"
				+ "cf3Y85fcwv03hNE///wNBp+Nde4NQRDK/oiQARzWwWslfinm5d83eQwzC3cpSzt+\n"
				+ "7ts6M5UlOblGsLXZI7THWO1tkgoEra9p+zezxLMmf/2MpNyZMZlVoJPM2YGxU9cN\n"
				+ "ws0AyeY1gpBEdT21vjsBPdxxj6qklXVMnzS3zF8YwXyOndDYQWdjmFEknRK/qmQ2\n"
				+ "gkLHrzpSpyCziecna5mGuDRdCU2dpsWiq1npEPXTq+PQGwWYcoaFTtXF8DDqhfPC\n"
				+ "4Abe8gPm6MfzerdmS3RFTj9b/DIIENM=\n"
				+ "-----END CERTIFICATE-----",
				//
				// RSA private key related to cert endEntityCertStrs[1].
				//
				"MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDfq0lpd8nYH8AW\n"
				+ "8RL62e57JA9I0AFW72d8x1T40Q9qYn4UftwQXxnVKmvW+VCA3MKkNRWt+eZPvmsJ\n"
				+ "qmDPmV0D37L7eF19TIeNkHPN/H7oYdcsHi7p5TY0BNru+pIs1twtx9nv9CaQWqDg\n"
				+ "lEltfgXjaQqREmtZ0pnxSgJgLxZda8NpnedSzTlcd76YEnyow09NthJPWOnNc/If\n"
				+ "kKWOUUZiLaYokNMiYOHCG3ua7b7O/C9snzUaPZclRJNJ/1+7TPEVwKTpGYk/D2dJ\n"
				+ "Wp49WU7C000Gh18o36TjKv6A7PW/w2Yy2YS2SVVK6Wv8nhDEj4TZlqv8L7hePGS+\n"
				+ "y0hL480pAgMBAAECggEBAJyP1zk+IkloIBtu7+wrdCU6HoDHKMjjlzrehHoOTI4Z\n"
				+ "F0vdaMkE6J4vrYCyz0kEPjKW/e/jxvT2wxHm8xEdtuApS61+mWJFmXTcMlNzdJnR\n"
				+ "Mr6s+gW67fAHngA94OgGFeTtyX2PFxdgeM/6vFMqLZD7S+w0SnR7WEpvla4iB7On\n"
				+ "lXqhJKVQeVc+IpByg/S4MmJb91jck73GltCaCL/b6BTrsz+zc/AY5tb8JInxjMZ9\n"
				+ "jmjmA+s6l7tnBrFQfJHlF9a374lxCOtZTxyxVJjD7tQcGpsUpSHXZGdpDcT34qYT\n"
				+ "UGh0yp2Mc/1PfWni5gS/6UGLrYmT57RRCn5YJBJTEkkCgYEA/XPCNehFaOMSxOZh\n"
				+ "OGBVhQ+eRAmdpJfMhSUsDdEdQLZyWGmZsMTHjZZrwevBX/D0dxQYDv/sAl0GZomJ\n"
				+ "d6iRCHlscycwx5Q0U/EpacsgRlYHz1nMRzXqS3Ry+8O8qQlliqCLUM7SfVgzdI5/\n"
				+ "ll9JMrng9NnRl8ccjEdOGK8g/MMCgYEA4eriKMfRslGY4uOQoTPbuEJSMMwQ2X4k\n"
				+ "lPj1p+xSQfU9QBaWJake67oBj3vpCxqN7/VkvCIeC6LCjhLpWHCn4EkdGiqkEdWz\n"
				+ "m5CHzpzVIgznzWnbt0rCVL2KdL+ihgY8KPDdsZ6tZrABHuYhsWkAu10wyvuQYM88\n"
				+ "3u6yOIQn36MCgYEAk5qR1UEzAxWTPbaJkgKQa5Cf9DHBbDS3eCcg098f8SsPxquh\n"
				+ "RRAkwzGCCgqZsJ0sUhkStdGXifzRGHAq7dPuuwe0ABAn2WNXYjeFjcYtQqkhnUFH\n"
				+ "tYURsOXdfQAOZEdDqos691GrxjHSraO7bECL6Y3VE+Oyq3jbCFsSgU+kn28CgYBT\n"
				+ "mrXZO6FJqVK33FlAns1YEgsSjeJKapklHEDkxNroF9Zz6ifkhgKwX6SGMefbORd/\n"
				+ "zsNZsBKIYdI3+52pIf+uS8BeV5tiEkCmeEUZ3AYv1LDP3rX1zc++xmn/rI97o8EN\n"
				+ "sZ2JRtyK3OV9RtL/MYmYzPLqm1Ah02+GXLVNnvKWmwKBgE8Ble8CzrXYuuPdGxXz\n"
				+ "BZU6HnXQrmTUcgeze0tj8SDHzCfsGsaG6pHrVNkT7CKsRuCHTZLM0kXmUijLFKuP\n"
				+ "5xyE257z4IbbEbs+tcbB3p28n4/47MzZkSR3kt8+FrsEMZq5oOHbFTGzgp9dhZCC\n"
				+ "dKUqlw5BPHdbxoWB/JpSHGCV"
				);

		private final String keyType;
		private final String trustedCert;
		private final String endCert;
		private final String privateKey;

		private KeyType(String keyType, String trustedCert, String endCert, String privateKey) {
			this.keyType = keyType;
			this.trustedCert = trustedCert;
			this.endCert = endCert;
			this.privateKey = privateKey;
		}

		public String getKeyType() {
			return keyType;
		}

		public String getTrustedCert() {
			return trustedCert;
		}

		public String getEndCert() {
			return endCert;
		}

		public String getPrivateKey() {
			return privateKey;
		}

	}

}