https证书生成、服务器配置、Android端配置

 

单项认证--服务器配置

生成服务器证书

命令:C:\Users\bwkt>keytool -genkey -alias server -keyalg RSA -keystore server.jks -validity 3650

-genkey:在用户主目录中创建一个默认文件".keystore"

-alias:别名,独一无二,通常不区分大小写

-keyalg: 指定密钥的算法 (如 RSA  DSA(如果不指定默认采用DSA)

-keystore:指定密钥库的名称(产生的各类信息将不在.keystore文件中),可指定路径,例如:D:\keys\server.jks

-validity:证书的有效期,单位:天。

 

 

A、输入keystore密码:此处需要输入大于6个字符的字符串。

B、“您的名字与姓氏是什么?”这是必填项。

C、你的组织单位名称是什么?”、“您的组织名称是什么?”、“您所在城市或区域名称是什么?”、“您所在的省//自治区名称是什么?”、“该单位的两字母国家代码是什么?”可以按照需要填写也可以不填写直接回车,在系统询问“正确吗?”时,对照输入信息,如果符合要求则使用键盘输入字母“y”,否则输入“n”重新填写上面的信息。

D、输入<bwkt>的密钥口令,这项较为重要,会在tomcat配置文件中使用,建议输入与keystore的密码一致,设置其它密码也可以,完成上述输入后,直接回车则在你在第二步中定义的位置找到生成的文件。

 

接下来利用server.jks来签发证书:

C:\Users\bwkt>keytool -export -alias server -file server.cer -keystore server.jks



  

 

配置Tomcat

找到tomcat/conf/sever.xml文件,并以文本形式打开。

找到端口为8443的标签,修改为:

 

<Connector SSLEnabled="true" acceptCount="100" clientAuth="true" 
disableUploadTimeout="true" enableLookups="true" 
keystoreFile="C:\Users\bwkt\server.jks" keystorePass="123456" 
maxSpareThreads="75" 
maxThreads="200" minSpareThreads="5" port="8443" 
protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https" 
secure="true" sslProtocol="TLS"
/> 

注:

keystoreFilejks文件存放路径

keystorePass:生成证书时候的密码

测试

启动Tomcat服务器,在浏览器中输入  https://localhost:8443/ ,浏览器提示下图即为成功。



  

 

注:上面生成的server.cer是为Android客户端准备的。

单项认证--Android

准备证书

Android客户端启动的时候在Application中设置证书信息

 

public class MyApplication extends Application {

	@Override
	public void onCreate() {
		super.onCreate();
		try {
	// 证书放在assets文件夹中
			OkHttpClientManager.getInstance().setCertificates(new InputStream[]{getAssets().open("server.cer")});
		} catch (IOException e) {
			e.printStackTrace();
		}
		OkHttpClientManager.getInstance().getOkHttpClient().setConnectTimeout(100000, TimeUnit.MILLISECONDS);
	}
	
}

 也可以通过命令获取到字符串:

C:\Users\bwkt>keytool -printcert -rfc -file server.cer



  

代码:

 

public class MyApplication extends Application {
	
	private static final String SERVER_CER = "-----BEGIN CERTIFICATE-----\n"
			+ "MIIDSTCCAjGgAwIBAgIEd05HCTANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJjbjELMAkGA1UE\n"
			+ "CBMCYmoxCzAJBgNVBAcTAmJqMQwwCgYDVQQKEwNzdW4xDTALBgNVBAsTBGJ3a3QxDzANBgNVBAMT\n"
			+ "BnNlcnZlcjAeFw0xNTExMjAwMjAzMTRaFw0yNTExMTcwMjAzMTRaMFUxCzAJBgNVBAYTAmNuMQsw\n"
			+ "CQYDVQQIEwJiajELMAkGA1UEBxMCYmoxDDAKBgNVBAoTA3N1bjENMAsGA1UECxMEYndrdDEPMA0G\n"
			+ "A1UEAxMGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi98I4lBsevRZIPpX\n"
			+ "4y0ocJrGHTNp4CBeNP+EXDs0ofqrdphd4U+rAs1pcYaC0yrXG8MdbS2E1ar4g3YOpuKNMtoac+gL\n"
			+ "C+9+Ri+0Ge6o5Rwcly2JUUEJDyMVMxZTLJdGoaG2lkFRLbkHJDNil2hpnxMkU9f8BzTblTUOJvwX\n"
			+ "MK0hgTDAwOyBcQRDTyKYT41Izn2ofk4UoGQdc2a7BmCZ9aRGkL2ZBtiuqDbebKV7+xZuyGIahCj0\n"
			+ "K3odF61fQAbgDmaHpDiIvkWrRFuhTX6VuIfvrg1ek/fzSYJ2s6w40jDfGpGeaGbMjxcJ4DokwpRI\n"
			+ "R//+7rbuPwH/BZ0KqxbifwIDAQABoyEwHzAdBgNVHQ4EFgQUorCf7tMptaAH6F53FbGO981Zhjow\n"
			+ "DQYJKoZIhvcNAQELBQADggEBAAz+qTR3b7ezVdz3eL+n1qqrc+5GCp7aFhFTrT7GNsKP1A6MmYG9\n"
			+ "j8H2IB58+AEnDGSrOKPFqHUlQSJzW05WDpCJorw8VXC4Mbsb8bP5jXmiJEakyic8dLoiZn3f4uNA\n"
			+ "wWI4g8t/ZGAobG/X/d5Sd3Cyyi60BJoLcFIshjd3Z1YVl5V1c2Q8+k1qzfDno68Msu2IJ5LVbD44\n"
			+ "Wmt03rlDP2bfeAvpX0PMyPS4RbILtvixLOUB5KM9LPOO7kliS6ZajVR/qDKo3H4fX2OCCYke4hsW\n"
			+ "DR+iUT2S8FQEpBLQOyX6ULdELg0eMLhfmcUk2vvOaItF9LzeMim3tPPzs2XyWmA=\n"
			+ "-----END CERTIFICATE-----";

	@Override
	public void onCreate() {
		super.onCreate();
		try {
			// 证书放在assets文件夹中
			// OkHttpClientManager.getInstance().setCertificates(new InputStream[]{getAssets().open("server.cer")});
	// 根据证书生成的字符串设置证书信息
			OkHttpClientManager.getInstance().setCertificates(new InputStream[]{new Buffer().writeUtf8(SERVER_CER).inputStream()});
		} catch (IOException e) {
			e.printStackTrace();
		}
		OkHttpClientManager.getInstance().getOkHttpClient().setConnectTimeout(100000, TimeUnit.MILLISECONDS);
	}
	
}

 准备证书的核心代码如下:

 

1.设置OkHttpClient主机认证。

 

mOkHttpClient.setHostnameVerifier(new HostnameVerifier() {
			@Override
			public boolean verify(String hostname, SSLSession session) {
				return true;
			}
		});

2.设置证书信息 

 

	/**
	 * 设置证书信息
	 * @param certificates
	 * @param bksFile
	 * @param password
	 */
	public void setCertificates(InputStream[] certificates, InputStream bksFile, String password) {
		try {
			TrustManager[] trustManagers = prepareTrustManager(certificates);
			KeyManager[] keyManagers = prepareKeyManager(bksFile, password);
			SSLContext sslContext = SSLContext.getInstance("TLS");

			sslContext.init(keyManagers, new TrustManager[] { new MyTrustManager(chooseTrustManager(trustManagers)) },
					new SecureRandom());
			mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (KeyManagementException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		}
	}
	/**
	 * 准备所信任的服务器证书
	 * @param certificates
	 * @return
	 */
	private TrustManager[] prepareTrustManager(InputStream... certificates) {
		if (certificates == null || certificates.length <= 0){
			return null;
		}
		try {
			CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
			KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
			keyStore.load(null);
			int index = 0;
			for (InputStream certificate : certificates) {
				String certificateAlias = Integer.toString(index++);
				keyStore.setCertificateEntry(certificateAlias, certificateFactory.generateCertificate(certificate));
				try {
					if (certificate != null){
						certificate.close();
					}
				} catch (IOException e) {
				}
			}
			TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
			trustManagerFactory.init(keyStore);
			TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
			return trustManagers;
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (CertificateException e) {
			e.printStackTrace();
		} catch (KeyStoreException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;

	}

	/**
	 * 准备服务器信任的客户端的证书
	 * @param bksFile
	 * @param password
	 * @return
	 */
	private KeyManager[] prepareKeyManager(InputStream bksFile, String password) {
		try {
			if (bksFile == null || password == null) {
				return null;
			}
			// Android默认的是BKS格式的证书
			KeyStore clientKeyStore = KeyStore.getInstance("BKS");
			clientKeyStore.load(bksFile, password.toCharArray());
			KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
			keyManagerFactory.init(clientKeyStore, password.toCharArray());
			return keyManagerFactory.getKeyManagers();

		} catch (KeyStoreException e) {
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnrecoverableKeyException e) {
			e.printStackTrace();
		} catch (CertificateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

  

测试

String url = "https://192.168.0.163:8443/";
new OkHttpRequest.Builder().url(url).get(
		new MyResultCallback<String>() {
			@Override
			public void onError(Request request, Exception e) {
				Log.e(TAG, "onError" + e.getMessage());
				textView.setText(e.getMessage());
			}

 注:只是获取的页面Html字符串。

 

双向认证--服务器配置

生成客户端证书

按照生成证书的方式,再生成一对这样的文件,我们命名为:client.jksclient.cer

 

配置服务器

将端口为8443的标签,修改为:

 

	<Connector SSLEnabled="true" acceptCount="100" clientAuth="true" 
		disableUploadTimeout="true" enableLookups="true" 
		keystoreFile="C:\Users\bwkt\server.jks" keystorePass="123456" 
		truststoreFile="C:\Users\bwkt\client.jks" truststorePass="123456"
		maxSpareThreads="75" 
		maxThreads="200" minSpareThreads="5" port="8443" 
		protocol="org.apache.coyote.http11.Http11NioProtocol" scheme="https" 
		secure="true" sslProtocol="TLS"
		/>

 

注:

truststoreFile:信任证书的文件路径

truststorePass:信任证书的秘密

测试

启动Tomcat服务器,在浏览器中输入  https://localhost:8443/ ,浏览器提示下图即为成功。



  

 

双向认证--Android

生成Android所需的bks格式的证书

由于Java平台默认识别的是jks格式证书,Android默认识别的是bks格式证书,所有要将jks格式的证书转换成bks格式的证书。

步骤如下:

解压后,里面包含portecle.jar文件,双击portecle.jar即可打开GUI界面。



  

导入证书

点击

 
打开之前生成的jks文件。



  

输入密码:



  

 

成功打开。



  

 

 

 

转换证书

点击Tools-->Change keystore Type-->BKS



  

输入密码,成功提示如下:



  

保存证书

Ctrl+s

 

 

准备证书

Android客户端启动的时候在Application中设置证书信息

 

public class MyApplication extends Application {
	
	private static final String SERVER_CER = "-----BEGIN CERTIFICATE-----\n"
			+ "MIIDSTCCAjGgAwIBAgIEd05HCTANBgkqhkiG9w0BAQsFADBVMQswCQYDVQQGEwJjbjELMAkGA1UE\n"
			+ "CBMCYmoxCzAJBgNVBAcTAmJqMQwwCgYDVQQKEwNzdW4xDTALBgNVBAsTBGJ3a3QxDzANBgNVBAMT\n"
			+ "BnNlcnZlcjAeFw0xNTExMjAwMjAzMTRaFw0yNTExMTcwMjAzMTRaMFUxCzAJBgNVBAYTAmNuMQsw\n"
			+ "CQYDVQQIEwJiajELMAkGA1UEBxMCYmoxDDAKBgNVBAoTA3N1bjENMAsGA1UECxMEYndrdDEPMA0G\n"
			+ "A1UEAxMGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi98I4lBsevRZIPpX\n"
			+ "4y0ocJrGHTNp4CBeNP+EXDs0ofqrdphd4U+rAs1pcYaC0yrXG8MdbS2E1ar4g3YOpuKNMtoac+gL\n"
			+ "C+9+Ri+0Ge6o5Rwcly2JUUEJDyMVMxZTLJdGoaG2lkFRLbkHJDNil2hpnxMkU9f8BzTblTUOJvwX\n"
			+ "MK0hgTDAwOyBcQRDTyKYT41Izn2ofk4UoGQdc2a7BmCZ9aRGkL2ZBtiuqDbebKV7+xZuyGIahCj0\n"
			+ "K3odF61fQAbgDmaHpDiIvkWrRFuhTX6VuIfvrg1ek/fzSYJ2s6w40jDfGpGeaGbMjxcJ4DokwpRI\n"
			+ "R//+7rbuPwH/BZ0KqxbifwIDAQABoyEwHzAdBgNVHQ4EFgQUorCf7tMptaAH6F53FbGO981Zhjow\n"
			+ "DQYJKoZIhvcNAQELBQADggEBAAz+qTR3b7ezVdz3eL+n1qqrc+5GCp7aFhFTrT7GNsKP1A6MmYG9\n"
			+ "j8H2IB58+AEnDGSrOKPFqHUlQSJzW05WDpCJorw8VXC4Mbsb8bP5jXmiJEakyic8dLoiZn3f4uNA\n"
			+ "wWI4g8t/ZGAobG/X/d5Sd3Cyyi60BJoLcFIshjd3Z1YVl5V1c2Q8+k1qzfDno68Msu2IJ5LVbD44\n"
			+ "Wmt03rlDP2bfeAvpX0PMyPS4RbILtvixLOUB5KM9LPOO7kliS6ZajVR/qDKo3H4fX2OCCYke4hsW\n"
			+ "DR+iUT2S8FQEpBLQOyX6ULdELg0eMLhfmcUk2vvOaItF9LzeMim3tPPzs2XyWmA=\n"
			+ "-----END CERTIFICATE-----";

	@Override
	public void onCreate() {
		super.onCreate();
		try {
			// 证书放在assets文件夹中
			// OkHttpClientManager.getInstance().setCertificates(new InputStream[]{getAssets().open("server.cer")});
			// 根据证书生成的字符串设置证书信息
			// OkHttpClientManager.getInstance().setCertificates(new InputStream[]{new Buffer().writeUtf8(SERVER_CER).inputStream()});
			// 双向认证,设置证书信息
			OkHttpClientManager.getInstance().setCertificates(new InputStream[]{getAssets().open("server.cer")}, 
					getAssets().open("client.bks"), "123456");
		} catch (IOException e) {
			e.printStackTrace();
		}
		OkHttpClientManager.getInstance().getOkHttpClient().setConnectTimeout(100000, TimeUnit.MILLISECONDS);
	}
	
}

测试

String url = "https://192.168.0.163:8443/";
new OkHttpRequest.Builder().url(url).get(
		new MyResultCallback<String>() {
			@Override
			public void onError(Request request, Exception e) {
				Log.e(TAG, "onError" + e.getMessage());
				textView.setText(e.getMessage());
			}

			@Override 
			public void onResponse(String response) {
				textView.setText(response);
			}
		});

 

注:只是获取的页面Html字符串。

猜你喜欢

转载自tonysun3544.iteye.com/blog/2265448