java 证书体系及应用

接下来我们将域名www.zlex.org定位到本机上。打开C:\Windows\System32\drivers\etc\hosts文件,将www.zlex.org绑定在本机上。在文件末尾追加127.0.0.1       www.zlex.org。现在通过地址栏访问http://www.zlex.org,或者通过ping命令,如果能够定位到本机,域名映射就搞定了。 
现在,配置tomcat。先将zlex.keystore拷贝到tomcat的conf目录下,然后配置server.xml。将如下内容加入配置文件

<Connector
			SSLEnabled="true"
			URIEncoding="UTF-8"
			clientAuth="false"
			keystoreFile="conf/zlex.keystore"
			keystorePass="123456"
			maxThreads="150"
			port="443"
			protocol="HTTP/1.1"
			scheme="https"
			secure="true"
			sslProtocol="TLS" />


注意clientAuth="false"测试阶段,置为false,正式使用时建议使用true。现在启动tomcat,访问https://www.zlex.org/各种Java加密算法 
显然,证书未能通过认证,这个时候你可以选择安装证书(上文中的zlex.cer文件就是证书),作为受信任的根证书颁发机构导入,再次重启浏览器(IE,其他浏览器对于域名www.zlex.org不支持本地方式访问),访问https://www.zlex.org/,你会看到地址栏中会有个小锁各种Java加密算法,就说明安装成功。所有的浏览器联网操作已经在RSA加密解密系统的保护之下了。但似乎我们感受不到。 
这个时候很多人开始怀疑,如果我们要手工做一个这样的https的访问是不是需要把浏览器的这些个功能都实现呢?不需要! 

接着上篇内容,给出如下代码实现:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
import  java.io.FileInputStream;
import  java.security.KeyStore;
import  java.security.PrivateKey;
import  java.security.PublicKey;
import  java.security.Signature;
import  java.security.cert.Certificate;
import  java.security.cert.CertificateFactory;
import  java.security.cert.X509Certificate;
import  java.util.Date;
 
import  javax.crypto.Cipher;
import  javax.net.ssl.HttpsURLConnection;
import  javax.net.ssl.KeyManagerFactory;
import  javax.net.ssl.SSLContext;
import  javax.net.ssl.SSLSocketFactory;
import  javax.net.ssl.TrustManagerFactory;
 
/**
  * 证书组件
 
  * @author 梁栋
  * @version 1.0
  * @since 1.0
  */
public  abstract  class  CertificateCoder  extends  Coder {
 
     /**
      * Java密钥库(Java Key Store,JKS)KEY_STORE
      */
     public  static  final  String KEY_STORE =  "JKS" ;
 
     public  static  final  String X509 =  "X.509" ;
     public  static  final  String SunX509 =  "SunX509" ;
     public  static  final  String SSL =  "SSL" ;
 
     /**
      * 由KeyStore获得私钥
     
      * @param keyStorePath
      * @param alias
      * @param password
      * @return
      * @throws Exception
      */
     private  static  PrivateKey getPrivateKey(String keyStorePath, String alias,
             String password)  throws  Exception {
         KeyStore ks = getKeyStore(keyStorePath, password);
         PrivateKey key = (PrivateKey) ks.getKey(alias, password.toCharArray());
         return  key;
     }
 
     /**
      * 由Certificate获得公钥
     
      * @param certificatePath
      * @return
      * @throws Exception
      */
     private  static  PublicKey getPublicKey(String certificatePath)
             throws  Exception {
         Certificate certificate = getCertificate(certificatePath);
         PublicKey key = certificate.getPublicKey();
         return  key;
     }
 
     /**
      * 获得Certificate
     
      * @param certificatePath
      * @return
      * @throws Exception
      */
     private  static  Certificate getCertificate(String certificatePath)
             throws  Exception {
         CertificateFactory certificateFactory = CertificateFactory
                 .getInstance(X509);
         FileInputStream in =  new  FileInputStream(certificatePath);
 
         Certificate certificate = certificateFactory.generateCertificate(in);
         in.close();
 
         return  certificate;
     }
 
