// Path: mitm-common/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/crypto/PermissiveTrustManager.java
// public final class PermissiveTrustManager extends X509ExtendedTrustManager {
// 	@Override
// 	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public X509Certificate[] getAcceptedIssuers() {
// 		return new X509Certificate[0];
// 	}
// 
// 	@Override
// 	public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
// 		/* empty */
// 	}
// }
// 
// Path: mitm-common/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/crypto/cert/CertificateUtils.java
// public final class CertificateUtils {
// 	private static final String[] EMPTY_STRING_ARRAY = new String[0];
// 
// 	public static X509Certificate readCertificate(Path path) throws IOException {
// 		try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
// 			return readCertificate(reader);
// 		}
// 	}
// 
// 	public static X509Certificate readCertificate(Reader reader) throws IOException {
// 		// TODO share with CertificateAuthority's own implementation
// 		try (PEMParser parser = new PEMParser(reader)) {
// 			Object object = parser.readObject();
// 			if (!(object instanceof X509CertificateHolder))
// 				throw new IOException("File does not contain a certificate");
// 
// 			X509CertificateHolder certificate = (X509CertificateHolder) object;
// 			return new JcaX509CertificateConverter().getCertificate(certificate);
// 		} catch (CertificateException ex) {
// 			throw new IOException(ex);
// 		}
// 	}
// 
// 	public static String extractCn(X509Certificate certificate) {
// 		X500Name dn = JcaX500NameUtil.getSubject(certificate);
// 		for (RDN rdn : dn.getRDNs()) {
// 			AttributeTypeAndValue first = rdn.getFirst();
// 			if (first.getType().equals(BCStyle.CN)) {
// 				return first.getValue().toString();
// 			}
// 		}
// 
// 		throw new IllegalArgumentException("certificate subject has no common name (CN)");
// 	}
// 
// 	public static String[] extractSans(X509Certificate certificate) {
// 		try {
// 			Collection<List<?>> pairs = certificate.getSubjectAlternativeNames();
// 			if (pairs == null)
// 				return EMPTY_STRING_ARRAY;
// 
// 			List<String> sans = new ArrayList<>();
// 			for (List<?> pair : pairs) {
// 				int type = (Integer) pair.get(0);
// 				if (type == 2) { // TODO fix magic number!
// 					String san = (String) pair.get(1);
// 					sans.add(san);
// 				}
// 			}
// 			return sans.toArray(EMPTY_STRING_ARRAY);
// 		} catch (CertificateParsingException ex) {
// 			throw new IllegalArgumentException(ex); // TODO ideal?
// 		}
// 	}
// 
// 	private CertificateUtils() {
// 		/* to prevent instantiation */
// 	}
// }


