设置Java SSL服务器套接字使用的证书
我想在Java服务器应用程序中打开一个安全侦听套接字。我知道建议的方法是这样做:设置Java SSL服务器套接字使用的证书,java,ssl,Java,Ssl,我想在Java服务器应用程序中打开一个安全侦听套接字。我知道建议的方法是这样做: SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); ServerSocket ss = ssf.createServerSocket(443); 但这需要在启动java时将服务器的证书传递给JVM。因为这会使部署中的一些事情对我来说更加复杂,所以我更愿意在运行时加载证书 所以我有一个密
SSLServerSocketFactory ssf = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
ServerSocket ss = ssf.createServerSocket(443);
但这需要在启动java时将服务器的证书传递给JVM。因为这会使部署中的一些事情对我来说更加复杂,所以我更愿意在运行时加载证书
所以我有一个密钥文件和密码,我想要一个服务器套接字。我怎么去那里?嗯,我阅读了文档,我能找到的唯一方法是:
// these are my parameters for SSL encryption
char[] keyPassword = "P@ssw0rd!".toCharArray();
FileInputStream keyFile = new FileInputStream("ssl.key");
// init keystore
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(keyFile, keyPassword);
// init KeyManagerFactory
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, keyPassword);
// init KeyManager
KeyManager keyManagers[] = keyManagerFactory.getKeyManagers();
// init the SSL context
SSLContext sslContext = SSLContext.getDefault();
sslContext.init(keyManagers, null, new SecureRandom());
// get the socket factory
SSLServerSocketFactory socketFactory = sslContext.getServerSocketFactory();
// and finally, get the socket
ServerSocket serverSocket = socketFactory.createServerSocket(443);
这甚至没有任何错误处理。真的有那么复杂吗?难道没有更简单的方法吗?如果你看一下代码,你就会明白为什么它一定很复杂。此代码将SSL协议的实现与以下内容分离:
- 关键材料的来源(
)KeyStore
- 证书算法选择和密钥管理(
)KeyManager
- 对等信任规则的管理(
)-此处不使用TrustManager
- 安全随机算法(
)SecureRandom
- NIO或套接字实现(
)-可以对NIO使用SSLServerSocketFactory
SSLEngine
SSLServerSocket:
javax.net.ssl.keyStore ssl.key
javax.net.ssl.keyStorePassword P@ssw0rd!
您可以使用System.setProperties()
或在命令行上执行此操作。使用此选项
public class KeyMaster
{
public static SSLSocketFactory getSSLSocketFactory(KeyStore trustKey, String sslAlgorithm)
{
try
{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustKey);
SSLContext context = SSLContext.getInstance(sslAlgorithm);//"SSL" "TLS"
context.init(null, tmf.getTrustManagers(), null);
return context.getSocketFactory();
}
catch(Exception e)
{
Assistance.log("Err: getSSLSocketFactory(), ");
}
return null;
}
public static SSLServerSocketFactory getSSLServerSocketFactory(KeyStore trustKey, String sslAlgorithm)
{
try
{
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustKey);
SSLContext context = SSLContext.getInstance(sslAlgorithm);//"SSL" "TLS"
context.init(null, tmf.getTrustManagers(), null);
return context.getServerSocketFactory();
}
catch(Exception e)
{
Assistance.log("Err: getSSLSocketFactory(), ");
}
return null;
}
public static SSLServerSocket getSSLServerSocket(SSLServerSocketFactory socketFactory, int port)
{
try
{
return (SSLServerSocket) socketFactory.createServerSocket(port);
}
catch(Exception e)
{Assistance.log("Err: getSSLSocket(), ");}
return null;
}
public static KeyStore getFromPath(String path, String algorithm, String filePassword)//PKSC12
{
try
{
File f = new File(path);
if(!f.exists())
throw new RuntimeException("Err: File not found.");
FileInputStream keyFile = new FileInputStream(f);
KeyStore keystore = KeyStore.getInstance(algorithm);
keystore.load(keyFile, filePassword.toCharArray());
keyFile.close();
return keystore;
}
catch(Exception e)
{
Assistance.log("Err: getFromPath(), " + e.toString());
}
return null;
}
基本上
KeyStore key = KeyMaster.getFromPath(".\\cssl.pfx", "PKCS12", "123");
SSLServerSocketFactory fac = KeyMaster.getSSLServerSocketFactory(key, "TLS");
listener = KeyMaster.getSSLServerSocket(fac, 49015);
这个问题主要是关于设置证书的问题。你的标题没有突出这一点(到目前为止,有一个答案似乎没有抓住这一点),所以我冒昧地修改了它。如果你愿意的话,请进一步改进标题。我认为你迄今为止提出的代码(a)非常可怕,(b)尽管如此,很可能是实现这一点的“正确”方式。Java并不总是过于冗长,但是当它是的时候,它确实是非常非常冗长的。如果你认为这很复杂,试着用NIO来做。但是我使用默认值来完成所有这些。应该有更直接的方法。@Philipp没有默认的密钥库。不建议这样做。任何事情都不要依赖于系统属性:/n您可能无法创建每个证书都不同的并发套接字。我亲自跟随