我有一个常规的Java应用程序,它使用以下代码连接到我的java服务器:
KeyStore ks = KeyStore.getInstance("JKS");
InputStream inputStream = getClass().getResourceAsStream("cert.jks");
ks.load(inputStream, "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(ks);
SSLContext ssc = SSLContext.getInstance("TLS");
ssc.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory factory = ssc.getSocketFactory();
Socket socket = new Socket(Proxy.NO_PROXY);
InetAddress host = InetAddress.getByName("<ip address of server">);
int port = <some port>;
socket.connect(new InetSocketAddress(host, port));
SSLSocket ssls = (SSLSocket)factory.createSocket(socket, host.getHostAddress(), port, false);
ssls.setUseClientMode(true);
ssls.setNeedClientAuth(false);
ssls.startHandshake();
一切正常。但是,由于Android不支持JKS Keystores或SunX509,我必须进行一些更改。我已经使用充气城堡(帽子提示到:How to create a BKS (BouncyCastle) format Java Keystore that contains a client certificate chain)将JKS证书转换为BKS证书并使用了TrustManagerFactory的默认算法,所以现在我的代码如下所示:
KeyStore ks = KeyStore.getInstance("BKS");
android.content.res.Resources res = <getter for resources>;
InputStream inputStream = res.openRawResources(R.raw.cert); //The converted bks certificate stored in the raw directory
ks.load(inputStream, "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
SSLContext ssc = SSLContext.getInstance("TLS");
ssc.init(null, tmf.getTrustManagers(), null);
... same as above ...
ssls.startHandshake();
但是,上面的代码在startHandshake的最后一行抛出一个异常:
javax.net.ssl.SSLHandshakeException:com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)中com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(本地方法)的对等关闭连接
这里有什么问题?是否有任何其他信息可以提供帮助?
答案 0 :(得分:0)
InputStream inputStream = getClass().getResourceAsStream("cert.bks"); //The converted bks certificate
您应该将cert.bks
文件放入/res/raw
目录,然后使用getResources().openRawResource(R.raw.cert);
打开该文件。
编辑:
我认为您在加载信任库时没有指定提供程序。
KeyStore keyStore = KeyStore.getInstance("BKS", BouncyCastleProvider.PROVIDER_NAME);
如果您忘记了,则需要在Application
课程中添加SpongyCastle提供程序。
public class CustomApplication
extends Application {
static {
Security.insertProviderAt(new BouncyCastleProvider(), 1);
}
并将其添加到AndroidManifest.xml
<application
android:allowBackup="true"
android:name=".application.CustomApplication"
但如果仍然无效,您可以尝试做的是从Apache HttpClient的来源添加以下类(它的apache许可所以你可以这样做):
import java.util.Collection;
class Args {
public static void check(final boolean expression, final String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
public static void check(final boolean expression, final String message, final Object... args) {
if (!expression) {
throw new IllegalArgumentException(String.format(message, args));
}
}
public static void check(final boolean expression, final String message, final Object arg) {
if (!expression) {
throw new IllegalArgumentException(String.format(message, arg));
}
}
public static <T> T notNull(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
return argument;
}
public static <T extends CharSequence> T notEmpty(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.isEmpty(argument)) {
throw new IllegalArgumentException(name + " may not be empty");
}
return argument;
}
public static <T extends CharSequence> T notBlank(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.isBlank(argument)) {
throw new IllegalArgumentException(name + " may not be blank");
}
return argument;
}
public static <T extends CharSequence> T containsNoBlanks(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.containsBlanks(argument)) {
throw new IllegalArgumentException(name + " may not contain blanks");
}
return argument;
}
public static <E, T extends Collection<E>> T notEmpty(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (argument.isEmpty()) {
throw new IllegalArgumentException(name + " may not be empty");
}
return argument;
}
public static int positive(final int n, final String name) {
if (n <= 0) {
throw new IllegalArgumentException(name + " may not be negative or zero");
}
return n;
}
public static long positive(final long n, final String name) {
if (n <= 0) {
throw new IllegalArgumentException(name + " may not be negative or zero");
}
return n;
}
public static int notNegative(final int n, final String name) {
if (n < 0) {
throw new IllegalArgumentException(name + " may not be negative");
}
return n;
}
public static long notNegative(final long n, final String name) {
if (n < 0) {
throw new IllegalArgumentException(name + " may not be negative");
}
return n;
}
}
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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
*
* [...add this back]
*/
import java.security.cert.X509Certificate;
import java.util.Arrays;
/**
* Private key details.
*
* @since 4.4
*/
public final class PrivateKeyDetails {
private final String type;
private final X509Certificate[] certChain;
public PrivateKeyDetails(final String type, final X509Certificate[] certChain) {
super();
this.type = Args.notNull(type, "Private key type");
this.certChain = certChain;
}
public String getType() {
return type;
}
public X509Certificate[] getCertChain() {
return certChain;
}
@Override
public String toString() {
return type + ':' + Arrays.toString(certChain);
}
}
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) [...add this back]
*
*/
import java.net.Socket;
import java.util.Map;
/**
* A strategy allowing for a choice of an alias during SSL authentication.
*
* @since 4.4
*/
public interface PrivateKeyStrategy {
/**
* Determines what key material to use for SSL authentication.
*
* @param aliases available private key material
* @param socket socket used for the connection. Please note this parameter can be {@code null}
* if key material is applicable to any socket.
*/
String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket);
}
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) [...add this back]
*
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509TrustManager;
/**
* Builder for {@link javax.net.ssl.SSLContext} instances.
* <p>
* Please note: the default Oracle JSSE implementation of {@link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)}
* accepts multiple key and trust managers, however only only first matching type is ever used.
* See for example:
* <a href="http://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLContext.html#init%28javax.net.ssl.KeyManager[],%20javax.net.ssl.TrustManager[],%20java.security.SecureRandom%29">
* SSLContext.html#init
* </a>
*
* @since 4.4
*/
public class SSLContextBuilder {
static final String TLS = "TLS";
private String protocol;
private final Set<KeyManager> keymanagers;
private final Set<TrustManager> trustmanagers;
private SecureRandom secureRandom;
public static SSLContextBuilder create() {
return new SSLContextBuilder();
}
public SSLContextBuilder() {
super();
this.keymanagers = new LinkedHashSet<KeyManager>();
this.trustmanagers = new LinkedHashSet<TrustManager>();
}
public SSLContextBuilder useProtocol(final String protocol) {
this.protocol = protocol;
return this;
}
public SSLContextBuilder setSecureRandom(final SecureRandom secureRandom) {
this.secureRandom = secureRandom;
return this;
}
public SSLContextBuilder loadTrustMaterial(
final KeyStore truststore,
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
final TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init(truststore);
final TrustManager[] tms = tmfactory.getTrustManagers();
if (tms != null) {
if (trustStrategy != null) {
for (int i = 0; i < tms.length; i++) {
final TrustManager tm = tms[i];
if (tm instanceof X509TrustManager) {
tms[i] = new TrustManagerDelegate(
(X509TrustManager) tm, trustStrategy);
}
}
}
for (final TrustManager tm : tms) {
this.trustmanagers.add(tm);
}
}
return this;
}
public SSLContextBuilder loadTrustMaterial(
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
return loadTrustMaterial(null, trustStrategy);
}
public SSLContextBuilder loadTrustMaterial(
final File file,
final char[] storePassword,
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
Args.notNull(file, "Truststore file");
final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
final FileInputStream instream = new FileInputStream(file);
try {
trustStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadTrustMaterial(trustStore, trustStrategy);
}
public SSLContextBuilder loadTrustMaterial(
final File file,
final char[] storePassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
return loadTrustMaterial(file, storePassword, null);
}
public SSLContextBuilder loadTrustMaterial(
final File file) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
return loadTrustMaterial(file, null);
}
public SSLContextBuilder loadTrustMaterial(
final URL url,
final char[] storePassword,
final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
Args.notNull(url, "Truststore URL");
final KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
final InputStream instream = url.openStream();
try {
trustStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadTrustMaterial(trustStore, trustStrategy);
}
public SSLContextBuilder loadTrustMaterial(
final URL url,
final char[] storePassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
return loadTrustMaterial(url, storePassword, null);
}
public SSLContextBuilder loadKeyMaterial(
final KeyStore keystore,
final char[] keyPassword,
final PrivateKeyStrategy aliasStrategy)
throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
final KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
kmfactory.init(keystore, keyPassword);
final KeyManager[] kms = kmfactory.getKeyManagers();
if (kms != null) {
if (aliasStrategy != null) {
for (int i = 0; i < kms.length; i++) {
final KeyManager km = kms[i];
if (km instanceof X509ExtendedKeyManager) {
kms[i] = new KeyManagerDelegate((X509ExtendedKeyManager) km, aliasStrategy);
}
}
}
for (final KeyManager km : kms) {
keymanagers.add(km);
}
}
return this;
}
public SSLContextBuilder loadKeyMaterial(
final KeyStore keystore,
final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
return loadKeyMaterial(keystore, keyPassword, null);
}
public SSLContextBuilder loadKeyMaterial(
final File file,
final char[] storePassword,
final char[] keyPassword,
final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
Args.notNull(file, "Keystore file");
final KeyStore identityStore = KeyStore.getInstance(KeyStore.getDefaultType());
final FileInputStream instream = new FileInputStream(file);
try {
identityStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
}
public SSLContextBuilder loadKeyMaterial(
final File file,
final char[] storePassword,
final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
return loadKeyMaterial(file, storePassword, keyPassword, null);
}
public SSLContextBuilder loadKeyMaterial(
final URL url,
final char[] storePassword,
final char[] keyPassword,
final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
Args.notNull(url, "Keystore URL");
final KeyStore identityStore = KeyStore.getInstance(KeyStore.getDefaultType());
final InputStream instream = url.openStream();
try {
identityStore.load(instream, storePassword);
} finally {
instream.close();
}
return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
}
public SSLContextBuilder loadKeyMaterial(
final URL url,
final char[] storePassword,
final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
return loadKeyMaterial(url, storePassword, keyPassword, null);
}
protected void initSSLContext(
final SSLContext sslcontext,
final Collection<KeyManager> keyManagers,
final Collection<TrustManager> trustManagers,
final SecureRandom secureRandom) throws KeyManagementException {
sslcontext.init(
!keyManagers.isEmpty() ? keyManagers.toArray(new KeyManager[keyManagers.size()]) : null,
!trustManagers.isEmpty() ? trustManagers.toArray(new TrustManager[trustManagers.size()]) : null,
secureRandom);
}
public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
final SSLContext sslcontext = SSLContext.getInstance(
this.protocol != null ? this.protocol : TLS);
initSSLContext(sslcontext, keymanagers, trustmanagers, secureRandom);
return sslcontext;
}
static class TrustManagerDelegate implements X509TrustManager {
private final X509TrustManager trustManager;
private final TrustStrategy trustStrategy;
TrustManagerDelegate(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
super();
this.trustManager = trustManager;
this.trustStrategy = trustStrategy;
}
@Override
public void checkClientTrusted(
final X509Certificate[] chain, final String authType) throws CertificateException {
this.trustManager.checkClientTrusted(chain, authType);
}
@Override
public void checkServerTrusted(
final X509Certificate[] chain, final String authType) throws CertificateException {
if (!this.trustStrategy.isTrusted(chain, authType)) {
this.trustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return this.trustManager.getAcceptedIssuers();
}
}
static class KeyManagerDelegate extends X509ExtendedKeyManager {
private final X509ExtendedKeyManager keyManager;
private final PrivateKeyStrategy aliasStrategy;
KeyManagerDelegate(final X509ExtendedKeyManager keyManager, final PrivateKeyStrategy aliasStrategy) {
super();
this.keyManager = keyManager;
this.aliasStrategy = aliasStrategy;
}
@Override
public String[] getClientAliases(
final String keyType, final Principal[] issuers) {
return this.keyManager.getClientAliases(keyType, issuers);
}
public Map<String, PrivateKeyDetails> getClientAliasMap(
final String[] keyTypes, final Principal[] issuers) {
final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
for (final String keyType: keyTypes) {
final String[] aliases = this.keyManager.getClientAliases(keyType, issuers);
if (aliases != null) {
for (final String alias: aliases) {
validAliases.put(alias,
new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
}
}
}
return validAliases;
}
public Map<String, PrivateKeyDetails> getServerAliasMap(
final String keyType, final Principal[] issuers) {
final Map<String, PrivateKeyDetails> validAliases = new HashMap<String, PrivateKeyDetails>();
final String[] aliases = this.keyManager.getServerAliases(keyType, issuers);
if (aliases != null) {
for (final String alias: aliases) {
validAliases.put(alias,
new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
}
}
return validAliases;
}
@Override
public String chooseClientAlias(
final String[] keyTypes, final Principal[] issuers, final Socket socket) {
final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
return this.aliasStrategy.chooseAlias(validAliases, socket);
}
@Override
public String[] getServerAliases(
final String keyType, final Principal[] issuers) {
return this.keyManager.getServerAliases(keyType, issuers);
}
@Override
public String chooseServerAlias(
final String keyType, final Principal[] issuers, final Socket socket) {
final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
return this.aliasStrategy.chooseAlias(validAliases, socket);
}
@Override
public X509Certificate[] getCertificateChain(final String alias) {
return this.keyManager.getCertificateChain(alias);
}
@Override
public PrivateKey getPrivateKey(final String alias) {
return this.keyManager.getPrivateKey(alias);
}
@Override
public String chooseEngineClientAlias(
final String[] keyTypes, final Principal[] issuers, final SSLEngine sslEngine) {
final Map<String, PrivateKeyDetails> validAliases = getClientAliasMap(keyTypes, issuers);
return this.aliasStrategy.chooseAlias(validAliases, null);
}
@Override
public String chooseEngineServerAlias(
final String keyType, final Principal[] issuers, final SSLEngine sslEngine) {
final Map<String, PrivateKeyDetails> validAliases = getServerAliasMap(keyType, issuers);
return this.aliasStrategy.chooseAlias(validAliases, null);
}
}
}
/**
* @since 4.3
*/
final class TextUtils {
/**
* Returns true if the parameter is null or of zero length
*/
public static boolean isEmpty(final CharSequence s) {
if (s == null) {
return true;
}
return s.length() == 0;
}
/**
* Returns true if the parameter is null or contains only whitespace
*/
public static boolean isBlank(final CharSequence s) {
if (s == null) {
return true;
}
for (int i = 0; i < s.length(); i++) {
if (!Character.isWhitespace(s.charAt(i))) {
return false;
}
}
return true;
}
/**
* @since 4.4
*/
public static boolean containsBlanks(final CharSequence s) {
if (s == null) {
return false;
}
for (int i = 0; i < s.length(); i++) {
if (Character.isWhitespace(s.charAt(i))) {
return true;
}
}
return false;
}
}
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* Created on 2015.06.02..
*/
public class TrustAllStrategy implements TrustStrategy {
@Override
public boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
return true;
}
}
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* [...add this back]
*
*/
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* A trust strategy that accepts self-signed certificates as trusted. Verification of all other
* certificates is done by the trust manager configured in the SSL context.
*
* @since 4.1
*/
public class TrustSelfSignedStrategy implements TrustStrategy {
public static final TrustSelfSignedStrategy INSTANCE = new TrustSelfSignedStrategy();
@Override
public boolean isTrusted(
final X509Certificate[] chain, final String authType) throws CertificateException {
return chain.length == 1;
}
}
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) [...add this back]
*/
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
/**
* A strategy to establish trustworthiness of certificates without consulting the trust manager
* configured in the actual SSL context. This interface can be used to override the standard
* JSSE certificate verification process.
*
* @since 4.4
*/
public interface TrustStrategy {
/**
* Determines whether the certificate chain can be trusted without consulting the trust manager
* configured in the actual SSL context. This method can be used to override the standard JSSE
* certificate verification process.
* <p/>
* Please note that, if this method returns {@code false}, the trust manager configured
* in the actual SSL context can still clear the certificate as trusted.
*
* @param chain the peer certificate chain
* @param authType the authentication type based on the client certificate
* @return {@code true} if the certificate can be trusted without verification by
* the trust manager, {@code false} otherwise.
* @throws CertificateException thrown if the certificate is not trusted or invalid.
*/
boolean isTrusted(X509Certificate[] chain, String authType)
throws CertificateException;
}
添加这些内容后,您可以像这样构建SSLContext
:
SSLContextBuilder sslContextBuilder = SSLContextBuilder.create();
KeyStore keyStore = KeyStore.getInstance("BKS", BouncyCastleProvider.PROVIDER_NAME);
android.content.res.Resources res = <getter for resources>;
InputStream inputStream = res.openRawResources(R.raw.cert);
keyStore.load(inputStream, trustStorePassword);
sslContextBuilder.loadTrustMaterial(keyStore, trustStorePassword);
SSLContext sslContext = sslContextBuilder.build();
//okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
编辑:测试证书
keyStore.load(byteArrayInputStream, keyStorePassword);
Certificate[] certificates = keyStore.getCertificateChain("key-alias"); //you need to know the alias
if(certificates.length > 0) {
Certificate certificate = certificates[0];
X509Certificate x509Certificate = (X509Certificate) certificate;
Log.d(TAG,
"Certificate found with DN [" + x509Certificate.getSubjectDN() + "]");
答案 1 :(得分:0)
根据您的要求,您可以参考Google转换文档中的以下示例代码:
// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// From https://www.washington.edu/itconnect/security/ca/load-der.crt
InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
URL url = new URL("https://certs.cac.washington.edu/CAtest/");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);