生成证书
此内容仅供参考转载需要标注作者。内容相关密钥均为测试密钥。
生成 CA
#生成 CA 私钥: ca.key
openssl genrsa -out ca.key 2048
#生成 CA 的证书请求文件: ca.crt
openssl req -new -out ca.csr -key ca.key
#生成 CA 根证书
openssl x509 -req -in ca.csr -out ca.crt -signkey ca.key -CAcreateserial -days 3650
生成中间 CA
#生成中间CA私钥:intermediate.key
openssl genrsa -out intermediate.key 2048
#生成中间CA的证书请求文件:intermediate.csr
openssl req -new -out intermediate.csr -key intermediate.key
#使用根CA签发中间CA证书:intermediate.crt
openssl ca -extensions v3_ca -in intermediate.csr -out intermediate.crt -cert ca.crt -keyfile ca.key -days 3650
使用中间 CA 签发服务端证书
#生成服务端私钥:server.key
openssl genrsa -out server.key 2048
#生成服务端的证书请求文件:server.csr
openssl req -new -out server.csr -key server.key
#使用中间CA签发服务端证书:server.crt
openssl ca -in server.csr -out server.crt -cert intermediate.crt -keyfile intermediate.key -days 3650
使用中间 CA 签发客户端证书
#生成客户端私钥:client.key
openssl genrsa -out client.key 2048
#生成中间CA的证书请求文件:client.csr
openssl req -new -out client.csr -key client.key
#使用根CA签发中间CA证书:intermediate.crt
openssl ca -in client.csr -out client.crt -cert intermediate.crt -keyfile intermediate.key -days 3650
单向认证
NGINX 配置
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# HTTPS server
#
server {
listen 443 ssl;
server_name localhost;
ssl_certificate cert/server.crt;
ssl_certificate_key cert/server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
proxy_pass http://localhost:9091/;
proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;
}
}
}
JAVA 代码测试
static void loadCustomCaCertsTest() throws IOException {
// Create a new HttpURLConnection to the HTTPS server.
URL url = new URL("https://127.0.0.1/test");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
//Execute the request
connection.connect();
// Check the response code
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
throw new IOException("HTTP error code: " + responseCode);
}
// Read the response body.
InputStream responseInputStream = connection.getInputStream();
byte[] responseBytes = new byte[responseInputStream.available()];
responseInputStream.read(responseBytes);
String responseString = new String(responseBytes);
System.out.println(responseString);
}
使用ssl连接时,遇到不信任的证书,应用程序一般都会拒绝连接。 浏览网站时,我们可以通过在浏览器的设置中导入证书,把证书加入到信任列表中。 而在JAVA直接进行SSL连接应用时,默认没有一个界面来导入证书。JAVA进行不信任的ssl连接时,会报如下异常
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
解决方法
使用keytool导入intermediate.crt或server.crt
Java 使用了一种叫 keystore 的文件来存储证书 (默认是位于 $JAVA_HOME/jre/lib/security/cacerts ) 。
该文件使用 keytool 工具去管理 (该工具默认位于 $JAVA_HOME/bin/keytool )。
使用这种方式不需要改java代码。
keytool -import -alias <证书别名> -keystore $JAVA_HOME/jre/lib/security/cacerts -file your.crt
使用java代码导入intermediate.crt或server.crt
这种方式需要修改代码,代码中加入ca证书
static void loadCaCertsInCodeTest() throws Exception {
byte[] certBytes = Base64.decode("MIIC/zCCAeegAwIBAgIBAzANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApTTkIg\n" +
"SU9UIENBMB4XDTIzMDgwNDA2NDQxOVoXDTMzMDgwMTA2NDQxOVowHzEdMBsGA1UE\n" +
"AwwUU05CIElPVCBJTlRFUk1FRElBVEUwggEiMb0GCSqGSIb3DQEBAQUAA4IBDwAw\n" +
"ggEKAoIBAQDBPSiCv4989QXgeOiWCt2fLUGpCjDKcPoIxnYLDXyPYhy2Lq2J10e5\n" +
"bO8F52qeAH4OpJnxt5cNvVmayfaFh63iVKqaYdPXhiZHlXWrAids0Wocw5hb0+pd\n" +
"71O9raqoqvofYIwQ7LJqK/e61kA8hP0dVlo2niNCubhEri3tQWTrbKmKax9JJldn\n" +
"1MVFqMuUl8C4RqKwLyiLaWS+6N+fN8S1BQArcbZ/PFZ366Vcwh4patXdM1aUtdc9\n" +
"/+CIqUNG5BEI/LkerI+ajKn4FIauPyyUbm7UDavJj2U4uI3mww3O/ylnSMTiVwBh\n" +
"hutw7THLhROv4NcSlwDTg7TrmFGO/bdJAgMBAAGjUDBOMB0GA1UdDgQWBBS4d9HP\n" +
"tyMGIndimcfuqfILbNva4zAfBgNVHSMEGDAWg2RiWJPDGD340cgnJGtuIxS4selj\n" +
"FzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA0ZqpLBqbiAuaFQSD/\n" +
"zn+KwzHCb2UzZUVehOYGiqlT8L6StOVnuu2a9BEdOzx0pSQmfRsV2/p33Zszs2U9\n" +
"KwdJqF5g/OLj6nIzTkh0RjZXaJsCaqq6Ka5Ktykrb7pATyiiSensTN8mvgTb9I7X\n" +
"6XQI/Oi54Wgz41CYuyEwIFF/rbaX1/AZfSGU/lr6kXEjxm6n5FC/mRZdAt7RK4/g\n" +
"C+YhDCbgjDoCIZvaE0aC/HJGXKDgF+ID4bbTfr1ECDUeMJe15jQjW9UyZGAQNeY0\n" +
"5y7LaInrlS3zNFxzuEUlRg3vvw6EqESV5tE8QecYTVg1zCQE7PIG4YRFLZgSeXvm\n" +
"ombN");
InputStream certInputStream = new ByteArrayInputStream(certBytes);
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(certInputStream);
KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
truststore.load(null, null);
truststore.setCertificateEntry("testintermediateca", certificate);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(truststore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), new java.security.SecureRandom());
// Create a new HttpURLConnection to the HTTPS server.
URL url = new URL("https://192.168.188.130/test");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
//Execute the request
connection.connect();
// Check the response code
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
throw new IOException("HTTP error code: " + responseCode);
}
// Read the response body.
InputStream responseInputStream = connection.getInputStream();
byte[] responseBytes = new byte[responseInputStream.available()];
responseInputStream.read(responseBytes);
String responseString = new String(responseBytes);
System.out.println(responseString);
}
双向认证
NGINX 配置
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
# HTTPS server
#
server {
listen 443 ssl;
server_name localhost;
ssl_certificate cert/server.crt;
ssl_certificate_key cert/server.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_client_certificate cert/client_ca.crt;
ssl_verify_client on;
ssl_verify_depth 2;
location / {
root html;
index index.html index.htm;
proxy_pass http://localhost:9091/;
proxy_set_header X-SSL-CERT $ssl_client_escaped_cert;
}
}
}
JAVA 代码测试
用openssl把client.key和client.crt转成p12文件
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -certfile client_ca.crt
public static void test() throws Exception {
/**
* 1、服务端证书放在代码中
* 2、把客户端证书和key转成p12文件
*/
// Load client certificate and private key from keystore
String filePath = "client.p12";
char[] keystorePassword = "888888".toCharArray();
KeyStore keystore = KeyStore.getInstance("PKCS12");
InputStream keystoreFile = MutualAuthenticationTestApp.class.getClassLoader().getResourceAsStream(filePath);
keystore.load(keystoreFile, keystorePassword);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keystore, keystorePassword);
byte[] certBytes = Base64.decode("MIIC/zCCAeegAwIBAgIBAzANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDDApTTkIg\n" +
"SU9UIENBMB4XDTIzMDgwNDA2NDQxOVoXDTMzMDgwMTA2NDQxOVowHzEdMBsGA1UE\n" +
"AwwUU05CIElPVCBJTlRFUk1FRElBVEUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\n" +
"ggEKAoIBAQDBPSiCv1989QXgeOiWCt2fLUGpCJDKcPoIxnYLDXyPYhy2Lq2J10e5\n" +
"bO8F52qeAH4OpJnxt5cNvVmayfaFh63iVKqDYdPXhiZHlXWrAids0Wocw5hb0+pd\n" +
"71O9raqoqvofYIwQ7LJqK/e61kA8hP0dVlo2niNCubhEri3tQWTrbKmKax9JJldn\n" +
"1MVFqMuUl8C4RqKwLyiLaWS+6N+fN8S1BQArobZ/PFZ366Vcwh4patXdM1aUtdc9\n" +
"/+CIqUNG5tEI/LkerI+ajKn4FIauPyyUbm7UDasJj2U4uI3mww3O/ylnSMTiVwBh\n" +
"hutw7THLhROv4NcSlwDTg7TrmFGO/bdJAgMBAAGjUDBOMB0GA1UdDgQWBBS4d9HP\n" +
"tyMGIndimcfuqfILbNva4zAfBgNVHSMEGDAWgBRiWJPDGD340cgnJGtuIxS4selj\n" +
"FzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA0ZqpLBqbiAuaFQSD/\n" +
"zn+KwzHCb2UzZUVehOYGiqlT8L63tOVnuu2a9BEdOzx0pSQmfRsV2/p33Zszs2U9\n" +
"KwdJqF5g/OLj6nIzTkh0RjZXaJsCaqq6Ka5Ktykrb7pATyiiSensTN8mvgTb9I7X\n" +
"6XQI/Oi54Wgz41CYuyEwIFF/rbaX1/AZfSGU/lr6kXEjxm6n5FC/mRZdAt7RK4/g\n" +
"C+YhDCbgjDoCIZvaE0aC/HJGXKDgF+ID4bbTfr1ECDUeMJe15jQjW9UyZGAQNeY0\n" +
"5y7LaInrlS3zNFxzuEUlRg3vvw6EqESV5tE8QecYTVg1zCQE7PIG4YRFLZgSeXvm\n" +
"ombN");
InputStream certInputStream = new ByteArrayInputStream(certBytes);
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(certInputStream);
KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
truststore.load(null, null);
truststore.setCertificateEntry("testintermediateca", certificate);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(truststore);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new java.security.SecureRandom());
// Create a new HttpURLConnection to the HTTPS server.
//URL url = new URL("https://192.168.188.130/test");
URL url = new URL("https://transit-qa.xxxxxxxx.com:8443/api/kms/V3/getTk");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());
//Execute the request
connection.connect();
// Check the response code
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
log.info("HTTP error code: " + responseCode);
//throw new IOException("HTTP error code: " + responseCode);
}
// Read the response body.
InputStream responseInputStream = connection.getInputStream();
byte[] responseBytes = new byte[responseInputStream.available()];
responseInputStream.read(responseBytes);
String responseString = new String(responseBytes);
log.info(responseString);
}
curl测试
curl -v --cert ./client.crt --cacert ./client_ca.crt --key ./client.key https://192.168.188.130/test