SpringBoot 自签名证书使用 及 HttpClient调用自签名服务器Https接口报错

获取自签名证书

openssl keytool 钥匙串(mac) 都可以生成自签名证书,这里不多描述
openssl生成ip证书
openssl生成域名证书
在这里插入图片描述
在这里插入图片描述

SpringBoot 配置自签名证书

server:
  ssl:
  	# 证书存储路径
    key-store: classpath:config/tls/my.p12
    # 密码
    key-store-password: password
    # 存储类型
    key-store-type: PKCS12

JDK导入自签名证书且启用信任证书

证书导入

使用keytool将需要添加信任的证书导入到jssecacerts 存储文件中去
可以参考命令提示使用
-importcert 导入证书或证书链
-importkeystore 从其他密钥库导入一个或所有条目

xxxxxx@bogon security % keytool 
密钥和证书管理工具
命令:

 -certreq            生成证书请求
 -changealias        更改条目的别名
 -delete             删除条目
 -exportcert         导出证书
 -genkeypair         生成密钥对
 -genseckey          生成密钥
 -gencert            根据证书请求生成证书
 -importcert         导入证书或证书链
 -importpass         导入口令
 -importkeystore     从其他密钥库导入一个或所有条目
 -keypasswd          更改条目的密钥口令
 -list               列出密钥库中的条目
 -printcert          打印证书内容
 -printcertreq       打印证书请求的内容
 -printcrl           打印 CRL 文件的内容
 -storepasswd        更改密钥库的存储口令
 -showinfo           显示安全相关信息

使用 "keytool -?, -h, or --help" 可输出此帮助消息
使用 "keytool -command_name --help" 可获取 command_name 的用法。
使用 -conf <url> 选项可指定预配置的选项文件

从另一个存储库导入到jssecacerts
keytool -importkeystore -keystore jssecacerts -srckeystore /path/config/tls/my.p12

启用信任证书

JDK有TrustStoreManager 功能读取受信任的证书,代码请参考sun.security.ssl.TrustStoreManager
可以通过定义配置来设置相关属性

        String storePropName = System.getProperty(
                "javax.net.ssl.trustStore", jsseDefaultStore);
        String storePropType = System.getProperty(
                "javax.net.ssl.trustStoreType",
                KeyStore.getDefaultType());
        String storePropProvider = System.getProperty(
                "javax.net.ssl.trustStoreProvider", "");
        String storePropPassword = System.getProperty(
                "javax.net.ssl.trustStorePassword", "");
package sun.security.ssl;

import java.io.*;
import java.lang.ref.WeakReference;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import java.util.concurrent.locks.ReentrantLock;
import sun.security.action.*;
import sun.security.util.FilePaths;
import sun.security.validator.TrustStoreUtil;

/**
 * Collection of static utility methods to manage the default trusted KeyStores
 * effectively.
 */
final class TrustStoreManager {

    // A singleton service to manage the default trusted KeyStores effectively.
    private static final TrustAnchorManager tam = new TrustAnchorManager();

    // Restrict instantiation of this class.
    private TrustStoreManager() {
        // empty
    }

    /**
     * Return an unmodifiable set of all trusted X509Certificates contained
     * in the default trusted KeyStore.
     */
    public static Set<X509Certificate> getTrustedCerts() throws Exception {
        return tam.getTrustedCerts(TrustStoreDescriptor.createInstance());
    }

    /**
     * Return an instance of the default trusted KeyStore.
     */
    public static KeyStore getTrustedKeyStore() throws Exception {
        return tam.getKeyStore(TrustStoreDescriptor.createInstance());
    }

    /**
     * A descriptor of the default trusted KeyStore.
     *
     * The preference of the default trusted KeyStore is:
     *    javax.net.ssl.trustStore
     *    jssecacerts
     *    cacerts
     */
    private static final class TrustStoreDescriptor {
        private static final String fileSep = File.separator;
        /**
        * 默认的证书存储路径
        */
        private static final String defaultStorePath =
                GetPropertyAction.privilegedGetProperty("java.home") +
                fileSep + "lib" + fileSep + "security";
        private static final String defaultStore = FilePaths.cacerts();
        /**
        * 证书存储文件路径
        */
        private static final String jsseDefaultStore =
                defaultStorePath + fileSep + "jssecacerts";

        // the trust store name
        private final String storeName;

        // the trust store type, JKS/PKCS12
        private final String storeType;

        // the provider of the trust store
        private final String storeProvider;

        // the password used for the trust store
        private final String storePassword;

        // the File object of the trust store
        private final File storeFile;

        // the last modified time of the store
        private final long lastModified;

