生成HTTPS证书及使用

本文详细介绍了如何使用JDK的keytool工具生成SSL/TLS证书和密钥,包括生成非对称密钥、导出证书、以及在Tomcat和Nginx服务器上的配置方法。同时,提供了自定义证书验证的Java类实现,确保HTTPS服务的安全访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

生成证书和秘钥

使用JDK7的keytool工具生成

转到JDK的安装目录下的bin,如/usr/java/jdk1.7.0_79/bin

生成非对称密钥

keytool -genkeypair -v -alias aaa -keyalg RSA -keystore /home/app/key/pay.jks -validity 3650 -dname "CN=pay.xxx.com,OU=,O=aaa,L=HEFEI,ST=ANHUI,C=CN" -storepass 222222 -keypass 222222
  • alias 密钥仓库别名,不区分大小写
  • keyalg 设置采用的算法
  • keystore 秘钥文件生成位置
  • validity 设置秘钥有效天数
  • dname 设置证书信息
    • CN 名字与姓氏,网站输入网站域名
    • OU 组织单位名称
    • O 组织名称
    • L 城市或区域
    • ST 州或省份名称
    • C 单位的两字母国家代码
  • storepass 仓库的密码,建议修改
  • keypass key的密码,建议修改

导出证书

keytool -export -alias aaa -keystore /home/app/key/pay.jks -file /home/app/key/pay.cer

Tomcat

生成P12格式私钥

keytool -importkeystore -srckeystore /home/app/key/pay.jks -destkeystore pay.p12 -deststoretype PKCS12

使用OpenSSL生成pem格式秘钥

openssl pkcs12 -in /home/app/key/pay.p12 -out /home/app/key/pay.pem -nodes

Tomcat配置

在server.xml中添加443端口的Connector

要求Tomcat必须开启了APR支持

  • SSLCertificateFile:配置为导出的证书
  • SSLCertificateKeyFile:配置为OpenSSL生成的pem秘钥
<Connector port="443" protocol="HTTP/1.1" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS" 
			   SSLCertificateFile="E:/key/pay.cer"
                 SSLCertificateKeyFile="E:/key/pay.pem"
  ciphers="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_ 
CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_C 
BC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RS 
A_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA"/>

Nginx

生成P12格式私钥

keytool -importkeystore -srckeystore /home/app/key/pay.jks -destkeystore pay.p12 -deststoretype PKCS12

生成证书

openssl pkcs12 -in pay.p12 -nokeys -clcerts -out server-ssl.crt 
openssl pkcs12 -in pay.p12 -nokeys -cacerts -out gs_intermediate_ca.crt

server-ssl.crt是SSL证书,gs_intermediate_ca.crt是中级证书,俩个合并到一起才是nginx服务器所需要的证书

合并证书

cat server-ssl.crt gs_intermediate_ca.crt >nginx.crt

生成Nginx私钥

openssl pkcs12 -nocerts -nodes -in pay.p12 -out nginx.key

Nginx配置

修改nginx的nginx.conf配置文件

