参考博客
http://www.cnblogs.com/tyjsjl/p/3359255.html
1.SSL单向认证
1.关于JKS证书
生成CA签名证书keystore
keytool -genkey -alias twt_server -keyalg RSA -keystore twt_server.jks -validity 3600 -storepass 123456
您的名字与姓氏是什么? [Unknown]: 您的组织单位名称是什么? [Unknown]: itian 您的组织名称是什么? [Unknown]: itian 您所在的城市或区域名称是什么? [Unknown]: 北京 您所在的省/市/自治区名称是什么? [Unknown]: 海淀 该单位的双字母国家/地区代码是什么? [Unknown]: cn CN=zhang, OU=zhang, O=zhang, L=xian, ST=shanxi, C=cn是否正确? [否]: y 输入 <zhy_server> 的密钥口令 (如果和密钥库口令相同, 按回车): |
然后生成cer证书
keytool -export -alias ca_server -file twt_server.cer -keystore twt_server.jks -storepass 123456
然后部署
<Connector SSLEnabled="true" acceptCount="100" clientAuth="false"
disableUploadTimeout="true"
enableLookups="true"
keystoreFile="conf/CA/twt_server.jks"
keystorePass="123456"
maxSpareThreads="75"
maxThreads="200"
minSpareThreads="5"
port="443"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true"
sslProtocol="TLSv1.2"
/>
或者我们新增一个新的服务
<Service name="MySSLService">
<Executor name="MySSLServiceTomcatThreadPool" namePrefix="MySSLService-exec-" maxThreads="200" minSpareThreads="4"/>
<Connector
connectionTimeout="20000"
port="443"
redirectPort="8443"
maxPostSize="2048" #post请求最大数量,这里是2M,如果是0,则没有限制
maxThreads="200"
executor="MySSLServiceTomcatThreadPool" #使用连接池
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true"
SSLEnabled="true"
keystoreType="JKS" #证书类型
keystoreFile="conf/CA/twt_server.jks"
keystorePass="123456"
clientAuth="false"
sslProtocol="TLSv1.2"
/>
<Connector port="9009" protocol="AJP/1.3" redirectPort="8443" executor="MySSLServiceTomcatThreadPool" />
<Engine defaultHost="localhost" name="MySSLServiceEngine">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="ssl_access_log" suffix=".txt"/>
</Host>
</Engine>
</Service>
这样访问,通过相应的url,如https就能访问了.
2.关于部署PKCS12证书
这里还有个问题,我们生成的证书实际上是JKS类型的证书,如果我们使用PKCS12证书如何部署呢,PKCS12是互联网标准,如果使用PKCS12,那么java可以更好地与其他语言通信。
JKS与PKCS12互相导入
p12(pfx) -> jks
keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -deststoretype JKS -destkeystore keystore.jks
jks -> p12(pfx)
keytool -importkeystore -srckeystore keystore.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore keystore.p12
从jks里面导出cert
keytool -export -alias cert0001 -keystore trust.jks -storepass 123456 -file cert0001.cer
将cert导入jks
keytool -import -v -alias cert001 -file cert001.cer -keystore trust.jks -storepass 123456 -noprompt
那么,我们可以配置如下
<Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8443" maxThreads="200"
scheme="https" #使用https协议
secure="true" #使用安全链接
SSLEnabled="true"
keystoreFile="conf/CA/keystore.p12" #指定PKCS12 keystore的位置
keystoreType="PKCS12" #证书类型修改为PKCS12即可
keystorePass="123456"
clientAuth="false" #不去校验客户端
sslProtocol="TLS"/>
2.关于APR部署CA证书
APR可以提升Tomcat性能,那么APR的Connector如何配置SSL呢
<Connector protocol="HTTP/1.1" port="443" maxHttpHeaderSize="8192" maxThreads="150" enableLookups="false" disableUploadTimeout="true" acceptCount="100" scheme="https" secure="true" SSLEnabled="true" SSLCertificateFile="conf/CA/rsa-private-key.pem" SSLCertificateKeyFile="conf/CA/self-signed-cert.crt" />
注意,APR的CA证书需要通过openSSL生成
openssl genrsa -out rsa-private-key.pem 1024
openssl req -new -x509 -nodes -sha1 -days 365 -key rsa-private-key.pem -out self-signed-cert.crt
2.SSL双向认证
1.生成服务器证书库(为了测试,我把有效期改为1天)
keytool -genkey -alias ca_server -keyalg RSA -keystore ca_server.jks -validity 1 -storepass 123456
注意:第一项提示姓名与姓氏时请输入你的 域名
1.生成客户端证书库(为了测试,我把有效期改为1天)
keytool -genkey -alias ca_client -keyalg RSA -storetype PKCS12 -keystore ca_client.pfx -validity 1 -storepass 123456
客户端(客户端需要使用PKCS12的密钥,因此这里我们生成pfx密钥证书)
2.将客户端证书部分添加到服务端证书库(让服务器信任客户端)
2.1.pkcs12不能直接导入服务器证书库,需要导出cer证书,将证书导入到证书库中
keytool -export -alias ca_client -keystore ca_client.pfx -storetype PKCS12 -storepass 123456 -rfc -file ca_client.cer
2.2然后将证书导入到服务端证书库中
keytool -import -v -alias ca_client -file ca_client.cer -keystore ca_server.jks
3.配置Connector
在这里,我们为了让服务端证书库和认证库不要使用同一个keystore,我们把ca_server.jks复制一份起名为ca_trust.jks
此时配置修改如下
<Connector SSLEnabled="true"
acceptCount="100"
disableUploadTimeout="true"
enableLookups="true"
maxSpareThreads="75"
maxThreads="200"
minSpareThreads="5"
port="8848"
protocol="org.apache.coyote.http11.Http11NioProtocol"
scheme="https"
secure="true"
clientAuth="true" #设置为true,否则不回去验证客户端
sslProtocol="TLSv1.2"
clientAuth="true"
keystoreType="JKS"
keystoreFile="conf/auth/ca_server.jks"
keystorePass="123456"
truststoreType="JKS"
truststoreFile="conf/auth/ca_trust.jks"
truststorePass="123456"
/>
4.使用浏览器访问出现限制
然后我们启动Tomcat,使用浏览器访问,发现不能访问。说明我们的设置已经生效了,那么想让浏览器能访问该如何做呢?
首先,我们需要安装我们的pfx证书,双击安装,存储区域位置请选择【个人】,否则浏览器依然无法访问!
然后我们访问浏览器,就会出现证书选择提示,选择确定,便能浏览网页了。
5.Android双向认证
双向认证,以Android为例子,Android支持PKCS12,BKS,AndroidCAStore,AndroidKeyStore
Name | Supported (API Levels) |
---|---|
AndroidCAStore | 14+(推荐) |
AndroidKeyStore | 18+ (推荐) |
BCPKCS12 | 1–8 (不建议考虑) |
BKS | 1+ |
BouncyCastle | 1+ |
PKCS12 | 1+ (推荐,PKCS12是互联网标准) |
PKCS12-DEF | 1–8(不建议考虑) |
我们这里用网上的代码,BKS做例子,当然,pkcs12可以参考 android https通过加载pfx证书获取数据
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(KeyStore.getDefaultType());
clientKeyStore.load(mContext.getAssets().open("ca_client.bks"), "123456".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, "123456".toCharArray());
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession sslsession) {
if("localhost".equals(hostname)){
return true;
} else {
return false;
}
}
});
} catch (Exception e)
{
e.printStackTrace();
}
}
读取cer证书
CertificateFactory certificatefactory = CertificateFactory
.getInstance("X.509");
FileInputStream bais = new FileInputStream("srca.cer");
X509Certificate Cert = (X509Certificate) certificatefactory
.generateCertificate(bais);
bais.close();
System.out.println("版本号 " + Cert.getVersion());
System.out.println("序列号 " + Cert.getSerialNumber().toString(16));
System.out.println("全名 " + Cert.getSubjectDN());
System.out.println("签发者全名n" + Cert.getIssuerDN());
System.out.println("有效期起始日 " + Cert.getNotBefore());
System.out.println("有效期截至日 " + Cert.getNotAfter());
System.out.println("签名算法 " + Cert.getSigAlgName());
byte[] sig = Cert.getSignature();
System.out.println("签名:" + new BigInteger(sig).toString(16));
PublicKey pk = Cert.getPublicKey();
System.out.println("PublicKey:"
+ Base64.getEncoder().encodeToString(pk.getEncoded()));
如果从密钥库读取
String pass="080302";
String alias="mykey";
String name=".keystore";
FileInputStream in=new FileInputStream(name);
KeyStore ks=KeyStore.getInstance("JKS");
ks.load(in,pass.toCharArray());
Certificate c=ks.getCertificate(alias);
in.close();
System.out.println(c.toString( ));
PHP部分参阅
http://php.net/manual/zh/ref.openssl.php
http://www.sunzhenghua.com/wamp-config-ssl-https