        private TrustStoreDescriptor(String storeName, String storeType,
                String storeProvider, String storePassword,
                File storeFile, long lastModified) {
            this.storeName = storeName;
            this.storeType = storeType;
            this.storeProvider = storeProvider;
            this.storePassword = storePassword;
            this.storeFile = storeFile;
            this.lastModified = lastModified;

            if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
                SSLLogger.fine(
                    "trustStore is: " + storeName + "\n" +
                    "trustStore type is: " + storeType + "\n" +
                    "trustStore provider is: " + storeProvider + "\n" +
                    "the last modified time is: " + (new Date(lastModified)));
            }
        }

        /**
         * Create an instance of TrustStoreDescriptor for the default
         * trusted KeyStore.
         */
        @SuppressWarnings({"removal","Convert2Lambda"})
        static TrustStoreDescriptor createInstance() {
             return AccessController.doPrivileged(
                    new PrivilegedAction<TrustStoreDescriptor>() {

                @Override
                public TrustStoreDescriptor run() {
                    // Get the system properties for trust store.
                    String storePropName = System.getProperty(
                            "javax.net.ssl.trustStore", jsseDefaultStore);
                    String storePropType = System.getProperty(
                            "javax.net.ssl.trustStoreType",
                            KeyStore.getDefaultType());
                    String storePropProvider = System.getProperty(
                            "javax.net.ssl.trustStoreProvider", "");
                    // 证书存储的口令
                    String storePropPassword = System.getProperty(
                            "javax.net.ssl.trustStorePassword", "");

                    String temporaryName = "";
                    File temporaryFile = null;
                    long temporaryTime = 0L;
                    if (!"NONE".equals(storePropName)) {
                        String[] fileNames =
                                new String[] {storePropName, defaultStore};
                        for (String fileName : fileNames) {
                            File f = new File(fileName);
                            if (f.isFile() && f.canRead()) {
                                temporaryName = fileName;
                                temporaryFile = f;
                                temporaryTime = f.lastModified();

                                break;
                            }

                            // Not break, the file is inaccessible.
                            if (SSLLogger.isOn &&
                                    SSLLogger.isOn("trustmanager")) {
                                SSLLogger.fine(
                                        "Inaccessible trust store: " +
                                        fileName);
                            }
                        }
                    } else {
                        temporaryName = storePropName;
                    }

                    return new TrustStoreDescriptor(
                            temporaryName, storePropType, storePropProvider,
                            storePropPassword, temporaryFile, temporaryTime);
                }
            });
        }

    /**
     * The trust anchors manager used to expedite the performance.
     *
     * This class can be used to provide singleton services to access default
     * trust KeyStore more effectively.
     */
    private static final class TrustAnchorManager {
        // Last trust store descriptor.
        private TrustStoreDescriptor descriptor;

        // The key store used for the trust anchors.
        //
        // Use weak reference so that the heavy loaded KeyStore object can
        // be atomically cleared, and reloaded if needed.
        private WeakReference<KeyStore> ksRef;

        // The trusted X.509 certificates in the key store.
        //
        // Use weak reference so that the heavy loaded certificates collection
        // objects can be atomically cleared, and reloaded if needed.
        private WeakReference<Set<X509Certificate>> csRef;

        private final ReentrantLock tamLock = new ReentrantLock();

        private TrustAnchorManager() {
            this.descriptor = null;
            this.ksRef = new WeakReference<>(null);
            this.csRef = new WeakReference<>(null);
        }

        /**
         * Get the default trusted KeyStore with the specified descriptor.
         *
         * @return null if the underlying KeyStore is not available.
         */
        KeyStore getKeyStore(
                TrustStoreDescriptor descriptor) throws Exception {

            TrustStoreDescriptor temporaryDesc = this.descriptor;
            KeyStore ks = ksRef.get();
            if ((ks != null) && descriptor.equals(temporaryDesc)) {
                return ks;
            }

            tamLock.lock();
            try {
                // double check
                ks = ksRef.get();
                if ((ks != null) && descriptor.equals(temporaryDesc)) {
                    return ks;
                }

                // Reload a new key store.
                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
                    SSLLogger.fine("Reload the trust store");
                }

                ks = loadKeyStore(descriptor);
                this.descriptor = descriptor;
                this.ksRef = new WeakReference<>(ks);
            } finally {
                tamLock.unlock();
            }

            return ks;
        }

        /**
         * Get trusted certificates in the default trusted KeyStore with
         * the specified descriptor.
         *
         * @return empty collection if the underlying KeyStore is not available.
         */
        Set<X509Certificate> getTrustedCerts(
                TrustStoreDescriptor descriptor) throws Exception {

            KeyStore ks = null;
            TrustStoreDescriptor temporaryDesc = this.descriptor;
            Set<X509Certificate> certs = csRef.get();
            if ((certs != null) && descriptor.equals(temporaryDesc)) {
                return certs;
            }

            tamLock.lock();
            try {
                // double check
                temporaryDesc = this.descriptor;
                certs = csRef.get();
                if (certs != null) {
                    if (descriptor.equals(temporaryDesc)) {
                        return certs;
                    } else {
                        // Use the new descriptor.
                        this.descriptor = descriptor;
                    }
                } else {
                    // Try to use the cached store at first.
                    if (descriptor.equals(temporaryDesc)) {
                        ks = ksRef.get();
                    } else {
                        // Use the new descriptor.
                        this.descriptor = descriptor;
                    }
                }

                // Reload the trust store if needed.
                if (ks == null) {
                    if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
                        SSLLogger.fine("Reload the trust store");
                    }
                    ks = loadKeyStore(descriptor);
                    this.ksRef = new WeakReference<>(ks);
                }

                // Reload trust certs from the key store.
                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
                    SSLLogger.fine("Reload trust certs");
                }

                certs = loadTrustedCerts(ks);
                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
                    SSLLogger.fine("Reloaded " + certs.size() + " trust certs");
                }

                this.csRef = new WeakReference<>(certs);
            } finally {
                tamLock.unlock();
            }

            return certs;
        }

        /**
         * Load the KeyStore as described in the specified descriptor.
         */
        private static KeyStore loadKeyStore(
                TrustStoreDescriptor descriptor) throws Exception {
            if (!"NONE".equals(descriptor.storeName) &&
                    descriptor.storeFile == null) {

                // No file available, no KeyStore available.
                if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
                    SSLLogger.fine("No available key store");
                }

                return null;
            }

            KeyStore ks;
            if (descriptor.storeProvider.isEmpty()) {
                ks = KeyStore.getInstance(descriptor.storeType);
            } else {
                ks = KeyStore.getInstance(
                        descriptor.storeType, descriptor.storeProvider);
            }

            char[] password = null;
            if (!descriptor.storePassword.isEmpty()) {
                password = descriptor.storePassword.toCharArray();
            }

            if (!"NONE".equals(descriptor.storeName)) {
                try (@SuppressWarnings("removal") FileInputStream fis = AccessController.doPrivileged(
                        new OpenFileInputStreamAction(descriptor.storeFile))) {
                    ks.load(fis, password);
                } catch (FileNotFoundException fnfe) {
                    // No file available, no KeyStore available.
                    if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) {
                        SSLLogger.fine(
                            "Not available key store: " + descriptor.storeName);
                    }

                    return null;
                }
            } else {
                ks.load(null, password);
            }

            return ks;
        }

        /**
         * Load trusted certificates from the specified KeyStore.
         */
        private static Set<X509Certificate> loadTrustedCerts(KeyStore ks) {
            if (ks == null) {
                return Collections.<X509Certificate>emptySet();
            }

            return TrustStoreUtil.getTrustedCerts(ks);
        }
    }
}

问题:由于服务端使用自签名证书,导致客户端HttpClient调用的时候报错

由于服务端使用自签名证书,导致客户端HttpClient调用的时候报错

问题1.jdk找不到信任证书的存储文件

Exception in thread "main" javax.net.ssl.SSLHandshakeException: 
		PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
		unable to find valid certification path to requested target
	at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:578)
	at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:119)

解决办法

参考 > JDK导入自签名证书且启用信任证书>

问题2.确认证书存储中有证书,但是读取不到证书

Caused by: java.security.InvalidAlgorithmParameterException: 
		the trustAnchors parameter must be non-empty
	at java.base/java.security.cert.PKIXParameters.setTrustAnchors(PKIXParameters.java:200)
	at java.base/java.security.cert.PKIXParameters.<init>(PKIXParameters.java:120)
	at java.base/java.security.cert.PKIXBuilderParameters.<init>(PKIXBuilderParameters.java:104)
	at java.base/sun.security.validator.PKIXValidator.<init>(PKIXValidator.java:98)

解决办法

设置存储库的访问密码

System.setProperty("javax.net.ssl.trustStorePassword", "password(自己证书库的密码)");

问题3.No subject alternative names present

这种问题是证书有问题,需要重新生成具有DnsIP的证书

Caused by: java.security.cert.CertificateException: No subject alternative names present
	at java.base/sun.security.util.HostnameChecker.matchIP(HostnameChecker.java:142)
	at java.base/sun.security.util.HostnameChecker.match(HostnameChecker.java:101)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:452)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:426)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:292)
	at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:144)
	at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:632)
	... 21 more

跳过HttpClient请求时证书验证

参考实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值