import java.util.Arrays;
import uk.ac.cam.gpe21.droidssl.mitm.crypto.PermissiveTrustManager;
import uk.ac.cam.gpe21.droidssl.mitm.crypto.cert.CertificateUtils;
import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
/*
 * Copyright 2013-2014 Graham Edgecombe
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.ac.cam.gpe21.droidssl.mitm.testclient;



public final class SniClient {
	public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException, IOException {
		System.setProperty("java.net.preferIPv4Stack", "true");

		String host = args.length >= 1 ? args[0] : null;

		SniClient client = new SniClient(new InetSocketAddress("127.0.0.1", 12345), host);
		client.start();
	}

	private final InetSocketAddress address;
	private final String host;
	private final SSLSocketFactory factory;

	public SniClient(InetSocketAddress address, String host) throws NoSuchAlgorithmException, KeyManagementException {
		this.address = address;
		this.host = host;

		SSLContext context = SSLContext.getInstance("TLS");
		context.init(null, new TrustManager[] {
// Path: mitm-common/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/crypto/PermissiveTrustManager.java
// public final class PermissiveTrustManager extends X509ExtendedTrustManager {
// 	@Override
// 	public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public X509Certificate[] getAcceptedIssuers() {
// 		return new X509Certificate[0];
// 	}
// 
// 	@Override
// 	public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
// 		/* empty */
// 	}
// 
// 	@Override
// 	public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) throws CertificateException {
// 		/* empty */
// 	}
// }
// 
// Path: mitm-common/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/crypto/cert/CertificateUtils.java
// public final class CertificateUtils {
// 	private static final String[] EMPTY_STRING_ARRAY = new String[0];
// 
// 	public static X509Certificate readCertificate(Path path) throws IOException {
// 		try (Reader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
// 			return readCertificate(reader);
// 		}
// 	}
// 
// 	public static X509Certificate readCertificate(Reader reader) throws IOException {
// 		// TODO share with CertificateAuthority's own implementation
// 		try (PEMParser parser = new PEMParser(reader)) {
// 			Object object = parser.readObject();
// 			if (!(object instanceof X509CertificateHolder))
// 				throw new IOException("File does not contain a certificate");
// 
// 			X509CertificateHolder certificate = (X509CertificateHolder) object;
// 			return new JcaX509CertificateConverter().getCertificate(certificate);
// 		} catch (CertificateException ex) {
// 			throw new IOException(ex);
// 		}
// 	}
// 
// 	public static String extractCn(X509Certificate certificate) {
// 		X500Name dn = JcaX500NameUtil.getSubject(certificate);
// 		for (RDN rdn : dn.getRDNs()) {
// 			AttributeTypeAndValue first = rdn.getFirst();
// 			if (first.getType().equals(BCStyle.CN)) {
// 				return first.getValue().toString();
// 			}
// 		}
// 
// 		throw new IllegalArgumentException("certificate subject has no common name (CN)");
// 	}
// 
// 	public static String[] extractSans(X509Certificate certificate) {
// 		try {
// 			Collection<List<?>> pairs = certificate.getSubjectAlternativeNames();
// 			if (pairs == null)
// 				return EMPTY_STRING_ARRAY;
// 
// 			List<String> sans = new ArrayList<>();
// 			for (List<?> pair : pairs) {
// 				int type = (Integer) pair.get(0);
// 				if (type == 2) { // TODO fix magic number!
// 					String san = (String) pair.get(1);
// 					sans.add(san);
// 				}
// 			}
// 			return sans.toArray(EMPTY_STRING_ARRAY);
// 		} catch (CertificateParsingException ex) {
// 			throw new IllegalArgumentException(ex); // TODO ideal?
// 		}
// 	}
// 
// 	private CertificateUtils() {
// 		/* to prevent instantiation */
// 	}
// }


// Path: mitm-test-sni-client/src/main/java/uk/ac/cam/gpe21/droidssl/mitm/testclient/SniClient.java
import java.util.Arrays;
import uk.ac.cam.gpe21.droidssl.mitm.crypto.PermissiveTrustManager;
import uk.ac.cam.gpe21.droidssl.mitm.crypto.cert.CertificateUtils;
import javax.net.ssl.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

/*
 * Copyright 2013-2014 Graham Edgecombe
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package uk.ac.cam.gpe21.droidssl.mitm.testclient;



public final class SniClient {
	public static void main(String[] args) throws KeyManagementException, NoSuchAlgorithmException, IOException {
		System.setProperty("java.net.preferIPv4Stack", "true");

		String host = args.length >= 1 ? args[0] : null;

		SniClient client = new SniClient(new InetSocketAddress("127.0.0.1", 12345), host);
		client.start();
	}

	private final InetSocketAddress address;
	private final String host;
	private final SSLSocketFactory factory;

	public SniClient(InetSocketAddress address, String host) throws NoSuchAlgorithmException, KeyManagementException {
		this.address = address;
		this.host = host;

		SSLContext context = SSLContext.getInstance("TLS");
		context.init(null, new TrustManager[] {
			new PermissiveTrustManager()