     /**
      * 获得Certificate
     
      * @param keyStorePath
      * @param alias
      * @param password
      * @return
      * @throws Exception
      */
     private  static  Certificate getCertificate(String keyStorePath,
             String alias, String password)  throws  Exception {
         KeyStore ks = getKeyStore(keyStorePath, password);
         Certificate certificate = ks.getCertificate(alias);
 
         return  certificate;
     }
 
     /**
      * 获得KeyStore
     
      * @param keyStorePath
      * @param password
      * @return
      * @throws Exception
      */
     private  static  KeyStore getKeyStore(String keyStorePath, String password)
             throws  Exception {
         FileInputStream is =  new  FileInputStream(keyStorePath);
         KeyStore ks = KeyStore.getInstance(KEY_STORE);
         ks.load(is, password.toCharArray());
         is.close();
         return  ks;
     }
 
     /**
      * 私钥加密
     
      * @param data
      * @param keyStorePath
      * @param alias
      * @param password
      * @return
      * @throws Exception
      */
     public  static  byte [] encryptByPrivateKey( byte [] data, String keyStorePath,
             String alias, String password)  throws  Exception {
         // 取得私钥
         PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
 
         // 对数据加密
         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, privateKey);
 
         return  cipher.doFinal(data);
 
     }
 
     /**
      * 私钥解密
     
      * @param data
      * @param keyStorePath
      * @param alias
      * @param password
      * @return
      * @throws Exception
      */
     public  static  byte [] decryptByPrivateKey( byte [] data, String keyStorePath,
             String alias, String password)  throws  Exception {
         // 取得私钥
         PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password);
 
         // 对数据加密
         Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, privateKey);
 
         return  cipher.doFinal(data);
 
     }
 
     /**
      * 公钥加密
     
      * @param data
      * @param certificatePath
      * @return
      * @throws Exception
      */
     public  static  byte [] encryptByPublicKey( byte [] data, String certificatePath)
             throws  Exception {
 
         // 取得公钥
         PublicKey publicKey = getPublicKey(certificatePath);
         // 对数据加密
         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
         cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 
         return  cipher.doFinal(data);
 
     }
 
     /**
      * 公钥解密
     
      * @param data
      * @param certificatePath
      * @return
      * @throws Exception
      */
     public  static  byte [] decryptByPublicKey( byte [] data, String certificatePath)
             throws  Exception {
         // 取得公钥
         PublicKey publicKey = getPublicKey(certificatePath);
 
         // 对数据加密
         Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm());
         cipher.init(Cipher.DECRYPT_MODE, publicKey);
 
         return  cipher.doFinal(data);
 
     }
 
     /**
      * 验证Certificate
     
      * @param certificatePath
      * @return
      */
     public  static  boolean  verifyCertificate(String certificatePath) {
         return  verifyCertificate( new  Date(), certificatePath);
     }
 
     /**
      * 验证Certificate是否过期或无效
     
      * @param date
      * @param certificatePath
      * @return
      */
     public  static  boolean  verifyCertificate(Date date, String certificatePath) {
         boolean  status =  true ;
         try  {
             // 取得证书
             Certificate certificate = getCertificate(certificatePath);
             // 验证证书是否过期或无效
             status = verifyCertificate(date, certificate);
         catch  (Exception e) {
             status =  false ;
         }
         return  status;
     }
 
     /**
      * 验证证书是否过期或无效
     
      * @param date
      * @param certificate
      * @return
      */
     private  static  boolean  verifyCertificate(Date date, Certificate certificate) {
         boolean  status =  true ;
         try  {
             X509Certificate x509Certificate = (X509Certificate) certificate;
             x509Certificate.checkValidity(date);
         catch  (Exception e) {
             status =  false ;
         }
         return  status;
     }
 
     /**
      * 签名
     
      * @param keyStorePath
      * @param alias
      * @param password
     
      * @return
      * @throws Exception
      */
     public  static  String sign( byte [] sign, String keyStorePath, String alias,
             String password)  throws  Exception {
         // 获得证书
         X509Certificate x509Certificate = (X509Certificate) getCertificate(
                 keyStorePath, alias, password);
         // 获取私钥
         KeyStore ks = getKeyStore(keyStorePath, password);
         // 取得私钥
         PrivateKey privateKey = (PrivateKey) ks.getKey(alias, password
                 .toCharArray());
 
         // 构建签名
         Signature signature = Signature.getInstance(x509Certificate
                 .getSigAlgName());
         signature.initSign(privateKey);
         signature.update(sign);
         return  encryptBASE64(signature.sign());
     }
 
     /**
      * 验证签名
     
      * @param data
      * @param sign
      * @param certificatePath
      * @return
      * @throws Exception
      */
     public  static  boolean  verify( byte [] data, String sign,
             String certificatePath)  throws  Exception {
         // 获得证书
         X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath);
         // 获得公钥
         PublicKey publicKey = x509Certificate.getPublicKey();
         // 构建签名
         Signature signature = Signature.getInstance(x509Certificate
                 .getSigAlgName());
         signature.initVerify(publicKey);
         signature.update(data);
 
         return  signature.verify(decryptBASE64(sign));
 
     }
 
     /**
      * 验证Certificate
     
      * @param keyStorePath
      * @param alias
      * @param password
      * @return
      */
     public  static  boolean  verifyCertificate(Date date, String keyStorePath,
             String alias, String password) {
         boolean  status =  true ;
         try  {
             Certificate certificate = getCertificate(keyStorePath, alias,
                     password);
             status = verifyCertificate(date, certificate);
         catch  (Exception e) {
             status =  false ;
         }
         return  status;
     }
 
     /**
      * 验证Certificate
     
      * @param keyStorePath
      * @param alias
      * @param password
      * @return
      */
     public  static  boolean  verifyCertificate(String keyStorePath, String alias,
             String password) {
         return  verifyCertificate( new  Date(), keyStorePath, alias, password);
     }
 
     /**
      * 获得SSLSocektFactory
     
      * @param password
      *            密码
      * @param keyStorePath
      *            密钥库路径
     
      * @param trustKeyStorePath
      *            信任库路径
      * @return
      * @throws Exception
      */
     private  static  SSLSocketFactory getSSLSocketFactory(String password,
             String keyStorePath, String trustKeyStorePath)  throws  Exception {
         // 初始化密钥库
         KeyManagerFactory keyManagerFactory = KeyManagerFactory
                 .getInstance(SunX509);
         KeyStore keyStore = getKeyStore(keyStorePath, password);
         keyManagerFactory.init(keyStore, password.toCharArray());
 
         // 初始化信任库
         TrustManagerFactory trustManagerFactory = TrustManagerFactory
                 .getInstance(SunX509);
         KeyStore trustkeyStore = getKeyStore(trustKeyStorePath, password);
         trustManagerFactory.init(trustkeyStore);
 
         // 初始化SSL上下文
         SSLContext ctx = SSLContext.getInstance(SSL);
         ctx.init(keyManagerFactory.getKeyManagers(), trustManagerFactory
                 .getTrustManagers(),  null );
         SSLSocketFactory sf = ctx.getSocketFactory();
 
         return  sf;
     }
 
     /**
      * 为HttpsURLConnection配置SSLSocketFactory
     
      * @param conn
      *            HttpsURLConnection
      * @param password
      *            密码
      * @param keyStorePath
      *            密钥库路径
     
      * @param trustKeyStorePath
      *            信任库路径
      * @throws Exception
      */
     public  static  void  configSSLSocketFactory(HttpsURLConnection conn,
             String password, String keyStorePath, String trustKeyStorePath)
             throws  Exception {
         conn.setSSLSocketFactory(getSSLSocketFactory(password, keyStorePath,
                 trustKeyStorePath));
     }
}



增加了configSSLSocketFactory方法供外界调用,该方法为 HttpsURLConnection配置了SSLSocketFactory。当HttpsURLConnection配置了 SSLSocketFactory后,我们就可以通过HttpsURLConnection的getInputStream、 getOutputStream,像往常使用HttpURLConnection做操作了。尤其要说明一点,未配置SSLSocketFactory 前,HttpsURLConnection的getContentLength()获得值永远都是-1。 

给出相应测试类:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import  static  org.junit.Assert.*;
 
import  java.io.DataInputStream;
import  java.io.InputStream;
import  java.net.URL;
 
import  javax.net.ssl.HttpsURLConnection;
 
import  org.junit.Test;
 
/**
 
  * @author 梁栋
  * @version 1.0
  * @since 1.0
  */
public  class  CertificateCoderTest {
     private  String password =  "123456" ;
     private  String alias =  "www.zlex.org" ;
     private  String certificatePath =  "d:/zlex.cer" ;
     private  String keyStorePath =  "d:/zlex.keystore" ;
     private  String clientKeyStorePath =  "d:/zlex-client.keystore" ;
     private  String clientPassword =  "654321" ;
 
     @Test
     public  void  test()  throws  Exception {
         System.err.println( "公钥加密——私钥解密" );
         String inputStr =  "Ceritifcate" ;
         byte [] data = inputStr.getBytes();
 
         byte [] encrypt = CertificateCoder.encryptByPublicKey(data,
                 certificatePath);
 
         byte [] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
                 keyStorePath, alias, password);
         String outputStr =  new  String(decrypt);
 
         System.err.println( "加密前: "  + inputStr +  "\n\r"  "解密后: "  + outputStr);
 
         // 验证数据一致
         assertArrayEquals(data, decrypt);
 
         // 验证证书有效
         assertTrue(CertificateCoder.verifyCertificate(certificatePath));
 
     }
 
     @Test
     public  void  testSign()  throws  Exception {
         System.err.println( "私钥加密——公钥解密" );
 
         String inputStr =  "sign" ;
         byte [] data = inputStr.getBytes();
 
         byte [] encodedData = CertificateCoder.encryptByPrivateKey(data,
                 keyStorePath, alias, password);
 
         byte [] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
                 certificatePath);
 
         String outputStr =  new  String(decodedData);
         System.err.println( "加密前: "  + inputStr +  "\n\r"  "解密后: "  + outputStr);
         assertEquals(inputStr, outputStr);
 
         System.err.println( "私钥签名——公钥验证签名" );
         // 产生签名
         String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
                 password);
         System.err.println( "签名:\r"  + sign);
 
         // 验证签名
         boolean  status = CertificateCoder.verify(encodedData, sign,
                 certificatePath);
         System.err.println( "状态:\r"  + status);
         assertTrue(status);
 
     }
 
     @Test
     public  void  testHttps()  throws  Exception {
         URL url =  new  URL( "https://www.zlex.org/examples/" );
         HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
 
         conn.setDoInput( true );
         conn.setDoOutput( true );
 
         CertificateCoder.configSSLSocketFactory(conn, clientPassword,
                 clientKeyStorePath, clientKeyStorePath);
 
         InputStream is = conn.getInputStream();
 
         int  length = conn.getContentLength();
 
         DataInputStream dis =  new  DataInputStream(is);
         byte [] data =  new  byte [length];
         dis.readFully(data);
 
         dis.close();
         System.err.println( new  String(data));
         conn.disconnect();
     }
}


