1.准备工作
1.1 下载Openfire.
[http://download.igniterealtime.org/openfire/openfire_4_0_2.exe]
1.2 安装Openfire
建议安装在非C盘。 配置过程自行百度。
1.3 openfire配置SSL
配置完毕启动Openfire管理台,添加或更改以下属性
按照图中所示,保存设置后会添加属性xmpp.socket.ssl.keystore、xmpp.socket.ssl.keypass、xmpp.socket.ssl.truststore、xmpp.socket.ssl.trustpass
• xmpp.socket.ssl.active — 设置为“true”激活SSL
• xmpp.socket.ssl.keystore –您的Openfire安装根目录相对的keystore文件的位置。您可以离开此属性为空,使用默认密钥库。
• xmpp.socket.ssl.keypass –密钥库/密钥的密码 默认密码是changeit
• xmpp.socket.ssl.truststore –不使用信任库中则留空白,否则设置您的Openfire安装根目录相对的truststore文件的位置。
• xmpp.socket.ssl.trustpass — 改变的信任库/密钥密码默认密码是changeit
1.4 修改初始密码
进入path\resources\security有keystore和truststore2个文件,初始密码是changit。
修改初始密码,命令:
keytool -storepasswd -keystore keystore -storepass changeit -new 12344321
keytool -storepasswd -keystore truststore -storepass changeit -new 12344321
keytool -storepasswd -keystore client.truststore -storepass changeit -new 12344321
2.准备证书
2.1 导出默认证书
keystore中有2个签名证书,home_rsa,home_dsa, 其中home是opefire自定义服务器域名。使用以下命令将其导出。
keytool -exportcert -aliashome_rsa -file home_rsa.cer -keystore keystore -storepass 12344321
keytool -exportcert -alias home_dsa -file home_dsa.cer -keystore keystore -storepass 12344321
把证书导入客户端信任证书库,truststore, client.truststore
keytool -importcert -alias home_rsa -file home_rsa.cer -keystore truststore -storepass 12344321
keytool -importcert -alias home_dsa -file home_dsa.cer -keystore truststore -storepass 12344321
keytool -importcert -alias home_dsa -file home_dsa.cer -keystore client.truststore -storepass 12344321
keytool -importcert -alias home_rsa -file home_rsa.cer -keystore client.truststore -storepass 12344321
2.2 安装java第三方加密jar包
下载bcprov-ext-jdk15on-154.jar
https://downloads.bouncycastle.org/java/bcprov-ext-jdk15on-154.jar
拷贝到 jdkpath\jre\lib\ext下。
2.3 生成Android使用的client.bks
使用导出的证书home_dsa.cer生成client.bks
keytool -importcert -keystore client.bks -storepass 12344321 -file home_dsa.cer -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider
3 Android配置SSLContext
3.1 创建SSLContext
将client.bks拷贝至项目raw文件夹中,使用它来创建SSLContext.
private SSLContext createSSLContext(Context context) throws Exception {
SSLContext sslContext = SSLContext.getInstance(“TLS”);
MyX509TrustManager myX509TrustManager = new MyX509TrustManager(context.getResources().openRawResource(R.raw.client), “12344321”);
sslContext.init(null, new TrustManager[]{myX509TrustManager},
new SecureRandom());
return sslContext;
}
3.2 客户端创建MyX509TrustManager.
注意:Android需要使用BKS格式签名文件。
public class MyX509TrustManager implements X509TrustManager{
/*
* The default PKIX X509TrustManager9. Decisions are delegated
* to it, and a fall back to the logic in this class is performed
* if the default X509TrustManager does not trust it.
*/
X509TrustManager pkixTrustManager;
public MyX509TrustManager(InputStream ksfileStream, String kspass) throws Exception {
// create a "default" JSSE X509TrustManager.
KeyStore ks = KeyStore.getInstance("BKS");
ks.load(ksfileStream, kspass.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
TrustManager tms [] = tmf.getTrustManagers();
/*
* Iterate over the returned trust managers, looking
* for an instance of X509TrustManager. If found,
* use that as the default trust manager.
*/
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
pkixTrustManager = (X509TrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else the
* constructor fails.
*/
throw new Exception("Couldn't initialize");
}
public MyX509TrustManager(String ksfile, String kspass) throws Exception {
// create a "default" JSSE X509TrustManager.
KeyStore ks = KeyStore.getInstance("BKS");
ks.load(new FileInputStream(ksfile), kspass.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(ks);
TrustManager tms [] = tmf.getTrustManagers();
/*
* Iterate over the returned trust managers, looking
* for an instance of X509TrustManager. If found,
* use that as the default trust manager.
*/
for (int i = 0; i < tms.length; i++) {
if (tms[i] instanceof X509TrustManager) {
pkixTrustManager = (X509TrustManager) tms[i];
return;
}
}
/*
* Find some other way to initialize, or else the
* constructor fails.
*/
throw new Exception("Couldn't initialize");
}
/*
* Delegate to the default trust manager.
*/
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException excep) {
// do any special handling here, or rethrow exception.
}
}
/*
* Delegate to the default trust manager.
*/
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
try {
pkixTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException excep) {
/*
* Possibly pop up a dialog box asking whether to trust the
* cert chain.
*/
}
}
/*
* Merely pass this through.
*/
public X509Certificate[] getAcceptedIssuers() {
return pkixTrustManager.getAcceptedIssuers();
}
}
3.3 创建XMPPTCPConnectionConfiguration
端口使用5222, 5223是过时的加密端口,5223不支持SSL/TSL。 添加CustomSSLContext,将setSocketFactory注释掉,SecurityMode设置为required。
connectionConfig = XMPPTCPConnectionConfiguration.builder()
.setServiceName(serviceName)
.setHost(host)
.setPort(port)
.setCustomSSLContext(sslContext)
// .setSocketFactory(sslContext.getSocketFactory())
.setDebuggerEnabled(false)
.setCompressionEnabled(false)
.setResource(XMPP_RESOURCE_NAME)
.setSecurityMode(ConnectionConfiguration.SecurityMode.required)
.setSendPresence(true)
.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
.build();
- 自签名证书生成
4.1生成别名为jxjc的证书server.jks
keytool -genkeypair -alias server -keypass 12344321 -keyalg RSA -keysize 1024 -validity 365 -keystore server.jks -storepass 12344321 -dname “CN=*.home, OU=, O=, L=, ST=, C=”
4.2导出别名为server的证书保存到sercer.cer
keytool -exportcert -alias server -file server.cer -keystore server.jks -storepass 12344321
4.3 导出信任库
如需将自签名证书导入到openfire中,重复1,2步骤。
5.OkHttp3使用SSL加密连接
1.单向验证
1.获取包含公钥的证书
可使用sercer.cer 密码是12344321
2.设置证书。
将证书关联到SSLContext,并为okhttpClient设置SSLContextFactory
public void setCertificates(InputStream... certificates)
{
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)
{
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init
(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e)
{
e.printStackTrace();
}
}
代码流程解析:
1.构造CertificateFactory对象,通过它的generateCertificate(is)方法得到Certificate。
2. 然后讲得到的Certificate放入到keyStore中。
3. 接下来利用keyStore去初始化我们的TrustManagerFactory
4.由trustManagerFactory.getTrustManagers获得TrustManager[]初始化我们的SSLContext
5.最后,设置我们mOkHttpClient.setSslSocketFactory即可。
2.双向验证
1.证书准备
首先对于双向证书验证,也就是说,客户端也会有个“jks文件”,服务器那边会同时有个“cer文件”与之对应。我们已经生成了server.jks和server.cer,按照相同的步骤再生成client.jks和client.cer。生成完毕后,将client.cer导入到server.jks中。
keytool -import -alias client -file client.cer -keystore server.jks
2.Android端配置
需要修改setCertificates方法,添加KeyStoreManager注册到SSLContext
代码如下
public void setCertificates(InputStream... certificates)
{
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)
{
}
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.
getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
//初始化keystore
KeyStore clientKeyStore = KeyStore.getInstance("BKS");
clientKeyStore.load(mContext.getAssets().open("jxjcclient.bks"), "12344321".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "12344321".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
mOkHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
} catch (Exception e)
{
e.printStackTrace();
}
}
注:client.bks生成方法参考上文