抛出NoSuchAlgorithException的Java SSL代码

Mat*_*922 7 java ssl

我正在开发一个我想要添加SSL的项目,所以我创建了一个简单的客户端/服务器测试实现,看看它是否有效,我得到一个NoSuchAlgorithmException.以下是我抛出异常的服务器代码:

import java.io.*;
import java.net.*;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.*;

public class SslServer
{
    private static final int PORT = 5555;

    public static void main(String[] args)
    {
        SecureRandom sr = new SecureRandom();
        sr.nextInt();

        try {
            //client.public is the keystore file that holds the client's public key (created with keytool)
            KeyStore clientKeyStore = KeyStore.getInstance("JKS");
            clientKeyStore.load(new FileInputStream("client.public"), "clientpublicpw".toCharArray());

            //server.private is the key pair for the server (created with keytool)
            KeyStore serverKeyStore = KeyStore.getInstance("JKS");
            clientKeyStore.load(new FileInputStream("server.private"), "serverprivatepw".toCharArray());

            TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
            tmf.init(clientKeyStore);

            //This next line is where the exception occurs
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("TLS");
            kmf.init(serverKeyStore, "serverprivatepw".toCharArray());

            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), sr);

            SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
            SSLServerSocket ss = (SSLServerSocket)sf.createServerSocket(SslServer.PORT);
            ss.setNeedClientAuth(true);

            BufferedReader in = new BufferedReader(new InputStreamReader(ss.accept().getInputStream()));

            String line = null;
            while((line = in.readLine()) != null)
            {
                System.out.println(line);
            }
            in.close();
            ss.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (CertificateException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        } catch (UnrecoverableKeyException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我得到的堆栈跟踪是:

java.security.NoSuchAlgorithmException: TLS KeyManagerFactory not available
    at sun.security.jca.GetInstance.getInstance(Unknown Source)
    at javax.net.ssl.KeyManagerFactory.getInstance(Unknown Source)
    at SslServer.main(SslServer.java:32)
Run Code Online (Sandbox Code Playgroud)

我尝试用"SSL"替换"TLS",但我仍然有同样的例外.那对我来说没有意义.如何不支持TLS和SSL?这是我第一次尝试实现SSL,并且很难通过代码示例找到很好的资源.任何人都可以告诉我为什么我得到这个例外或指出我的代码有问题?

Bru*_*uno 16

有很多问题:

  • 它被称为TLS(传输层安全性),而不是TSL(用于SSLContext).
  • 我建议在这里使用默认值:( TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())默认将PKIX在Oracle JRE`上)
  • (编辑:)默认KeyManagerFactorySunX509(TLS此处不存在).再次,使用getDefaultAlgorithm().
  • FileInputStream一旦你读完它们就应该关闭它们.
  • 目前尚不清楚为什么在同一个地方同时拥有客户端和服务器密钥库.这些应该是两个程序:一个用于客户端和服务器(并且setNeedClientAuth(true)仅在服务器端有用).如果它实际上是你的密钥库,那么将它称为"客户端存储"之外的东西会更清楚.(此外,由于您似乎正在学习如何使这项工作,我建议首先尝试没有客户端证书身份验证,在这种情况下,服务器将不需要信任库:null用作第二个参数SSLContext.init(...)来使用默认值.)
  • 不要将服务器密钥库提供给客户端.仅将其证书导出到将用作信任库的新密钥库.每个实体(客户端和服务器)都应该将自己的私钥保密.
  • 这不是您在信任存储中所需的远程方的公钥(仅限):它将成为其证书.确保您不仅导入了其公钥,还导入了整个证书.
  • 为了澄清,请对文件保留适当的扩展名:.jks用于JKS密钥库,这样可以避免以后的麻烦.
  • 您可以使用nullSecureRandomSSLContext.init(...):这将根据安全提供使用默认值.

这样的事情应该更好:

KeyStore trustStore = KeyStore.getInstance("JKS");
InputStream tsis = new FileInputStream("trustedcerts.jks");
trustStore.load(tsis, "clientpublicpw".toCharArray());
tsis.close();

KeyStore serverKeyStore = KeyStore.getInstance("JKS");
InputStream ksis = new FileInputStream("server.jks");
clientKeyStore.load(ksis.close(), "serverprivatepw".toCharArray());
ksis.close();

TrustManagerFactory tmf = 
    TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);

KeyManagerFactory kmf = 
    KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(serverKeyStore, "serverprivatepw".toCharArray());

SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
SSLServerSocket ss = (SSLServerSocket)sf.createServerSocket(SslServer.PORT);
ss.setNeedClientAuth(true);
Run Code Online (Sandbox Code Playgroud)