server {
        listen       88;
        server_name  127.0.0.1;

		ssl on;
		ssl_certificate E:/key/nginx.crt;
		ssl_certificate_key E:/key/nginx.key;
  • ssl_certificate:上文生成的证书文件
  • ssl_certificate_key:上文生成的Nginx私钥

开发使用

由于证书未经过权威CA验证,因此需要进行特殊配置,需要自定义只生成证书的验证方法

证书验证类

/**
 * SSL客户端工具,信任设置的证书
 */
public class SSLClientUtil {

    private final static Logger logger = LoggerFactory.getLogger(SSLClientUtil.class);

    /**
     * 设置SSL验证证书和服务器域名(地址)
     * crtFiles crt证书文件,crt证书文件地址,可以通过firefox浏览器导出网站的crt文件
     */
    public void setSSLVerify(File... crtFiles) {
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                try {
                    String peerHost = session.getPeerHost(); //服务器返回的主机名
                    X509Certificate[] peerCertificates = (X509Certificate[]) session.getPeerCertificates();
                    for (X509Certificate certificate : peerCertificates) {
                        X500Principal subjectX500Principal = certificate.getSubjectX500Principal();
                        String name = subjectX500Principal.getName();
                        String[] split = name.split(",");
                        for (String str : split) {
                            if (str.startsWith("CN")) {//证书绑定的域名或者ip
                                // CN:www.baidu.com中取得后面的主机名
                                String hostName = str.substring(3);
                                // 秘钥的主机名为请求地址才放行
                                if (hostName.equals(peerHost)) {
                                    return true;
                                }
                            }
                        }
                    }
                } catch (SSLPeerUnverifiedException e1) {
                }
                return false;
            }
        };

        try {
            trustHttpsCertificates(crtFiles);
        } catch (Exception e) {
            logger.error("信任指定HTTPS证书失败,可能造成Hessian Https请求失败", e);
        }
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

    /**
     * 设置SSL验证证书,不验证服务器域名(地址)
     * crtFiles crt证书文件,crt证书文件地址,可以通过firefox浏览器导出网站的crt文件
     */
    public void setSSLVerifyWithoutDomain(File... crtFiles) {
        HostnameVerifier hv = new HostnameVerifier() {
            public boolean verify(String urlHostName, SSLSession session) {
                try {
                    String peerHost = session.getPeerHost(); //服务器返回的主机名
                    X509Certificate[] peerCertificates = (X509Certificate[]) session.getPeerCertificates();
                    for (X509Certificate certificate : peerCertificates) {
                        return true;
                    }
                } catch (SSLPeerUnverifiedException e1) {
                }
                return false;
            }
        };

        try {
            trustHttpsCertificates(crtFiles);
        } catch (Exception e) {
            logger.error("信任指定HTTPS证书失败,可能造成Hessian Https请求失败", e);
        }
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
    }

    /**
     * 设置可信任的crt证书
     *
     * @param crtFiles crt证书文件,crt证书文件地址,可以通过firefox浏览器导出网站的crt文件
     * @throws Exception
     */
    private void trustHttpsCertificates(File... crtFiles) throws Exception {
        javax.net.ssl.TrustManager[] trustCerts = new javax.net.ssl.TrustManager[crtFiles.length];
        for (int i = 0; i < crtFiles.length; i++) {
            javax.net.ssl.TrustManager tm = new TrustEverythingManager(crtFiles[i]);
            trustCerts[i] = tm;
        }

        javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
                .getInstance("SSL");
        sc.init(null, trustCerts, null);
        HttpsURLConnection.setDefaultSSLSocketFactory(sc
                .getSocketFactory());
    }

    class TrustEverythingManager implements javax.net.ssl.TrustManager,
            javax.net.ssl.X509TrustManager {

        /**
         * crt证书文件地址,可以通过firefox浏览器导出网站的该文件
         */
        private File crtFile;

        public TrustEverythingManager(File crtFile) {
            this.crtFile = crtFile;
        }

        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return null;
        }

        public boolean isServerTrusted(
                java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public boolean isClientTrusted(
                java.security.cert.X509Certificate[] certs) {
            return true;
        }

        public void checkServerTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            if (certs == null) {
                throw new IllegalArgumentException("X509Certificate is null");
            }
            if (certs.length == 0) {
                throw new IllegalArgumentException("X509Certificate is empty");
            }
            for (X509Certificate cert : certs) {
                cert.checkValidity();
                try {
                    cert.verify(getPublicKey());
                } catch (Exception ex) {
                    logger.error("验证证书失败,可能造成Hessian Https请求失败", ex);
                }
            }
            return;
        }

        public void checkClientTrusted(
                java.security.cert.X509Certificate[] certs, String authType)
                throws java.security.cert.CertificateException {
            return;
        }

        public PublicKey getPublicKey() throws FileNotFoundException, CertificateException {
            FileInputStream fileInputStream = null;
            try {
                fileInputStream = new FileInputStream(crtFile);
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(fileInputStream);
                return certificate.getPublicKey();
            } finally {
                IOUtils.closeQuietly(fileInputStream);
            }
        }
    }

}

使用HttpsURLConnection访问Https服务时

在访问HTTPS或项目启动时调用SSLClientUtil验证方法

仅验证证书

File file = new File("E:\\key\\pay.cer");
new SSLClientUtil().setSSLVerifyWithoutDomain(file);

验证证书和域名

File file = new File("E:\\key\\pay.cer");
new SSLClientUtil().setSSLVerify(file);

证书文件可通过Firefox浏览器导出证书,或者使用keytool -export导出的证书

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值