注意testHttps方法,几乎和我们往常做HTTP访问没有差别,我们来看控制台输出:

<!--
  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

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD><TITLE>Apache Tomcat Examples</TITLE>
<META http-equiv=Content-Type content="text/html">
</HEAD>
<BODY>
<P>
<H3>Apache Tomcat Examples</H3>
<P></P>
<ul>
<li><a href="http://javaeye.shaduwang.com/?snowolf/blog/servlets">Servlets examples</a></li>
<li><a href="http://javaeye.shaduwang.com/?snowolf/blog/jsp">JSP Examples</a></li>
</ul>
</BODY></HTML>


通过浏览器直接访问https://www.zlex.org/examples/你 也会获得上述内容。也就是说应用甲方作为服务器构建tomcat服务,乙方可以通过上述方式访问甲方受保护的SSL应用,并且不需要考虑具体的加密解密问 题。甲乙双方可以经过相应配置,通过双方的tomcat配置有效的SSL服务,简化上述代码实现,完全通过证书配置完成SSL双向认证!

    我们使用自签名证书完成了认证。接下来,我们使用第三方CA签名机构完成证书签名。 
    这里我们使用thawte提供的测试用21天免费ca证书。 
    1.要在该网站上注明你的域名,这里使用www.zlex.org作为测试用域名(请勿使用该域名作为你的域名地址,该域名受法律保护!请使用其他非注册域名!)。 
    2.如果域名有效,你会收到邮件要求你访问https://www.thawte.com/cgi/server/try.exe获得ca证书。 
    3.复述密钥库的创建。

keytool -genkey -validity 36000 -alias www.zlex.org -keyalg RSA -keystore d:\zlex.keystore



在这里我使用的密码为 123456 

控制台输出:

输入keystore密码:
再次输入新密码:
您的名字与姓氏是什么?
  [Unknown]:  www.zlex.org
您的组织单位名称是什么?
  [Unknown]:  zlex
您的组织名称是什么?
  [Unknown]:  zlex
您所在的城市或区域名称是什么?
  [Unknown]:  BJ
您所在的州或省份名称是什么?
  [Unknown]:  BJ
该单位的两字母国家代码是什么
  [Unknown]:  CN
CN=www.zlex.org, OU=zlex, O=zlex, L=BJ, ST=BJ, C=CN 正确吗?
  [否]:  Y

输入<tomcat>的主密码
        (如果和 keystore 密码相同,按回车):
再次输入新密码:



    4.通过如下命令,从zlex.keystore中导出CA证书申请。 
   

keytool -certreq -alias www.zlex.org -file d:\zlex.csr -keystore d:\zlex.keystore -v

你会获得zlex.csr文件,可以用记事本打开,内容如下格式:

-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBnDCCAQUCAQAwXDELMAkGA1UEBhMCQ04xCzAJBgNVBAgTAkJKMQswCQYDVQQHEwJCSjENMAsG
A1UEChMEemxleDENMAsGA1UECxMEemxleDEVMBMGA1UEAxMMd3d3LnpsZXgub3JnMIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQCR6DXU9Mp+mCKO7cv9JPsj0n1Ec/GpM09qvhpgX3FNad/ZWSDc
vU77YXZSoF9hQp3w1LC+eeKgd2MlVpXTvbVwBNVd2HiQPp37ic6BUUjSaX8LHtCl7l0BIEye9qQ2
j8G0kak7e8ZA0s7nb3Ymq/K8BV7v0MQIdhIc1bifK9ZDewIDAQABoAAwDQYJKoZIhvcNAQEFBQAD
gYEAMA1r2fbZPtNx37U9TRwadCH2TZZecwKJS/hskNm6ryPKIAp9APWwAyj8WJHRBz5SpZM4zmYO
oMCI8BcnY2A4JP+R7/SwXTdH/xcg7NVghd9A2SCgqMpF7KMfc5dE3iygdiPu+UhY200Dvpjx8gmJ
1UbH3+nqMUyCrZgURFslOUY=
-----END NEW CERTIFICATE REQUEST-----


    5.将上述文件内容拷贝到https://www.thawte.com/cgi/server/try.exe中,点击next,获得回应内容,这里是p7b格式。 
内容如下:

-----BEGIN PKCS7-----
MIIF3AYJKoZIhvcNAQcCoIIFzTCCBckCAQExADALBgkqhkiG9w0BBwGgggWxMIID
EDCCAnmgAwIBAgIQA/mx/pKoaB+KGX2hveFU9zANBgkqhkiG9w0BAQUFADCBhzEL
MAkGA1UEBhMCWkExIjAgBgNVBAgTGUZPUiBURVNUSU5HIFBVUlBPU0VTIE9OTFkx
HTAbBgNVBAoTFFRoYXd0ZSBDZXJ0aWZpY2F0aW9uMRcwFQYDVQQLEw5URVNUIFRF
U1QgVEVTVDEcMBoGA1UEAxMTVGhhd3RlIFRlc3QgQ0EgUm9vdDAeFw0wOTA1Mjgw
MDIxMzlaFw0wOTA2MTgwMDIxMzlaMFwxCzAJBgNVBAYTAkNOMQswCQYDVQQIEwJC
SjELMAkGA1UEBxMCQkoxDTALBgNVBAoTBHpsZXgxDTALBgNVBAsTBHpsZXgxFTAT
BgNVBAMTDHd3dy56bGV4Lm9yZzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
keg11PTKfpgiju3L/ST7I9J9RHPxqTNPar4aYF9xTWnf2Vkg3L1O+2F2UqBfYUKd
8NSwvnnioHdjJVaV0721cATVXdh4kD6d+4nOgVFI0ml/Cx7Qpe5dASBMnvakNo/B
tJGpO3vGQNLO5292JqvyvAVe79DECHYSHNW4nyvWQ3sCAwEAAaOBpjCBozAMBgNV
HRMBAf8EAjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBABgNVHR8E
OTA3MDWgM6Axhi9odHRwOi8vY3JsLnRoYXd0ZS5jb20vVGhhd3RlUHJlbWl1bVNl
cnZlckNBLmNybDAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9v
Y3NwLnRoYXd0ZS5jb20wDQYJKoZIhvcNAQEFBQADgYEATPuxZbtJJSPmXvfrr1yz
xqM06IwTZ6UU0lZRG7I0WufMjNMKdpn8hklUhE17mxAhGSpewLVVeLR7uzBLFkuC
X7wMXxhoYdJZtNai72izU6Rd1oknao7diahvRxPK4IuQ7y2oZ511/4T4vgY6iRAj
q4q76HhPJrVRL/sduaiu+gYwggKZMIICAqADAgECAgEAMA0GCSqGSIb3DQEBBAUA
MIGHMQswCQYDVQQGEwJaQTEiMCAGA1UECBMZRk9SIFRFU1RJTkcgUFVSUE9TRVMg
T05MWTEdMBsGA1UEChMUVGhhd3RlIENlcnRpZmljYXRpb24xFzAVBgNVBAsTDlRF
U1QgVEVTVCBURVNUMRwwGgYDVQQDExNUaGF3dGUgVGVzdCBDQSBSb290MB4XDTk2
MDgwMTAwMDAwMFoXDTIwMTIzMTIxNTk1OVowgYcxCzAJBgNVBAYTAlpBMSIwIAYD
VQQIExlGT1IgVEVTVElORyBQVVJQT1NFUyBPTkxZMR0wGwYDVQQKExRUaGF3dGUg
Q2VydGlmaWNhdGlvbjEXMBUGA1UECxMOVEVTVCBURVNUIFRFU1QxHDAaBgNVBAMT
E1RoYXd0ZSBUZXN0IENBIFJvb3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB
ALV9kG+Os6x/DOhm+tKUQfzVMWGhE95sFmEtkMMTX2Zi4n6i6BvzoReJ5njzt1LF
cqu4EUk9Ji20egKKfmqRzmQFLP7+1niSdfJEUE7cKY40QoI99270PTrLjJeaMcCl
+AYl+kD+RL5BtuKKU3PurYcsCsre6aTvjMcqpTJOGeSPAgMBAAGjEzARMA8GA1Ud
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAgozj7BkD9O8si2V0v+EZ/t7E
fz/LC8y6mD7IBUziHy5/53ymGAGLtyhXHvX+UIE6UWbHro3IqVkrmY5uC93Z2Wew
A/6edK3KFUcUikrLeewM7gmqsiASEKx2mKRKlu12jXyNS5tXrPWRDvUKtFC1uL9a
12rFAQS2BkIk7aU+ghYxAA==
-----END PKCS7-----

将其存储为zlex.p7b 
    6.将由CA签发的证书导入密钥库。

keytool -import -trustcacerts -alias www.zlex.org -file d:\zlex.p7b -keystore d:\zlex.keystore -v



在这里我使用的密码为 123456 

    控制台输出:

输入keystore密码:

回复中的最高级认证:

所有者:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FOR
 TESTING PURPOSES ONLY, C=ZA
签发人:CN=Thawte Test CA Root, OU=TEST TEST TEST, O=Thawte Certification, ST=FOR
 TESTING PURPOSES ONLY, C=ZA
序列号:0
有效期: Thu Aug 01 08:00:00 CST 1996 至Fri Jan 01 05:59:59 CST 2021
证书指纹:
         MD5:5E:E0:0E:1D:17:B7:CA:A5:7D:36:D6:02:DF:4D:26:A4
         SHA1:39:C6:9D:27:AF:DC:EB:47:D6:33:36:6A:B2:05:F1:47:A9:B4:DA:EA
         签名算法名称:MD5withRSA
         版本: 3

扩展:

#1: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:2147483647
]


... 是不可信的。 还是要安装回复? [否]:  Y
认证回复已安装在 keystore中
[正在存储 d:\zlex.keystore]



    7.域名定位 
    将域名www.zlex.org定位到本机上。打开C:\Windows\System32\drivers\etc\hosts文件,将 www.zlex.org绑定在本机上。在文件末尾追加127.0.0.1       www.zlex.org。现在通过地址栏访问http://www.zlex.org,或者通过ping命令,如果能够定位到本机,域名映射就搞定 了。 

    8.配置server.xml

