Java nginx https mutual authentication

http://blog.csdn.net/qq315737546/article/details/52864220



Recently, to do https two-way authentication, I made a demo, stepped on a lot of pits, and recorded it.
The main reason is that I don’t understand the principle thoroughly enough. I started to use an example directly from the Internet, but most of the results were not applicable.

1. Detailed explanation of one-way and two-way authentication process
2. Certificate format description
3. Use openssl to generate certificates
4. nginx configuration (server side)
5. Browser access (client)
6. Java code access (client)
7. Use the purchased certificate (issued by a trust agency)

1. Detailed explanation of the one-way and two-way authentication process
Process reference blog http://blog.chinaunix.net/uid-26335251 -id-3508651.html One-
way authentication is only the client authentication server, and two-way authentication is mutual authentication (two-way authentication is generally reflected in the browser as requiring a certificate)

2. Certificate format
description Use openssl to generate the certificate yourself At the time, you will find that the certificate formats generated by many examples on the Internet are different, and there are many formats in the same article.
Therefore, you need to understand the differences and connections between different formats.
Reference blog http://blog.csdn.net/ justinjing0612/article/details/7770301
Reference blog http://www.cnblogs.com/lzjsky/archive/2010/11/14/1877143.html

The der and cer files are generally in binary format, only the certificate is stored, but the private key is not included.
The crt file may be in binary format or in text format. It should be mostly
in text format. , you can put the certificate or the private key, or both have
pem. If only the private key is included, the .key extension is generally used, and the
pfx can be password-protected. The p12 file is in binary format, containing both the private key and the certificate, usually with Protect the password

3. Use openssl to generate the certificate
Create a folder to store the generated certificate
[html] view plain copy print?
1) Create the root certificate private key 
openssl genrsa -out root-key.key 1024 
[html] view plain copy print?
2 ) Create a root certificate request file 
[html] view plain copy print?
openssl req -new -out root-req.csr -key root-key.key 
 
is as follows 
[root@localhost sslKey]# openssl req -new -out root-req .csr -key root-key.key 
You are about to be asked to enter information that will be incorporated 
into your certificate request. 
What you are about to enter is what is called a Distinguished Name or a DN. 
There are quite a few fields but you can leave some blank 
For some fields there will be a default value, 
If you enter '.', the field will be left blank. 
----- 
Country Name (2 letter code) [XX]:cn 
State or Province Name (full name) []:bj 
Locality Name (eg, city) [Default City]:bj 
Organization Name (eg, company) [Default Company Ltd]:dc 
Organizational Unit Name (eg, section) []:dc 
Common Name (eg, your name or your server's hostname) []:root 
Email Address []: 
 
Please enter the following 'extra' attributes 
to be sent with your certificate request 
A challenge password []: 
An optional company name []: 
[html] view plain copy print?
7) Generate server certificate (root certificate, rootkey, server key, and server request file four generate server certificate) 
openssl x509 -req -in server-req.csr -out server-cert.cer -signkey server-key.key -CA root-cert.cer -CAkey root-key.key -CAcreateserial -days 3650 


in 2), it will Let fill in the information, among which the country, province, city, company, etc. need to be consistent with the following certificate. Just press Enter directly in the place of challenge password
[html] view plain copy print?
3) Self-signed root certificate 
openssl x509 -req -in root-req.csr -out root-cert.cer -signkey root-key.key -CAcreateserial -days 3650 

[html] view plain copy print?
4) Generate a root certificate in p12 format, fill in the password 123456 
openssl pkcs12 -export -clcerts - in root-cert.cer -inkey root-key.key -out root.p12 

[html] view plain copy print?
5)生成服务端key 
openssl genrsa -out server-key.key 1024 

[html] view plain copy print?
6)生成服务端请求文件 
openssl req -new -out server-req.csr -key server-key.key 
 
具体如下 
[root@localhost sslKey]# openssl req -new -out server-req.csr -key server-key.key 
You are about to be asked to enter information that will be incorporated 
into your certificate request. 
What you are about to enter is what is called a Distinguished Name or a DN. 
There are quite a few fields but you can leave some blank 
For some fields there will be a default value, 
If you enter '.', the field will be left blank. 
----- 
Country Name (2 letter code) [XX]:cn 
State or Province Name (full name) []:bj 
Locality Name (eg, city) [Default City]:bj 
Organization Name (eg, company) [Default Company Ltd]:dc 
Organizational Unit Name (eg, section) []: dc 
Common Name (eg, your name or your server's hostname) []:*.ttt.com 
Email Address []: 
 
Please enter the following 'extra' attributes 
to be sent with your certificate request 
A challenge password []: 
An optional company name []: 

In 6), the national, provincial, and municipal companies are consistent with 2), and special attention should be paid to the Common Name. The domain name of your server must be used. We test with ttt.com
[html] view plain copy print?
7) Generate Server certificate (root certificate, rootkey, server key, server request file, these four generate server certificate) 
openssl x509 -req -in server-req.csr -out server-cert.cer -signkey server-key.key -CA root-cert.cer -CAkey root-key.key -CAcreateserial -days 3650 

