Restlet javax.net.ssl.SSLHandshakeException:null cert chain

我正在本地测试客户端和服务器之间的SSL通信。 所以我使用OpenSSL命令生成证书。 在cacert文件中添加了此证书。 还生成.p12文件。

我在服务器和客户端使用相同的.p12文件。 这是服务器代码

Server server = component.getServers().add(Protocol.HTTPS, port); Series params = server.getContext().getParameters(); params.add("keystorePath", ".p12 file path"); params.add("keystoreType", "PKCS12"); params.add("needClientAuthentication","true"); component.getDefaultHost().attach("", "/AA"), new AAClass()); component.start(); 

这是客户端代码:

 Client client = trustAllCerts(); clientResource = new ClientResource(url); clientResource.setNext(client); try{ clientText = clientResource.post""); } catch(ResourceException e){ e.printStackTrace(); } public Client trustAllCerts() { Client client = null; try { client = new Client(new Context(), Protocol.HTTPS); Context context = client.getContext(); final SSLContext sslContext = SSLContext.getInstance("TLSv1.2"); context.getAttributes().put("sslContextFactory", new SslContextFactory() { public void init(Series parameters) { } public SSLContext createSslContext() { return sslContext; } }); TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; context.getAttributes().put("hostnameVerifier", new HostnameVerifier() { @Override public boolean verify(String arg0, SSLSession arg1) { return true; } }); sslContext.init(null, new TrustManager[] { tm }, null); } catch (KeyManagementException e) { LOGGER.error("Exception in Key Management" + e); } catch (NoSuchAlgorithmException e) { LOGGER.error("Exception in Algorithm Used" + e); } return client; } 

我得到以下exception:

 Restlet-1299242, fatal error: 42: null cert chain javax.net.ssl.SSLHandshakeException: null cert chain %% Invalidated: [Session-25, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256] Restlet-1299242, SEND TLSv1.2 ALERT: fatal, description = bad_certificate Restlet-1299242, WRITE: TLSv1.2 Alert, length = 2 Restlet-1299242, fatal: engine already closed. Rethrowing javax.net.ssl.SSLHandshakeException: null cert chain Restlet-1299242, called closeInbound() Restlet-1299242, fatal: engine already closed. Rethrowing javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack? Restlet-1299242, called closeOutbound() Restlet-1299242, closeOutboundInternal() 

我尝试使用System.setProperty()添加密钥库和信任库,但它不起作用。

请帮忙。 提前致谢。

首先,让我们创建一个JKS格式的密钥库。 PKCS12通常用于浏览器,默认的java应用程序使用JKS(据我所知)。 Java也支持PKCS12,但我不知道它的确切参数。

准备JKS文件

让我们查看我们的PKCS12文件并获取我们想要提取JKS文件的证书别名。

 keytool -list \ -keystore [*.p12 file] \ -storepass [password] \ -storetype PKCS12 \ -v 

请注意要导出的别名。 现在让我们创建一个JKS文件。

 keytool -keystore [*.jks file path] -genkey -alias client 

这会问一堆问题。 你可以随意填写它们。 现在,您可以将别名从* .p12文件导出到* .jks文件。

 keytool -importkeystore \ -srckeystore [*.p12 file path] \ -srcstoretype pkcs12 \ -srcalias [alias from first command] \ -destkeystore [*.jks file path] \ -deststoretype jks \ -deststorepass [*.jks file password] \ -destalias [new alias] 

如果您没有任何PKCS12文件,或者您的证书是CER,DER或PEM格式,则可以使用以下命令将证书添加到密钥库。

 keytool -import \ -alias [new alias] \ -keystore [*.jks file path] \ -file [*.DER file path] 

请确保您已导入,您的证书,证书提供商的证书(中间证书)和根证书。

现在您可以检查您的JKS文件是否包含您需要的所有证书。

 keytool -list \ -keystore [*.jks file path] \ -storepass [password] \ -storetype jks \ -v 

设置服务器

您可以在客户端和服务器端使用JKS文件。 根据Restlet文档,您可以使用这样的JKS文件来提供HTTPS连接。

 Server server = component.getServers().add(Protocol.HTTPS, port); Series parameters = server.getContext().getParameters(); parameters.add("sslContextFactory","org.restlet.engine.ssl.DefaultSslContextFactory"); parameters.add("keyStorePath", "*.jks file"); parameters.add("keyStorePassword", "password"); parameters.add("keyPassword", "password"); parameters.add("keyStoreType", "JKS"); 

之后,如果您从浏览器检查端口,则必须看到安全标志。 或者您可以使用一些在线工具( 如此 )来检查您的证书。

设置客户端

现在让我们来看看客户端。 由于您正在开发应用程序的两端,因此您可以使用已创建的JKS文件。

 Context con = new Context(); Series clParameters = con.getParameters(); clParameters.add("truststorePath", "*.jks file"); clParameters.add("truststorePassword", "password"); clParameters.add("truststoreType", "JKS"); Client restletClient = new Client(con, Protocol.HTTPS); 

在测试时或在其他情况下,您的证书主机名和实际主机名可能不匹配。 要禁用主机名检查,可以将此块添加到应用程序中。

 static{ javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier( new javax.net.ssl.HostnameVerifier(){ public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession ) { return true ; } }); } 

一些想法

由于我无法在我的语言环境中测试它,因此我不确定您的客户端和服务器JKS文件必须是否相同。 您可能只需要将自己的证书添加到server.jks。 SSL和证书对我来说总是很棘手。 经过一些试验和错误,我通常会让它工作。 我希望这能帮到您。

此外,您可能还需要考虑使用反向代理类型的Web服务器,如Apache2或Nginx。 如果要使用它们,则必须将证书合并到单个文件中。 如果查看证书文件,您会看到每个文件(您自己的证书,中间证书和根证书)都是这样的

 -----BEGIN CERTIFICATE----- MIIDfTCCAuagAwIBAgIDErvmMA0GCSqGSIb3DQEBBQUA... .... -----END CERTIFICATE----- 

您只需将一个添加到另一个即可创建合并证书。 而是使用该证书在Apache2或Nginx上结束SSL。 这就是我通常做的事情。 但在客户端,您仍然需要创建JKS文件。

我在服务器和客户端使用相同的.p12文件

这已经是一个错误。 客户端和服务器是不同的身份,不应具有相同的私钥,公钥或证书。

我建议你放弃所有OpenSSL的东西,然后用keytool重新开始,如下所示:

  1. 在服务器上,生成密钥对和证书请求; 把它签名; 使用-trustcacerts选项导入签名者的证书链; 并使用您在创建密钥对和CSR时使用的相同别名导入签名证书
  2. 在客户端 ,同上,但使用(当然)不同的密钥库文件。
  3. 你完成了。 把…忘了吧

    • OpenSSL的
    • PKCS#12
    • 自签名证书
    • 所有forms的trustAllCerts ,自定义TrustManagers以及任何类型的自定义代码
    • 为服务器和客户端使用相同的密钥对/证书
    • 将服务器证书导入客户端, 反之亦然
    • 除了那些标识javax.net.ssl.keyStorejavax.net.ssl.keyStorePassword系统属性之外的任何系统属性
    • 在密钥对或导入的签名证书上设置密码。

步骤(1)和(2)是如何完成的。 离开那些,你陷入困境和纷争。

您可能没有在密钥库中添加完整的证书链,只包括密钥对本身。 在这种情况下,客户端只接收公钥,但无法validation该密钥是否可信任。 证书链可以检查公钥上的签名是否匹配,并引导到受信任的证书颁发机构。

请参阅例如: 将证书链添加到p12(pfx)证书

 openssl pkcs12 -in certificate.p12 -out clientcert.pem -nodes -clcerts openssl x509 -in trusted_ca.cer -inform DER -out trusted_ca.pem openssl x509 -in root_ca.cer -inform DER -out root_ca.pem cat clientcert.pem trusted_ca.pem root_ca.pem >> clientcertchain.pem openssl pkcs12 -export -in clientcertchain.pem -out clientcertchain.pfx 

您也可以使用java方式,例如portecle: http ://portecle.sourceforge.net/import-ca-reply.html,但您还需要将证书链组合在一个文件中以进行导入。 只需将所有证书相互粘贴,从您自己开始,然后以根CA结束。

这样,可以在服务器上使用生成的pfx文件将证书链返回给客户端。

一种选择是读取p12 / pfx文件,获取证书并使用它们以编程方式构建KeyStores和TrustStores。 如果输入是一个包含CA根证书和相关客户端证书的pfx文件,则下面的SslUtils类中显示的方法将允许您这样做。
但有一点需要注意:默认的Restlet服务器(版本2.3.4)不会获取客户端发送的证书。 我确实设法解决了这个问题(虽然它并不漂亮),请参阅我对这个问题的回答 。

我将重点介绍如何配置安全连接,但是restlet-clientcert Github项目中提供了所有源代码和工作示例。 Github项目是我认为我知道自己在做什么,没有运气和没有Restlet经验的结果,但无论如何都咬紧牙关,所以我可以感觉更好一点,知道我可以让这些基本的东西起作用。

在服务器端,使用以编程方式配置已使用的SSLContext的自定义ServerSslContextFactory 。 注册自定义工厂:

 ServerSslContextFactory sslCtx = new ServerSslContextFactory(); sslCtx.init(certFileName, certFilePwd); ConcurrentMap attribs = server.getContext().getAttributes(); attribs.put("sslContextFactory", sslCtx); 

并附加“警卫”以提取客户端证书信息:

 CertificateAuthenticator guard = new CertificateAuthenticator(server.getContext()); guard.setNext(MyRestlet.class); component.getDefaultHost().attachDefault(guard); 

ServerSslContextFactory

 public class ServerSslContextFactory extends DefaultSslContextFactory { private static final Logger log = LoggerFactory.getLogger(ServerSslContextFactory.class); protected DefaultSslContext wrappedCtx; public void init(String certFileName, char[] certFilePwd) throws Exception { if (log.isDebugEnabled()) { log.debug("Loading certificates from [" + certFileName + "] and using " + (certFilePwd != null && certFilePwd.length > 0 ? "a" : "no") + " password."); } Path certFilePath = Paths.get(Thread.currentThread().getContextClassLoader().getResource(certFileName).toURI()); KeyManagerFactory kmf = SslUtils.loadKeyStore(certFilePath, certFilePwd); KeyManager[] kms = kmf.getKeyManagers(); List certs = SslUtils.getClientCaCerts(kms); TrustManagerFactory tmf = SslUtils.createTrustStore(Constants.CERT_CA_ALIAS, certs.get(0)); TrustManager[] tms = tmf.getTrustManagers(); super.setNeedClientAuthentication(true); SSLContext ctx = SSLContext.getInstance(SslUtils.DEFAULT_SSL_PROTOCOL); ctx.init(kms, tms, null); wrappedCtx = (DefaultSslContext) createWrapper(ctx); } @Override public void init(Series parameters) { log.debug("Not using parameters to initialize server SSL Context factory."); } @Override public SSLContext createSslContext() throws Exception { return wrappedCtx; } @Override public boolean isNeedClientAuthentication() { if (log.isDebugEnabled()) { //log.debug("Needing client auth: " + super.isNeedClientAuthentication(), new RuntimeException("trace")); log.debug("Needing client auth: " + super.isNeedClientAuthentication()); } return super.isNeedClientAuthentication(); } } 

在客户端,类似的事情:

 ClientSslContextFactory sslCtx = new ClientSslContextFactory(); sslCtx.init(certFileName, certFilePwd); attribs.put("sslContextFactory", sslCtx); 

还要设置hostnameVerifier (如您的问题所示)以不validation主机名。
ClientSslContextFactory

 public class ClientSslContextFactory extends SslContextFactory { private static final Logger log = LoggerFactory.getLogger(ClientSslContextFactory.class); protected KeyManager[] kms; protected TrustManager[] tms; public void init(String certFileName, char[] certFilePwd) throws Exception { log.debug("Loading certificates from [" + certFileName + "] and using " + (certFilePwd != null && certFilePwd.length > 0 ? "a" : "no") + " password."); Path certFilePath = Paths.get(Thread.currentThread().getContextClassLoader().getResource(certFileName).toURI()); KeyManagerFactory kmf = SslUtils.loadKeyStore(certFilePath, certFilePwd); kms = kmf.getKeyManagers(); /* List certs = SslUtils.getClientCaCerts(kms); TrustManagerFactory tmf = SslUtils.createTrustStore(Constants.CERT_CA_ALIAS, certs.get(0)); tms = tmf.getTrustManagers(); */ tms = new TrustManager[1]; tms[0] = new TrustServerCertAlways(); } @Override public void init(Series parameters) { log.debug("Not using parameters to initialize client SSL Context factory."); } @Override public SSLContext createSslContext() throws Exception { SSLContext ctx = SSLContext.getInstance(SslUtils.DEFAULT_SSL_PROTOCOL); ctx.init(kms, tms, null); return ctx; } static class TrustServerCertAlways implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { log.debug("Trusting all client certificates."); } @Override public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { log.debug("Trusting all server certificates."); } @Override public X509Certificate[] getAcceptedIssuers() { log.debug("No accepted issuers."); return null; } } } 

最后,包含“读取和重建”方法的SslUtils类(包括“从证书中获取电子邮件地址”方法的完整版本在前面提到的Github项目中可用):

 import java.io.InputStream; import java.net.Authenticator; import java.net.PasswordAuthentication; import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyStore; import java.security.KeyStore.LoadStoreParameter; import java.security.cert.X509Certificate; import java.util.*; import javax.net.ssl.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SslUtils { private static final Logger log = LoggerFactory.getLogger(SslUtils.class); /** * List of SSL protocols (SSLv3, TLSv1.2, etc.). See also {@link SslUtils#DEFAULT_SSL_PROTOCOL}. * 
Documented at http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext */ public static final String[] SSL_PROTOCOLS = new String[] { "SSL", "SSLv2", "SSLv3", "TLS", "TLSv1", "TLSv1.1", "TLSv1.2" }; /** * Default SSL protocol to use ("TLSv1.2"). */ public static final String DEFAULT_SSL_PROTOCOL = "TLSv1.2"; /** * Creates a default SSL context with an empty key-store and the default JRE trust-store. */ public static SSLContext createDefaultSslContext() throws Exception { return createSslContext(null, null, null, null); } /** * Creates a default SSL socket factory. *
All system properties related to trust/key-stores are ignored, eveything is done programmatically. * This is because the Sun implementation reads the system-properties once and then caches the values. * Among other things, this fails the unit tests. *
For reference, the system properties (again, NOT USED): *
- javax.net.ssl.trustStore (default cacerts.jks) *
- javax.net.ssl.trustStorePassword *
and for client certificate: *
- javax.net.ssl.keyStore (set to "agent-cert.p12") *
- javax.net.ssl.keyStoreType (set to "pkcs12") *
- javax.net.ssl.keyStorePassword *
See for a discussion: * https://stackoverflow.com/questions/6340918/trust-store-vs-key-store-creating-with-keytool *
See for client certificates in Java: * https://stackoverflow.com/questions/1666052/java-https-client-certificate-authentication * @param keyStoreFileName The name (ending with pfx) of the file with client certificates. * @param trustStoreFileName The name (ending with jks) of the Java KeyStore with trusted (root) certificates. * @return null or the SSLContext. */ public static SSLContext createSslContext(Path keyStoreFile, String keyStorePwd, Path trustStoreFile, String trustStorePwd) throws Exception { return createSslContext(keyStoreFile, keyStorePwd, trustStoreFile, trustStorePwd, DEFAULT_SSL_PROTOCOL); } /** * See {@link #createSslContext(Path, String, Path, String)}. * @param sslProtocol a value from {@link #SSL_PROTOCOLS}. */ public static SSLContext createSslContext(Path keyStoreFile, String keyStorePwd, Path trustStoreFile, String trustStorePwd, String sslProtocol) throws Exception { KeyManagerFactory kmf = loadKeyStore(keyStoreFile, keyStorePwd == null ? null : keyStorePwd.toCharArray()); TrustManagerFactory tmf = loadTrustStore(trustStoreFile, trustStorePwd == null ? null : trustStorePwd.toCharArray()); //set an Authenticator to generate username and password SSLContext ctx = SSLContext.getInstance(sslProtocol); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return ctx; } /** * Calls {@link #createSslContextFromClientKeyStore(Path, String, Path, String)} with the {@link #DEFAULT_SSL_PROTOCOL}. */ public static SSLContext createSslContextFromClientKeyStore(Path keyStoreFile, String keyStorePwd, String caAlias) throws Exception { return createSslContextFromClientKeyStore(keyStoreFile, keyStorePwd, caAlias, DEFAULT_SSL_PROTOCOL); } /** * Creates a SSL context from the given key-store containing a client certificate and a (CA) root certificate. * The root certificate is set in the trust-store of the SSL context. * @param keyStoreFileName key-store file name (ending with .pfx). * @param keyStorePwd key-store password * @param caAlias the alias to use for the CA (root) certificate (eg "mycaroot"). * @param sslProtocol the ssl-protocol (eg {@link #DEFAULT_SSL_PROTOCOL}). */ public static SSLContext createSslContextFromClientKeyStore(Path keyStoreFile, String keyStorePwd, String caAlias, String sslProtocol) throws Exception { KeyManagerFactory kmf = loadKeyStore(keyStoreFile, keyStorePwd == null ? null : keyStorePwd.toCharArray()); List certs = getClientCaCerts(kmf.getKeyManagers()); if (certs.size() < 1) { throw new Exception("Cannot find CA (root) certificate in key-managers from key store " + keyStoreFile.getFileName()); } TrustManagerFactory tmf = createTrustStore(caAlias, certs.get(0)); SSLContext ctx = SSLContext.getInstance(sslProtocol); ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); return ctx; } public static KeyManagerFactory loadKeyStore(Path storeFile) throws Exception { return loadKeyStore(storeFile, null); } public static KeyManagerFactory loadKeyStore(Path storeFile, char[] storePwd) throws Exception { return loadKeyStore(storeFile, storePwd, null, null); } public static KeyManagerFactory loadKeyStore(Path storeFile, char[] storePwd, String storeType, String algorithm) throws Exception { KeyManagerFactory kmf = null; if (storeFile == null) { kmf = loadKeyStore((InputStream)null, storePwd, storeType, algorithm); } else { try (InputStream storeIn = Files.newInputStream(storeFile)) { kmf = loadKeyStore(storeIn, storePwd, storeType, algorithm); log.info("Initialized certificate key-store from [" + storeFile.getFileName() + "]"); } } return kmf; } public static KeyManagerFactory loadKeyStore(InputStream storeIn, char[] storePwd, String storeType, String algorithm) throws Exception { if (storePwd == null && storeIn != null) { storePwd = "changeit".toCharArray(); log.debug("Using default key store password."); } if (storeType == null) { storeType = "pkcs12"; log.debug("Using default key store type " + storeType); } if (algorithm == null) { algorithm = KeyManagerFactory.getDefaultAlgorithm(); // "SunX509" log.debug("Using default key store algorithm " + algorithm); } KeyManagerFactory kmf = null; KeyStore keyStore = loadStore(storeIn, storePwd, storeType); kmf = KeyManagerFactory.getInstance(algorithm); kmf.init(keyStore, storePwd); if (storeIn == null) { log.info("Initialized a default certificate key-store"); } return kmf; } /** * Creates a trust-store with the given CA (root) certificate. * @param certAlias the alias for the certificate (eg "mycaroot") * @param caCert the CA (root) certificate * @return an initialized trust manager factory. */ public static TrustManagerFactory createTrustStore(String certAlias, X509Certificate caCert) throws Exception { KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load((LoadStoreParameter)null); // must initialize the key-store ks.setCertificateEntry(certAlias, caCert); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); return tmf; } public static TrustManagerFactory loadTrustStore(Path storeFile) throws Exception { return loadTrustStore(storeFile, null); } public static TrustManagerFactory loadTrustStore(Path storeFile, char[] storePwd) throws Exception { return loadTrustStore(storeFile, storePwd, null, null); } public static TrustManagerFactory loadTrustStore(Path storeFile, char[] storePwd, String storeType, String algorithm) throws Exception { TrustManagerFactory tmf = null; if (storeFile == null) { tmf = loadTrustStore((InputStream)null, storePwd, storeType, algorithm); } else { try (InputStream storeIn = Files.newInputStream(storeFile)) { tmf = loadTrustStore(storeIn, storePwd, storeType, algorithm); } log.info("Initialized certificate trust-store from [" + storeFile.getFileName() + "]"); } return tmf; } public static TrustManagerFactory loadTrustStore(InputStream storeIn, char[] storePwd, String storeType, String algorithm) throws Exception { if (storePwd == null && storeIn != null) { storePwd = "changeit".toCharArray(); log.debug("Using default trust store password."); } if (storeType == null) { storeType = KeyStore.getDefaultType(); log.debug("Using default trust store type " + storeType); } if (algorithm == null) { algorithm = TrustManagerFactory.getDefaultAlgorithm(); log.debug("Using default trust store algorithm " + algorithm); } TrustManagerFactory tmf = null; KeyStore trustStore = loadStore(storeIn, storePwd, storeType); tmf = TrustManagerFactory.getInstance(algorithm); tmf.init(trustStore); if (storeIn == null) { log.info("Initialized a default certificate trust-store"); } return tmf; } /** * Creates a default trust store containing the JRE certificates in {@code JAVA_HOME\lib\security\cacerts.jks} *
To view loaded certificates call *
{@code System.setProperty("javax.net.debug", "ssl,trustmanager");} *
before calling this method. */ public static TrustManagerFactory createDefaultTrustStore() throws Exception { TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init((KeyStore)null); return tmf; } /** * @param in if null, null is returned. */ public static KeyStore loadStore(InputStream in, char[] pwd, String type) throws Exception { if (in == null) { return null; } KeyStore ks = KeyStore.getInstance(type); ks.load(in, pwd); return ks; } /** * Finds any CA (root) certificates present in client certificate chains. *
Uses {@link #getClientAliases(KeyManager)} * @param kms key-managers (from a key-store). * @return an empty list or a list containing CA (root) certificates. */ public static List
getClientCaCerts(KeyManager[] kms) { List caCerts = new LinkedList(); for (int i = 0; i < kms.length; i++) { if (!(kms[i] instanceof X509KeyManager)) { continue; } X509KeyManager km = (X509KeyManager) kms[i]; List aliases = getClientAliases(km); for (String alias: aliases) { X509Certificate[] cchain = km.getCertificateChain(alias); if (cchain == null || cchain.length < 2) { continue; } // first certificate in chain is the user certificate // last certificate is the CA (root certificate). caCerts.add(cchain[cchain.length-1]); if (log.isDebugEnabled()) { log.debug("Found 1 root certificate from client certificate alias " + alias); } } } return caCerts; } /** * List of key types for client certificate aliases, used in {@link #getAliases(KeyManager)} *
List is documented at * http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#jssenames */ public static final String[] KEY_TYPES = new String[] {"RSA", "DSA", "DH_RSA", "DH_DSA", "EC", "EC_EC", "EC_RSA" }; /** * Searches for client aliases in the given key-manager. * Does nothing when the given key-manager is not an instance of {@link X509KeyManager}. * @return an empty list or a list containing client aliases found in the key-manager. */ public static List
getClientAliases(KeyManager keyManager) { List aliases = new LinkedList(); if (keyManager instanceof X509KeyManager) { X509KeyManager km = (X509KeyManager) keyManager; for (String keyType: KEY_TYPES) { String[] kmAliases = km.getClientAliases(keyType, null); if (kmAliases != null) { for (String alias: kmAliases) { if (!isEmpty(alias)) { aliases.add(alias); } } } } // for keytypes } return aliases; } /** * Sets the default authenticator which can be used for example with http-request that require basic authoriation. *
See also {@link Authenticator#setDefault(Authenticator)}. */ public static void setDefaultAuthenticator(final String userName, final char[] pwd) throws Exception { Authenticator auth = new Authenticator() { @Override protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(userName, pwd); } }; Authenticator.setDefault(auth); } /** * @return true if s is not null and not empty after trimming, false otherwise. */ public static boolean isEmpty(String s) { return (s == null || s.trim().isEmpty()); } }

在侧节点上:Java正在将默认密钥库类型从JKS转换为PKCS12(请参阅JEP 229 )。