作为最近学到的新知识的总结吧,好记性不如烂笔头写在这里,也方便以后忘了的时候查看用。
创建工作目录
mkdir ~/demo
cd ~/demo
mkdir -p ca/certs ca/csr ca/private
mkdir -p server/certs server/csr server/private
mkdir -p client/certs client/csr client/private
certs:存放证书文件
csr:存放证书请求文件
private:存放私钥文件
相当于CA的签发机构,linux下的Chrom和Firefox浏览器都能正常工作,windows下的IE能工作,windows下的Chrome目前没调试好,总是报证书错误(难道windows下不相信所有非真正的CA根证书么),有知道的麻烦告知一下,谢谢。
openssl genrsa -out ca/private/ca-key.pem 2048
也可以是1024或者4096位的key,如果需要密码保护,可以使用下面的命令
openssl genrsa -aes256 -out ca/private/ca-key.pem 2048
我为了测试学习,目前没有使用-aes256参数
openssl req -new -key ca/private/ca-key.pem -out ca/csr/ca-req.csr
如果上一步有密码,此时需要输入上一步的密码
属于自己给自己签发,跟12306的SRCA性质一样
openssl x509 -req -days 365 -sha256 -extensions v3_ca -signkey ca/private/ca-key.pem -in ca/csr/ca-req.csr -out ca/certs/ca-cert.cer
这样我们就有了签发机构了,可以给其它人签发证书了。
openssl genrsa -out server/private/server-key.pem 2048
openssl req -new -key server/private/server-key.pem -out server/csr/server-req.csr
注意,此证书中的Common Name(cn)是你要发布网站的域名,如www.mytest.com也可以是ip地址,就是浏览器或者客户端输入的那个地址
openssl x509 -req -days 365 -sha256 -extensions v3_req -CA ca/certs/ca-cert.cer -CAkey ca/private/ca-key.pem -CAserial ca/ca.srl -CAcreateserial -in server/csr/server-req.csr -out server/certs/server-cert.cer
openssl genrsa -out client/private/client-key.pem 2048
openssl req -new -key client/private/client-key.pem -out client/csr/client-req.csr
注意,此证书中的Common Name(cn)是你要发布网站的域名,如www.mytest.com也可以是ip地址(后面的双向认证使用),就是浏览器或者客户端输入的那个地址
openssl x509 -req -days 365 -sha256 -extensions v3_req -CA ca/certs/ca-cert.cer -CAkey ca/private/ca-key.pem -CAserial ca/ca.srl -CAcreateserial -in client/csr/client-req.csr -out client/certs/client-cert.cer
需要先装其转换成PKCS#12编码格式的密钥库,才能使用keytool工具进行相应的管理。
openssl pkcs12 -export -clcerts -name client -inkey client/private/client-key.pem -in client/certs/client-cert.cer -out client/certs/client-cert.p12
openssl pkcs12 -export -clcerts -name server -inkey server/private/server-key.pem -in server/certs/server-cert.cer -out server/certs/server-cert.p12
keytool -importcert -trustcacerts -alias server-trust -file ca/certs/ca-cert.cer -keystore ca/server-trust.p12
其中的-alias参数用于标识证书名字,可以取任意值
Android端使用的根证书的格式是BKS的(需要专门的一个jar包生成点此下载),安全度更高,据说修改一个bit的数据就会产生错误,反正就是安全级别更高。
keytool -importcert -trustcacerts -alias android-client-trust -file ca/certs/ca-cert.cer -keystore ca/android-client-trust.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath ./bcprov-jdk15on-157.jar
此时我们将有这些文件
demo/
├── bcprov-jdk15on-157.jar
├── ca
│ ├── android-client-trust.bks
│ ├── ca.srl
│ ├── certs
│ │ └── ca-cert.cer
│ ├── csr
│ │ └── ca-req.csr
│ ├── private
│ │ └── ca-key.pem
│ └── server-trust.p12
├── client
│ ├── certs
│ │ ├── client-cert.cer
│ │ └── client-cert.p12
│ ├── csr
│ │ └── client-req.csr
│ └── private
│ └── client-key.pem
└── server
├── certs
│ ├── server-cert.cer
│ └── server-cert.p12
├── csr
│ └── server-req.csr
└── private
└── server-key.pem
12 directories, 15 files
常用到的证书文件如下:
./ca/android-client-trust.bks /*Android端的根证书安装文件*/
./ca/server-trust.p12 /*服务器端的信任根证书安装文件(双向认证时使用),比如tomcat使用的*/
./ca/certs/ca-cert.cer /*通常是PC端浏览器上需要安装的*/
./client/certs/client-cert.p12 /*客户端证书,通常用于Android上使用*/
./client/certs/client-cert.cer /*客户端证书,通常用于PC端的浏览器上安装使用*/
./server/certs/server-cert.p12 /*服务器端使用的证书,比如tomcat*/
大概分析一下这些证书之间的关系,技术太差,如果错误,非常非常欢迎指出,非常感谢!!!
首先“./ca/android-client-trust.bks”、“./ca/server-trust.p12”和“./ca/certs/ca-cert.cer”可以看成是一样作用的文件,甚至可以看成一个文件,都是根证书,只是格式不一样。
“./ca/certs/ca-cert.cer”用openssl产生的;
“./ca/server-trust.p12”用keytool产生的,用于java环境下的证书;
“./ca/android-client-trust.bks”用BKS工具产生;
他们签发了Client的“./client/certs/client-cert.p12”证书和Server的“./server/certs/server-cert.p12”证书。
单向认证中
1、tomcat服务器端部署证书“./server/certs/server-cert.p12”
2、PC端浏览器安装根证书“./ca/certs/ca-cert.cer”
3、Android客户端安装根证书“./ca/android-client-trust.bks”
当客户端向服务器请求时,服务器将自己的证书给客户端,客户端根据服务器的证书中的CA根证书名字,找到自己安装的根证书来验证服务器的证书,由于服务器的证书是客户端安装的根证书签发的,所以,客户端能认证通过,然后进行安全会话。
双向认证中
在单项认证基础上
1、tomcat服务器端部署信任根证书“./ca/server-trust.p12”;
2、PC端浏览器安装证书“./client/certs/client-cert.cer”;
3、Android客户端安装证书“./client/certs/client-cert.p12”
当客户端向服务器请求时,客户端将自己的证书发给服务器,服务器更加客户端证书中的CA根证书名字,找到自己安装的根证书来验证客户端的证书,由于客户端的证书是服务器安装的根证书签发的,所以,服务器能认证通过;然后服务器将自己的证书发给客户端,客户端在用自己的CA根证书验证服务器的证书,验证通过,就可以进行安全会话,之间只要有任何不通过的地方,双方通信立刻停止。
打开Tomcat配置文件server.xml,增加如下内容:
<Connector
port="8443"
protocol="HTTP/1.1"
maxThreads="150"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="{绝对路径}/server-cert.p12"
keystoreType="pkcs12"
keystorePass="123456"
/>
如果是本机测试,而且是用的域名,可以将“/etc/hosts”文件中的localhost修改为自己的域名。
我本机搭建的tomcat服务器地址的我的ip地址(192.168.7.215),所以我都是以这个ip地址测试。
打开chrome,输入https://192.168.7.215:8443提示如下图:
此时添加我们CA根证书(./ca/certs/ca-cert.cer),来使chrome能正确验证我们自签发的服务端证书,一定要导入到授权中心,并勾选所有选择框。
在次刷新浏览器,可以看到已经认证成功,进行了https安全会话。
在Android中使用我们自己生成的根证书,使用方法如下:
private static final String KEY_STORE_TRUST_FILE = "/data/data/你自己app的包名/files/android-client-trust.bks";
private static final String KEY_STORE_TRUST_PASS = "123456";
private static final String KEY_STORE_TYPE_BKS = "bks";
KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
InputStream tsin = new FileInputStream(KEY_STORE_TRUST_FILE);
trustStore.load(tsin, KEY_STORE_TRUST_PASS.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
看网上很多都使用信任任何证书的方式访问https,我觉得不安全,但我又不知道如何使用系统自带的根证书去认证,有知道的麻烦告知一下,非常感谢!!!
<Connector
port="8443"
protocol="HTTP/1.1"
maxThreads="150"
SSLEnabled="true"
scheme="https"
secure="true"
clientAuth="true"
sslProtocol="TLS"
keystoreFile="{绝对路径}/server-cert.p12"
keystoreType="pkcs12"
keystorePass="123456"
truststoreFile="{绝对路径}/server-trust.p12"
truststoreType="jks"
truststorePass="123456"
/>
由于tomcat配置的是clientAuth=”true”,表示客户端也必须有证书,此时没有导入客户端证书,所以直接不能访问:
导入浏览器证书(./client/certs/client-cert.cer),需要导入到“您的证书”列表中,对于Firefox也是导入到这里面,不要导入到“个人”中
再次刷新页面:
需要选择证书,此时选择我们导入的证书,再次栓新页面:
代码如下,主要是添加客户端使用的证书
private static final String KEY_STORE_CLIENT_FILE = "/data/data/你自己app的包名/files/client-cert.p12";
private static final String KEY_STORE_CLIENT_PASS = "123456";
private static final String KEY_STORE_TRUST_FILE = "/data/data/你自己app的包名/files/android-client-trust.bks";
private static final String KEY_STORE_TRUST_PASS = "123456";
private static final String KEY_STORE_TYPE_BKS = "bks";
private static final String KEY_STORE_TYPE_P12 = "PKCS12";
KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE_P12);
InputStream ksin = new FileInputStream(KEY_STORE_CLIENT_FILE);
keyStore.load(ksin, KEY_STORE_CLIENT_PASS.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, KEY_STORE_CLIENT_PASS.toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance(KEY_STORE_TYPE_BKS);
InputStream tsin = new FileInputStream(KEY_STORE_TRUST_FILE);
trustStore.load(tsin, KEY_STORE_TRUST_PASS.toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(keyManagers, trustManagers, null);
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
如下配置,能使浏览器访问时不用输入http或者https,直接输入ip或者域名,都自动使用https访问。
打开tomcat的web.xml,在下面添加如下代码:
<welcome-file-list>
<welcome-file>index.htmlwelcome-file>
<welcome-file>index.htmwelcome-file>
<welcome-file>index.jspwelcome-file>
welcome-file-list>
<login-config>
<auth-method>CLIENT-CERTauth-method>
<realm-name>Client Cert Users-only Arearealm-name>
login-config>
<security-constraint>
<web-resource-collection >
<web-resource-name >SSLweb-resource-name>
<url-pattern>/*url-pattern>
web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIALtransport-guarantee>
user-data-constraint>
security-constraint>
重启tomcat即可。
其实这里还有SNI(Server Name Indication)方面的知识,是为了解决一个服务器使用多个域名和证书的SSL/TLS扩展,网上有很多介绍的,下图是我访问百度的抓包,里面有SNI扩展字段