获取自签名证书
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
这种问题是证书有问题,需要重新生成具有Dns
或IP
的证书
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