<Connector
			keystoreFile="conf/zlex.keystore"
			keystorePass="123456" 
			truststoreFile="conf/zlex.keystore"    
			truststorePass="123456"     
			SSLEnabled="true"
			URIEncoding="UTF-8"
			clientAuth="false"			
			maxThreads="150"
			port="443"
			protocol="HTTP/1.1"
			scheme="https"
			secure="true"
			sslProtocol="TLS" />



将文件zlex.keystore拷贝到tomcat的conf目录下,重新启动tomcat。访问https://www.zlex.org/,我们发现联网有些迟钝。大约5秒钟后,网页正常显示,同时有如下图所示: 
各种Java加密算法 
浏览器验证了该CA机构的有效性。 

打开证书,如下图所示: 
各种Java加密算法 

调整测试类: 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import  static  org.junit.Assert.*;
 
import  java.io.DataInputStream;
import  java.io.InputStream;
import  java.net.URL;
 
import  javax.net.ssl.HttpsURLConnection;
 
import  org.junit.Test;
 
/**
 
  * @author 梁栋
  * @version 1.0
  * @since 1.0
  */
public  class  CertificateCoderTest {
     private  String password =  "123456" ;
     private  String alias =  "www.zlex.org" ;
     private  String certificatePath =  "d:/zlex.cer" ;
     private  String keyStorePath =  "d:/zlex.keystore" ;
 
     @Test
     public  void  test()  throws  Exception {
         System.err.println( "公钥加密——私钥解密" );
         String inputStr =  "Ceritifcate" ;
         byte [] data = inputStr.getBytes();
 
         byte [] encrypt = CertificateCoder.encryptByPublicKey(data,
                 certificatePath);
 
         byte [] decrypt = CertificateCoder.decryptByPrivateKey(encrypt,
                 keyStorePath, alias, password);
         String outputStr =  new  String(decrypt);
 
         System.err.println( "加密前: "  + inputStr +  "\n\r"  "解密后: "  + outputStr);
 
         // 验证数据一致
         assertArrayEquals(data, decrypt);
 
         // 验证证书有效
         assertTrue(CertificateCoder.verifyCertificate(certificatePath));
 
     }
 
     @Test
     public  void  testSign()  throws  Exception {
         System.err.println( "私钥加密——公钥解密" );
 
         String inputStr =  "sign" ;
         byte [] data = inputStr.getBytes();
 
         byte [] encodedData = CertificateCoder.encryptByPrivateKey(data,
                 keyStorePath, alias, password);
 
         byte [] decodedData = CertificateCoder.decryptByPublicKey(encodedData,
                 certificatePath);
 
         String outputStr =  new  String(decodedData);
         System.err.println( "加密前: "  + inputStr +  "\n\r"  "解密后: "  + outputStr);
         assertEquals(inputStr, outputStr);
 
         System.err.println( "私钥签名——公钥验证签名" );
         // 产生签名
         String sign = CertificateCoder.sign(encodedData, keyStorePath, alias,
                 password);
         System.err.println( "签名:\r"  + sign);
 
         // 验证签名
         boolean  status = CertificateCoder.verify(encodedData, sign,
                 certificatePath);
         System.err.println( "状态:\r"  + status);
         assertTrue(status);
 
     }
 
     @Test
     public  void  testHttps()  throws  Exception {
         URL url =  new  URL( "https://www.zlex.org/examples/" );
         HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
 
         conn.setDoInput( true );
         conn.setDoOutput( true );
 
         CertificateCoder.configSSLSocketFactory(conn, password, keyStorePath,
                 keyStorePath);
 
         InputStream is = conn.getInputStream();
 
         int  length = conn.getContentLength();
 
         DataInputStream dis =  new  DataInputStream(is);
         byte [] data =  new  byte [length];
         dis.readFully(data);
 
         dis.close();
         conn.disconnect();
         System.err.println( new  String(data));
     }
}



再次执行,验证通过! 
由此,我们了基于SSL协议的认证过程。测试类的testHttps方法模拟了一次浏览器的HTTPS访问。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值