Korzystam z Jetty z HTTPS i ważnego certyfikatu i nie jestem pewien, czy jest to poprawne, ponieważ zestaw szyfrów wydaje się być SSL_NULL_WITH_NULL_NULL
w logach serwera. Jednak logi klientów wyglądają dobrze.SSL_NULL_WITH_NULL_NULL zestaw algorytmów szyfrowania w dziennikach Jetty
Długa historia: dołączam próbkę Java oczekującą Jetty-7.6.10 i dwa skrypty do tworzenia magazynu kluczy i magazynu zaufanych certyfikatów.
JettyHttpsForStackOverflow
uruchamia klienta i serwer, razem lub oddzielnie, aby anulować dowiązanie dzienników.
Skrypt create-chains.sh
tworzy magazyn kluczy i magazyn zaufanych certyfikatów. Magazyn kluczy zawiera łańcuch kończący się głównym urzędem certyfikacji wygenerowanym z tymczasowego magazynu kluczy. Replikuje on rzeczywistą sprawę z urzędem certyfikacji i certyfikatami pośrednimi.
Skrypt create-single-autosigned.sh
tworzy również magazyn kluczy i magazyn zaufanych certyfikatów, ale z samopodpisanym certyfikatem.
Należy pamiętać, że SSL_NULL_WITH_NULL_NULL
pojawia się jako zestaw szyfrów serwera dla obu łańcuchów certyfikatów.
Myślę, że nie ma problemu z nazwą domeny serwera. Ten sam problem występuje w przypadku serwera działającego na komputerze z nazwą domeny pasującą do nazwy wyróżniającej w prawidłowo podpisanym certyfikacie. SSLLab potwierdził, że SSL na moim serwerze działa dobrze (klasa B), a Google Chrome łączy się szczęśliwie.
Myślę, że nie ma problemu z klientem Jetty. Kiedy go używam, po prostu dzwoni SSLContextFactory
konfiguruję, aby utworzyć SSLSocket
. O dziwo, w dziennikach klienta Jetty wygląda na to, że używany pakiet algorytmu to TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
.
Czy to normalne, aby uzyskać SSL_NULL_WITH_NULL_NULL
w dziennikach serwera Jetty? Jeśli nie, jak to naprawić?
create-single-autosigned.sh
#!/bin/bash
rm their-keystore.jks 2> /dev/null
rm my-keystore.jks 2> /dev/null
rm my-truststore.jks 2> /dev/null
echo "===================================================="
echo "Creating fake third-party chain ca2 -> ca1 -> ca ..."
echo "===================================================="
keytool -genkeypair -alias ca -dname cn=ca \
-validity 10000 -keyalg RSA -keysize 2048 \
-ext BasicConstraints:critical=ca:true,pathlen:10000 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -genkeypair -alias ca1 -dname cn=ca1 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -genkeypair -alias ca2 -dname cn=ca2 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -certreq -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca \
-ext KeyUsage:critical=keyCertSign \
-ext SubjectAlternativeName=dns:ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
#echo "Debug exit" ; exit 0
keytool -certreq -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca1 \
-ext KeyUsage:critical=keyCertSign \
-ext SubjectAlternativeName=dns:ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore their-keystore.jks
echo "===================================================================="
echo "Fake third-party chain generated. Now generating my-keystore.jks ..."
echo "===================================================================="
read -p "Press a key to continue."
# Import authority's certificate chain
keytool -exportcert -alias ca \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -trustcacerts -noprompt -alias ca \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca1 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca2 \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca2 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
# Create our own certificate, the authority signs it.
keytool -genkeypair -alias e1 -dname cn=e1 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -certreq -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -gencert -alias ca2 \
-ext SubjectAlternativeName=dns:localhost,ip:127.0.0.1 \
-ext KeyUsage:critical=keyEncipherment,digitalSignature \
-ext ExtendedKeyUsage=serverAuth,clientAuth \
-keystore their-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-keystore.jks
echo "================================================="
echo "Keystore generated. Now generating truststore ..."
echo "================================================="
read -p "Press a key to continue."
keytool -exportcert -alias ca \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -trustcacerts -noprompt -alias ca \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca1 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias ca2 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias ca2 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -exportcert -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias e1 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-truststore.jks
rm their-keystore.jks 2> /dev/null
create-single-autosigned.sh
#!/bin/bash
rm my-keystore.jks 2> /dev/null
rm my-truststore.jks 2> /dev/null
keytool -genkeypair -alias e1 -dname cn=e1 \
-validity 10000 -keyalg RSA -keysize 2048 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-keystore.jks
echo "================================================="
echo "Keystore generated. Now generating truststore ..."
echo "================================================="
read -p "Press a key to continue."
keytool -exportcert -alias e1 \
-keystore my-keystore.jks -keypass Keypass -storepass Storepass \
| keytool -importcert -noprompt -alias e1 \
-keystore my-truststore.jks -keypass Keypass -storepass Storepass
keytool -list -v -storepass Storepass -keystore my-truststore.jks
JettyHttpsForStackOverflow.java
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
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.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import org.eclipse.jetty.client.ContentExchange;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
/**
* Code sample for Jetty {@link HttpClient} with HTTPS, in a completely standalone fashion.
* Use create-chains.sh and create-empty.sh to generate completely standalone certificates.
*/
public class JettyHttpsForStackOverflow {
public static void main(final String... arguments) throws Exception {
System.setProperty("javax.net.debug", "all") ;
try {
if(arguments.length == 0 || "server".equals(arguments[ 0 ])) {
runServer() ;
}
if(arguments.length == 0 || "client".equals(arguments[ 0 ])) {
runClient() ;
}
} catch(Exception e) {
e.printStackTrace() ;
System.exit(1) ; // Avoids keeping the port open.
}
}
private static void runServer() throws Exception {
final KeyStore keyStore = loadKeystore() ;
final SSLContext sslContext = createSslContext(
keyStore,
KEYPASS,
newTrustManagers(keyStore, CERTIFICATE_ALIAS)
) ;
final SslContextFactory sslContextFactory = new SslContextFactory() {
@Override
public SSLEngine newSslEngine() {
return sslContext.createSSLEngine() ;
}
@Override
public SSLEngine newSslEngine(final String host, final int port) {
return sslContext.createSSLEngine(host, port) ;
}
} ;
sslContextFactory.setAllowRenegotiate(true) ;
sslContextFactory.setNeedClientAuth(false) ;
sslContextFactory.setWantClientAuth(false) ;
sslContextFactory.setKeyStorePath(keyStore.toString()) ; // Better logging.
sslContextFactory.setKeyStore(keyStore) ;
sslContextFactory.setCertAlias(CERTIFICATE_ALIAS) ;
sslContextFactory.setKeyManagerPassword(KEYPASS) ;
final SslSelectChannelConnector sslConnector =
new SslSelectChannelConnector(sslContextFactory) ;
sslConnector.setPort(PORT) ;
sslConnector.open() ;
final Server jettyServer = new Server() ;
jettyServer.addConnector(sslConnector) ;
jettyServer.start() ;
}
public static void runClient() throws Exception {
final KeyStore keyStore = loadTruststore() ;
final HttpClient httpClient = new HttpClient() ;
httpClient.getSslContextFactory().setKeyStore(keyStore) ; // Better logging.
httpClient.getSslContextFactory().setKeyStorePassword("storepwd") ;
httpClient.getSslContextFactory().setKeyManagerPassword(KEYPASS) ;
httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL) ;
httpClient.setConnectorType(HttpClient.CONNECTOR_SOCKET);
// Don't need that because shipping our own certificate in the truststore.
// Anyways, it blows when set to true.
// httpClient.getSslContextFactory().setValidateCerts(false) ;
httpClient.start() ;
final ContentExchange contentExchange = new ContentExchange() ;
contentExchange.setURI(new URL("https://localhost:" + PORT).toURI()) ;
contentExchange.setTimeout(36_000_000) ; // Leave time for debugging.
httpClient.send(contentExchange) ;
contentExchange.waitForDone() ;
assert(contentExchange.getStatus() == ContentExchange.STATUS_COMPLETED) ;
}
private static SSLContext createSslContext(
final KeyStore keyStore,
final String keypass,
final TrustManager[] trustManagers
) {
try {
final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509") ;
keyManagerFactory.init(keyStore, keypass == null ? null : keypass.toCharArray()) ;
final KeyManager[] keyManagers = keyManagerFactory.getKeyManagers() ;
final SecureRandom secureRandom = new SecureRandom() ;
final SSLContext sslContext = SSLContext.getInstance("TLS") ;
sslContext.init(
keyManagers,
trustManagers,
secureRandom
) ;
return sslContext ;
} catch(NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException
| KeyManagementException e
) {
throw new RuntimeException(e) ;
}
}
private static TrustManager[] newTrustManagers(
final KeyStore keyStore,
final String certificateAlias
) {
try {
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("SunX509") ;
trustManagerFactory.init(keyStore) ;
final TrustManager[] trustManagers ;
if(certificateAlias == null) {
trustManagers = trustManagerFactory.getTrustManagers() ;
} else {
final Certificate certificate = keyStore.getCertificate(certificateAlias) ;
final X509Certificate[] x509Certificates ;
if(certificate == null) {
x509Certificates = new X509Certificate[ 0 ] ;
} else {
x509Certificates = new X509Certificate[] { (X509Certificate) certificate } ;
}
trustManagers = new TrustManager[] { newX509TrustManager(x509Certificates) } ;
}
return trustManagers ;
} catch(KeyStoreException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static final TrustManager newX509TrustManager(final X509Certificate[] certificates) {
return new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return certificates ;
}
public void checkClientTrusted(
final X509Certificate[] certs,
final String authType
) { ; }
public void checkServerTrusted(
final X509Certificate[] certs,
final String authType
) { ; }
} ;
}
public static KeyStore loadKeystore()
throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException
{
return loadKeystore(KEYSTORE_RESOURCE_URL) ;
}
public static KeyStore loadTruststore()
throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException
{
return loadKeystore(TRUSTSTORE_RESOURCE_URL) ;
}
public static KeyStore loadKeystore(final URL keystoreResourceUrl)
throws IOException, KeyStoreException, CertificateException, NoSuchAlgorithmException
{
try(final InputStream inputStream = keystoreResourceUrl.openStream()) {
final KeyStore keyStore = KeyStore.getInstance("JKS") ;
// We don't need the storepass for just reading one password-protected certificate
// of our own, or a trusted entry.
keyStore.load(inputStream, null) ;
return keyStore ;
}
}
private static final int PORT = 8443 ;
private static final String CERTIFICATE_ALIAS = "e1";
private static final String KEYPASS = "Keypass";
private static final URL KEYSTORE_RESOURCE_URL
= JettyHttpsForStackOverflow.class.getResource("my-keystore.jks") ;
private static final URL TRUSTSTORE_RESOURCE_URL
= JettyHttpsForStackOverflow.class.getResource("my-truststore.jks") ;
}
Dobra praca dochodzeniowa. Głupi błąd. – EJP
Otrzymuję to samo z Jetty 9.3.6 ..... – user2818782