[html] view plain copy print?
8)生成客户端key 
openssl genrsa -out client-key.key 1024 

[html] view plain copy print?
9)生成客户端请求文件 
openssl req -new -out client-req.csr -key client-key.key 
 
具体如下 
[root@localhost sslKey]# openssl req -new -out client-req.csr -key client-key.key 
You are about to be asked to enter information that will be incorporated 
into your certificate request. 
What you are about to enter is what is called a Distinguished Name or a DN. 
There are quite a few fields but you can leave some blank 
For some fields there will be a default value, 
If you enter '.', the field will be left blank. 
----- 
Country Name (2 letter code) [XX]:cn 
State or Province Name (full name) []:bj 
Locality Name (eg, city) [Default City]:bj 
Organization Name (eg, company) [Default Company Ltd]:dc 
Organizational Unit Name (eg, section) []:dc 
Common Name (eg, your name or your server's hostname) []:client common 
Email Address []: 
 
Please enter the following 'extra' attributes 
to be sent with your certificate request 
A challenge password []: 
An optional company name []: 
[html] view plain copy print?
10) Generate client certificate (root certificate, rootkey, client key, client request file four generate client certificate) 
openssl x509 -req -in client-req.csr -out client-cert.cer -signkey client- key.key -CA root-cert.cer -CAkey root-key.key -CAcreateserial -days 3650 

[html] view plain copy print?
11) Generate client p12 format root certificate (password set to 123456) 
openssl pkcs12 -export -clcerts -in client-cert.cer -inkey client-key.key -out client.p12 

4.nginx configuration (server side)
Step 3 After the certificates are generated, these certificates can be used. First, configure them on the server side. I won't say much about the installation, refer to http://blog.csdn.net/qq315737546/article/details/51834866
Note that when ./configure, to increase ssl support, you need to replace it with ./configure--with-http_ssl_module
below Post the simple version configuration file of nginx
[html] view plain copy print?
worker_processes 1; 
events { 
    worker_connections 1024; 

 
http { 
    include mime.types; 
    default_type application/octet-stream; 
    sendfile on; 
    keepalive_timeout 65; 
 
    server { 
        listen 443 ssl; 
        server_name ttt.com; 
        ssl on;   
        ssl_certificate /data/sslKey/server-cert.cer; #server certificate public Key 
        ssl_certificate_key /data/sslKey/server-key.key; #server private key 
        ssl_client_certificate /data/sslKey/root-cert.cer; #Root certificate public key, used to verify each secondary client 
        ssl_verify_client on; #Open the client certificate verification   
 
        location / { 
            root html; 
            index index.html index.htm; 
        } 
    } 


Start nginx, and then under our browser access test.

5. Browser access (client)
(first do the mapping of domain name and ip in C:\Windows\System32\drivers\etc\hosts 192.168.234.132 www .ttt.com)


click to continue to browse this website, then the 400 error



appears , because we do not have the client certificate, import client.p12 into the browser, then you
can access as shown below, but the certificate will have a red x number .Because it was signed by us. The browser does not trust it. At




this time, we also import our root.p12, the certificate store does not use the default personal, select the trusted root certificate authority, and if you visit the following figure again (may have to restart the browsing 6.java




code access (client)

According to our understanding in point 1, two-way authentication requires mutual authentication certificates. Therefore, the client needs to authenticate the server certificate, and also sends the client certificate to the server. Use browse When the browser is used as the client, the authentication server certificate is automatically performed, and the client certificate submission is also performed automatically (the certificate needs to be imported into the browser).
When we use java code to do it, these steps are also required.
1) The first is to authenticate the server certificate, jdk has a default list of trusted certificates $JRE/lib/security/cacerts
will also trust certificates
in $JRE/lib/security/jssecacerts by default.
If you put the certificate elsewhere, you need to specify it in the code
(Theoretically, if you buy a certificate issued by the root authority, you do not need to import it into java's own library, but the trust library of java and the operating system may be different. What we bought is OK in the browser, and in java. The server certificate must be manually imported into the trust list)


When importing with keytool, pay attention to the path of the keystore. The default password of cacerts is changeit
[html] view plain copy print?
D:\>cd jdk1.7.0_80\jre7\lib\ security 
 
D:\jdk1.7.0_80\jre7\lib\security>keytool -import -alias ttt -keystore cacerts -file e:/HttpsDemo/server-cert.cer 
Enter keystore password: 
owner: CN=*.ttt .com, OU=dc, O=dc, L=bj, ST=bj, C=cn 
Publisher: CN=root, OU=dc, O=dc, L=bj, ST=bj, C=cn 
Serial Number : a034f5e5d4b1c825 
Validity Start Date: Thu Oct 20 00:01:52 CST 2016, End Date: Sun Oct 18 00:01:52 CST 2026 
Certificate Fingerprint: 
         MD5: 65:CB:C9:0D:C4:E7:66:F9 :09:3D:B4:17:E6:6B:E5:AB 
         SHA1: 41:AD:9E:EB:61:88:AE:1B:A3:76:CE:F8:2C:BB:5D:74:C8:0D:2D:0D 
         SHA256: 0D:17:D4:EF :2E:9D:89:EA:3A:1F:32:44:D5:12:DF:E0:EE:58:61:04:1A:28:BC:91:D4:7C:3F:AF:FE :99:79:16 
         Signature Algorithm Name: SHA1withRSA 
         Version: 1 
Trust this certificate? [No]:  yThe
certificate has been added to the keystore 
 
D:\jdk1.7.0_80\jre7\lib\security> 


2) java code (including loading client certificate)
[java] view plain copy print?
import java.io.File; 
import java.io.FileInputStream; 
import java.io.InputStream; 
import java.security.KeyStore; 
 
import javax.net.ssl. SSLContext; 
 
import org.apache.http.HttpEntity; 
import org.apache.http.client.methods.CloseableHttpResponse; 
import org.apache.http.client.methods.HttpGet; 
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; 
import org.apache.http.impl.client.CloseableHttpClient; 
import org.apache.http.impl.client.HttpClients; 
import org.apache.http.ssl.SSLContexts; 
import org.apache.http.util.EntityUtils; 
 
public class HttpsDemo { 
    private final static String PFX_PATH = "e:/HttpsDemo/client.p12";   //客户端证书路径 
    private final static String PFX_PWD = "123456"; //客户端证书密码 
     
     
    public static String sslRequestGet(String url) throws Exception { 
        KeyStore keyStore = KeyStore.getInstance("PKCS12"); 
        InputStream instream = new FileInputStream(new File(PFX_PATH)); 
        try { 
            keyStore.load(instream, PFX_PWD.toCharArray()); 
        } finally { 
            instream.close(); 
        } 
 
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, PFX_PWD.toCharArray()).build(); 
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext 
                , new String[] { "TLSv1" }  // supportedProtocols ,这里可以按需要设置 
                , null  // supportedCipherSuites 
                , SSLConnectionSocketFactory.getDefaultHostnameVerifier());  
         
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build(); 
        try { 
            HttpGet httpget = new HttpGet(url);  
//          httpost.addHeader("Connection", "keep-alive");// 设置一些heander等 
            CloseableHttpResponse response = httpclient.execute(httpget); 
            try { 
                HttpEntity entity = response.getEntity(); 
                String jsonStr = EntityUtils.toString(response.getEntity(), "UTF-8");//返回结果 
                EntityUtils.consume(entity); 
                return jsonStr; 
            } finally { 
                response.close(); 
            } 
        } finally { 
            httpclient.close(); 
        } 
    } 
 
    public static void main(String[] args) throws Exception { 
        System.out.println(System.getProperty("java.home")); 
        System.out.println(sslRequestGet("https://www.ttt.com/")); 
    } 


我这里使用了 httpClient的包,具体如下


3) 编译运行2)里面的java文件
[html] view plain copy print?
E:\HttpsDemo>javac -encoding utf-8 -cp commons-logging-1.1.1.jar;httpclient-4.5.jar;httpcore-4.4.1.jar; HttpsDemo.java 
 
E:\HttpsDemo>java -cp commons-logging-1.1.1.jar;httpclient-4.5.jar;httpcore-4.4.1.jar; HttpsDemo 
D:\jdk1.7.0_80\jre7 
<!DOCTYPE html> 
<html> 
<head> 
<title>Welcome to nginx!</title> 
<style> 
    body { 
        width: 35em; 
        margin: 0 auto; 
        font-family: Tahoma, Verdana, Arial, sans-serif; 
    } 
</style> 
</head> 
<body> 
<h1>Welcome to nginx!</h1> 
<p>If you see this page, the nginx web server is successfully installed and 
working. Further configuration is required.</p> 
 
<p>For online documentation and support please refer to 
<a href="http://nginx.org/">nginx.org</a>.<br/> 
Commercial support is available at 
<a href="http://nginx.com/">nginx.com</a>.</p> 
 
<p><em>Thank you for using nginx.</em></p> 
</body> 
</html> 
 
 
E:\HttpsDemo> 

You can see that you can access it normally. You're done. (The output of jre is added to the code, because eclipse and cmd may not use the same one, the certificate is only imported into one of the jre, and the other is not working properly)


7. Use the purchased If the certificate (issued by the trust agency)

is used by the company, the certificate is generally bought from the trust agency. Therefore, the root certificate tested above is not required. The
trust agency provides the server certificate and private key, and the client certificate is fine.
If an error is reported
[html] view plain copy print?
Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 

, then check whether the client certificate is loaded correctly, and whether the server certificate is imported into the local trust store. Whether the running jre is the same as the one imported by the certificate.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326616863&siteId=291194637