ACME client will now reuse existing certificate instead of requesting new one every time.
This commit is contained in:
parent
3552c21404
commit
3afb1e241e
5 changed files with 227 additions and 146 deletions
|
|
@ -3,6 +3,7 @@ package zutil.net.acme;
|
|||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.Security;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
|
@ -114,60 +115,68 @@ public class AcmeClient {
|
|||
if (order == null)
|
||||
throw new IllegalStateException("prepareRequest() method has not been called before the request of certificate.");
|
||||
|
||||
// Perform all required domain authorizations
|
||||
for (Challenge challenge : challenges) {
|
||||
execDomainChallenge(challenge);
|
||||
}
|
||||
X509Certificate certificate = dataStore.getCertificate();
|
||||
|
||||
// Load or create a key pair for the domains. This should not be same as the userKeyPair!
|
||||
KeyPair domainKeyPair = dataStore.getDomainKeyPair();
|
||||
|
||||
if (domainKeyPair == null) {
|
||||
logger.fine("Creating new domain keys.");
|
||||
domainKeyPair = KeyPairUtils.createKeyPair(KEY_SIZE);
|
||||
dataStore.storeDomainKeyPair(domainKeyPair);
|
||||
}
|
||||
|
||||
// Generate one "Certificate Signing Request" for all the domains, and sign it with the domain key pair.
|
||||
CSRBuilder csrBuilder = new CSRBuilder();
|
||||
csrBuilder.addDomains(domains);
|
||||
csrBuilder.sign(domainKeyPair);
|
||||
|
||||
order.execute(csrBuilder.getEncoded()); // Order the certificate
|
||||
|
||||
// Wait for the order to complete
|
||||
try {
|
||||
for (int attempts = 0; attempts < 10; attempts++) {
|
||||
// Did the order pass or fail?
|
||||
if (order.getStatus() == Status.VALID) {
|
||||
break;
|
||||
} else if (order.getStatus() == Status.INVALID) {
|
||||
throw new AcmeException("Certificate order has failed, reason: " + order.getError());
|
||||
}
|
||||
|
||||
// Wait for a few seconds
|
||||
long sleep = 100L + 1000L * attempts;
|
||||
logger.fine("Challenge not yet completed, sleeping for: " + StringUtil.formatTimeToString(sleep));
|
||||
Thread.sleep(sleep);
|
||||
|
||||
// Then update the status
|
||||
order.update();
|
||||
// TODO: Check if certificate is valid for the given domains
|
||||
if (!isCertificateValid(certificate)) {
|
||||
// Perform all required domain authorizations
|
||||
for (Challenge challenge : challenges) {
|
||||
execDomainChallenge(challenge);
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Interrupted", ex);
|
||||
|
||||
// Load or create a key pair for the domains. This should not be same as the userKeyPair!
|
||||
KeyPair domainKeyPair = dataStore.getDomainKeyPair();
|
||||
|
||||
if (domainKeyPair == null) {
|
||||
logger.fine("Creating new domain keys.");
|
||||
domainKeyPair = KeyPairUtils.createKeyPair(KEY_SIZE);
|
||||
dataStore.storeDomainKeyPair(domainKeyPair);
|
||||
}
|
||||
|
||||
// Generate one "Certificate Signing Request" for all the domains, and sign it with the domain key pair.
|
||||
CSRBuilder csrBuilder = new CSRBuilder();
|
||||
csrBuilder.addDomains(domains);
|
||||
csrBuilder.sign(domainKeyPair);
|
||||
|
||||
order.execute(csrBuilder.getEncoded()); // Order the certificate
|
||||
|
||||
// Wait for the order to complete
|
||||
try {
|
||||
for (int attempts = 0; attempts < 10; attempts++) {
|
||||
// Did the order pass or fail?
|
||||
if (order.getStatus() == Status.VALID) {
|
||||
break;
|
||||
} else if (order.getStatus() == Status.INVALID) {
|
||||
throw new AcmeException("Certificate order has failed, reason: " + order.getError());
|
||||
}
|
||||
|
||||
// Wait for a few seconds
|
||||
long sleep = 100L + 1000L * attempts;
|
||||
logger.fine("Challenge not yet completed, sleeping for: " + StringUtil.formatTimeToString(sleep));
|
||||
Thread.sleep(sleep);
|
||||
|
||||
// Then update the status
|
||||
order.update();
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
logger.log(Level.SEVERE, "Interrupted", ex);
|
||||
}
|
||||
|
||||
// Get the certificate
|
||||
certificate = order.getCertificate().getCertificate();
|
||||
dataStore.storeCertificate(certificate);
|
||||
|
||||
logger.info("Successfully created new certificate for domains: " + StringUtil.join(",", domains));
|
||||
} else {
|
||||
logger.info("Using existing certificate for domains: " + StringUtil.join(",", domains));
|
||||
}
|
||||
|
||||
// Get the certificate
|
||||
Certificate certificate = order.getCertificate();
|
||||
|
||||
logger.info("The certificate for domains '" + StringUtil.join(",", domains) + "' has been successfully generated.");
|
||||
|
||||
// Cleanup
|
||||
|
||||
order = null;
|
||||
challenges.clear();
|
||||
|
||||
return certificate.getCertificate();
|
||||
return certificate;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -262,4 +271,23 @@ public class AcmeClient {
|
|||
|
||||
logger.fine("Domain challenge executed successfully.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A helper method to check if a certificate is still valid.
|
||||
*
|
||||
* @param certificate the certificate to validate.
|
||||
* @return true if the certificate is still valid otherwise false
|
||||
*/
|
||||
public static boolean isCertificateValid(X509Certificate certificate) {
|
||||
if (certificate == null)
|
||||
return false;
|
||||
|
||||
try {
|
||||
certificate.checkValidity();
|
||||
return true;
|
||||
} catch (GeneralSecurityException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,42 +2,59 @@ package zutil.net.acme;
|
|||
|
||||
import java.net.URL;
|
||||
import java.security.KeyPair;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public interface AcmeDataStore {
|
||||
|
||||
/**
|
||||
* Loads an accounts key pair.
|
||||
*
|
||||
* @return a KeyPair for the account, null if no KeyPair is found.
|
||||
*/
|
||||
URL getAccountLocation();
|
||||
/**
|
||||
* Read in an account location URL.
|
||||
*
|
||||
* @return a URL to the account, this is used as an identifier.
|
||||
*/
|
||||
URL getAccountLocation();
|
||||
|
||||
/**
|
||||
* Retrieve an account key pair.
|
||||
*
|
||||
* @return a KeyPair object for the account, null if no KeyPair is found.
|
||||
*/
|
||||
KeyPair getAccountKeyPair();
|
||||
/**
|
||||
* Retrieve an account key pair.
|
||||
*
|
||||
* @return a KeyPair object for the account, null if no KeyPair is found.
|
||||
*/
|
||||
KeyPair getAccountKeyPair();
|
||||
|
||||
/**
|
||||
* Stores an accounts key pair for later usage.
|
||||
*
|
||||
* @param accountLocation the URL to the account profile, this is used as an identifier to the ACME service.
|
||||
* @param accountKeyPair the keys for the user account
|
||||
*/
|
||||
void storeAccountKeyPair(URL accountLocation, KeyPair accountKeyPair);
|
||||
/**
|
||||
* Store an accounts key pair for later usage.
|
||||
*
|
||||
* @param accountLocation the URL to the account profile, this is used as an identifier to the ACME service.
|
||||
* @param accountKeyPair the keys for the user account
|
||||
*/
|
||||
void storeAccountKeyPair(URL accountLocation, KeyPair accountKeyPair);
|
||||
|
||||
/**
|
||||
* Loads a domain key pair.
|
||||
*
|
||||
* @return a KeyPair object for the domains, null if no KeyPar was found.
|
||||
*/
|
||||
KeyPair getDomainKeyPair();
|
||||
|
||||
/**
|
||||
* Stores a domain key pair for later usage.
|
||||
*
|
||||
* @param keyPair the keys for the domain
|
||||
*/
|
||||
void storeDomainKeyPair(KeyPair keyPair);
|
||||
}
|
||||
/**
|
||||
* Read in a domain key pair.
|
||||
*
|
||||
* @return a KeyPair object for the domains, null if no KeyPar was found.
|
||||
*/
|
||||
KeyPair getDomainKeyPair();
|
||||
|
||||
/**
|
||||
* Store a domain key pair for later usage.
|
||||
*
|
||||
* @param keyPair the keys for the domain
|
||||
*/
|
||||
void storeDomainKeyPair(KeyPair keyPair);
|
||||
|
||||
|
||||
/**
|
||||
* Loads a certificate
|
||||
*
|
||||
* @return a certificate that has previously been generated, null if no certificate is available.
|
||||
*/
|
||||
X509Certificate getCertificate();
|
||||
|
||||
/**
|
||||
* Store a domain key pair for later usage.
|
||||
*
|
||||
* @param certificate the certificate to be stored
|
||||
*/
|
||||
void storeCertificate(X509Certificate certificate);
|
||||
}
|
||||
|
|
@ -1,17 +1,23 @@
|
|||
package zutil.net.acme;
|
||||
|
||||
import org.shredzone.acme4j.toolbox.AcmeUtils;
|
||||
import org.shredzone.acme4j.util.KeyPairUtils;
|
||||
import zutil.io.file.FileUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.security.KeyPair;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
public class AcmeFileDataStore implements AcmeDataStore {
|
||||
|
||||
private final File accountLocationFile;
|
||||
private final File accountKeyFile;
|
||||
private final File domainKeyFile;
|
||||
private final File certificateFile;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -23,6 +29,7 @@ public class AcmeFileDataStore implements AcmeDataStore {
|
|||
this.accountLocationFile = new File(folder, "accountLocation.cfg");
|
||||
this.accountKeyFile = new File(folder, "account.key");
|
||||
this.domainKeyFile = new File(folder, "domain.key");
|
||||
this.certificateFile = new File(folder, "certificate.pem");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -77,4 +84,27 @@ public class AcmeFileDataStore implements AcmeDataStore {
|
|||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public X509Certificate getCertificate() {
|
||||
if (certificateFile.exists()) {
|
||||
try (FileInputStream in = new FileInputStream(certificateFile)) {
|
||||
CertificateFactory factory = CertificateFactory.getInstance("X.509");
|
||||
return (X509Certificate) factory.generateCertificate(in);
|
||||
} catch (IOException | CertificateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void storeCertificate(X509Certificate certificate) {
|
||||
try(FileWriter out = new FileWriter(certificateFile)) {
|
||||
AcmeUtils.writeToPem(certificate.getEncoded(), AcmeUtils.PemLabel.CERTIFICATE, out);
|
||||
} catch (IOException | CertificateEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ import java.io.BufferedInputStream;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
|
|
@ -60,7 +61,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{
|
|||
public static final String SESSION_KEY_ID = "session_id";
|
||||
public static final String SESSION_KEY_TTL = "session_ttl";
|
||||
public static final String SERVER_NAME = "Zutil HttpServer";
|
||||
public static final int SESSION_TTL = 10*60*1000; // in milliseconds
|
||||
public static final int SESSION_TTL = 10*60*1000; // in milliseconds
|
||||
|
||||
|
||||
private Map<String,HttpPage> pages = new ConcurrentHashMap<>();;
|
||||
|
|
@ -68,6 +69,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{
|
|||
private int nextSessionId = 0;
|
||||
private HttpPage defaultPage = null;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new instance of the sever
|
||||
*
|
||||
|
|
@ -75,9 +77,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{
|
|||
*/
|
||||
public HttpServer(int port) throws IOException {
|
||||
super(port);
|
||||
initGarbageCollector();
|
||||
|
||||
logger.info("HTTP Server ready and listening to port: " + port);
|
||||
initialize("HTTP");
|
||||
}
|
||||
/**
|
||||
* Creates a new instance of the sever which accepts SSL connections
|
||||
|
|
@ -85,32 +85,43 @@ public class HttpServer extends ThreadedTCPNetworkServer{
|
|||
* @param port The port that the server should listen to
|
||||
* @param certificate The certificate that should be used for the servers SSL connections
|
||||
*/
|
||||
public HttpServer(int port, Certificate certificate) throws IOException {
|
||||
public HttpServer(int port, Certificate certificate) throws IOException, GeneralSecurityException {
|
||||
super(port, certificate);
|
||||
initGarbageCollector();
|
||||
|
||||
logger.info("HTTPS Server ready and listening to port: " + port);
|
||||
initialize("HTTPS");
|
||||
}
|
||||
/**
|
||||
* Creates a new instance of the sever which accepts SSL connections
|
||||
*
|
||||
* @param port The port that the server should listen to
|
||||
* @param keyStore The keyStore containing the certificate to use for the servers SSL connections
|
||||
* @param keyStoreFile The keyStore file containing the certificate to use for the servers SSL connections
|
||||
* @param keyStorePass The password to unlock the key store.
|
||||
*/
|
||||
public HttpServer(int port, File keyStore, char[] keyStorePass) throws IOException {
|
||||
super(port, keyStore, keyStorePass);
|
||||
initGarbageCollector();
|
||||
|
||||
logger.info("HTTPS Server ready and listening to port: " + port);
|
||||
}
|
||||
|
||||
private void initGarbageCollector() {
|
||||
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
|
||||
exec.scheduleWithFixedDelay(new SessionGarbageCollector(), 10000, SESSION_TTL / 2, TimeUnit.MILLISECONDS);
|
||||
public HttpServer(int port, File keyStoreFile, char[] keyStorePass) throws IOException, GeneralSecurityException {
|
||||
super(port, keyStoreFile, keyStorePass);
|
||||
initialize("HTTPS");
|
||||
}
|
||||
/**
|
||||
* This class acts as an garbage collector that
|
||||
* Creates a new instance of the sever which accepts SSL connections
|
||||
*
|
||||
* @param port The port that the server should listen to
|
||||
* @param keyStore The keyStore object containing the certificate to use for the servers SSL connections
|
||||
* @param keyStorePass The password to unlock the key store.
|
||||
*/
|
||||
public HttpServer(int port, KeyStore keyStore, char[] keyStorePass) throws IOException, GeneralSecurityException {
|
||||
super(port, keyStore, keyStorePass);
|
||||
initialize("HTTPS");
|
||||
}
|
||||
|
||||
private void initialize(String httpType) {
|
||||
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
|
||||
exec.scheduleWithFixedDelay(new SessionGarbageCollector(), 10000, SESSION_TTL / 2, TimeUnit.MILLISECONDS);
|
||||
|
||||
logger.info(httpType + " Server ready and listening to port: " + httpType.toLowerCase() + "://localhost:" + getPort());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This class acts as a garbage collector that
|
||||
* removes old sessions from the session HashMap
|
||||
*/
|
||||
private class SessionGarbageCollector implements Runnable {
|
||||
|
|
@ -186,7 +197,7 @@ public class HttpServer extends ThreadedTCPNetworkServer{
|
|||
/**
|
||||
* Internal class that handles all the requests
|
||||
*/
|
||||
protected class HttpServerThread implements ThreadedTCPNetworkServerThread{
|
||||
protected class HttpServerThread implements ThreadedTCPNetworkServerThread {
|
||||
private HttpPrintStream out;
|
||||
private BufferedInputStream in;
|
||||
private Socket socket;
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ package zutil.net.threaded;
|
|||
|
||||
import zutil.log.LogUtil;
|
||||
|
||||
import javax.net.ServerSocketFactory;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
import javax.net.ssl.ManagerFactoryParameters;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import java.io.File;
|
||||
|
|
@ -37,7 +37,6 @@ import java.net.ServerSocket;
|
|||
import java.net.Socket;
|
||||
import java.security.*;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
|
|
@ -63,7 +62,16 @@ public abstract class ThreadedTCPNetworkServer extends Thread {
|
|||
*/
|
||||
public ThreadedTCPNetworkServer(int port) throws IOException {
|
||||
this.port = port;
|
||||
this.serverSocket = new ServerSocket(port);
|
||||
this.serverSocket = ServerSocketFactory.getDefault().createServerSocket(port);
|
||||
}
|
||||
/**
|
||||
* Creates a new SSL instance of the sever.
|
||||
*
|
||||
* @param port the port that the server should listen to.
|
||||
* @param certificate the certificate for the server domain.
|
||||
*/
|
||||
public ThreadedTCPNetworkServer(int port, Certificate certificate) throws IOException, GeneralSecurityException {
|
||||
this(port, getKeyStore(certificate), null);
|
||||
}
|
||||
/**
|
||||
* Creates a new SSL instance of the sever.
|
||||
|
|
@ -72,79 +80,66 @@ public abstract class ThreadedTCPNetworkServer extends Thread {
|
|||
* @param keyStoreFile the path to the key store file containing the server certificates
|
||||
* @param keyStorePass the password to decrypt the key store file.
|
||||
*/
|
||||
public ThreadedTCPNetworkServer(int port, File keyStoreFile, char[] keyStorePass) throws IOException {
|
||||
this.port = port;
|
||||
this.serverSocket = createSSLSocket(port, keyStoreFile, keyStorePass);
|
||||
public ThreadedTCPNetworkServer(int port, File keyStoreFile, char[] keyStorePass) throws IOException, GeneralSecurityException {
|
||||
this(port, getKeyStore(keyStoreFile, keyStorePass), keyStorePass);
|
||||
}
|
||||
/**
|
||||
* Creates a new SSL instance of the sever.
|
||||
*
|
||||
* @param port the port that the server should listen to.
|
||||
* @param certificate the certificate for the servers domain.
|
||||
* @param keyStore the KeyStore that contains the certificate to be used by the server
|
||||
* @param keyStorePass the password to decrypt the key store file, null if there is no password set
|
||||
*/
|
||||
public ThreadedTCPNetworkServer(int port, Certificate certificate) throws IOException {
|
||||
public ThreadedTCPNetworkServer(int port, KeyStore keyStore, char[] keyStorePass) throws IOException, GeneralSecurityException {
|
||||
this.port = port;
|
||||
this.serverSocket = createSSLSocket(port, certificate);
|
||||
this.serverSocket = getSSLServerSocketFactory(keyStore, keyStorePass).createServerSocket(port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a SSLServerSocket
|
||||
*
|
||||
* @param port the port the server should to
|
||||
* @param certificate the certificate for the server domain.
|
||||
* @return a SSLServerSocket object
|
||||
*/
|
||||
private static KeyStore getKeyStore(Certificate certificate) throws IOException, GeneralSecurityException {
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keyStore.load(null, null); // Create empty keystore
|
||||
keyStore.setCertificateEntry("ssl_server_cert", certificate);
|
||||
|
||||
return keyStore;
|
||||
}
|
||||
/**
|
||||
* Initiates a SSLServerSocket
|
||||
*
|
||||
* @param keyStoreFile the cert file location
|
||||
* @param keyStorePass the password for the cert file
|
||||
* @param keyStorePass the password for the cert file, null if there is no password set
|
||||
* @return a SSLServerSocket object
|
||||
*/
|
||||
private static ServerSocket createSSLSocket(int port, File keyStoreFile, char[] keyStorePass) throws IOException{
|
||||
try {
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keyStore.load(new FileInputStream(keyStoreFile), keyStorePass);
|
||||
private static KeyStore getKeyStore(File keyStoreFile, char[] keyStorePass) throws IOException, GeneralSecurityException {
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keyStore.load(new FileInputStream(keyStoreFile), keyStorePass);
|
||||
|
||||
return createSSLSocket(port, keyStore, keyStorePass);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new IOException("Unable to configure certificate.", e);
|
||||
}
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a SSLServerSocket
|
||||
* Creates a new SSLServerSocketFactory
|
||||
*
|
||||
* @param port the port the server should to.
|
||||
* @param certificate the certificate for the servers domain.
|
||||
* @return a SSLServerSocket object
|
||||
*/
|
||||
private static ServerSocket createSSLSocket(int port, Certificate certificate) throws IOException{
|
||||
try {
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keyStore.load(null); // Create empty keystore
|
||||
keyStore.setCertificateEntry("main_certificate", certificate);
|
||||
|
||||
return createSSLSocket(port, keyStore, null);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new IOException("Unable to configure certificate.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a SSLServerSocket
|
||||
*
|
||||
* @param port the port the server should to.
|
||||
* @param keyStore the key store containing the domain certificates
|
||||
* @param keyStorePass the password for the cert file
|
||||
* @return a SSLServerSocket object
|
||||
* @param keyStorePass the password for the cert file, null if there is no password set
|
||||
* @return a SSLServerSocketFactory object
|
||||
*/
|
||||
private static ServerSocket createSSLSocket(int port, KeyStore keyStore, char[] keyStorePass)
|
||||
throws IOException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeyManagementException {
|
||||
private static SSLServerSocketFactory getSSLServerSocketFactory(KeyStore keyStore, char[] keyStorePass)
|
||||
throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeyManagementException {
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
keyManagerFactory.init(keyStore, keyStorePass);
|
||||
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
ctx.init(keyManagerFactory.getKeyManagers(), null, SecureRandom.getInstanceStrong());
|
||||
SSLServerSocketFactory socketFactory = ctx.getServerSocketFactory();
|
||||
|
||||
return socketFactory.createServerSocket(port);
|
||||
return ctx.getServerSocketFactory();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the port that this TCP server is listening to.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue