Instantly share code, notes, and snippets.
Created
March 11, 2019 02:19
-
Save swankjesse/589e3e1c4a566e4a9aaec66f0f3a6223 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.ByteArrayInputStream; | |
import java.io.IOException; | |
import java.net.InetSocketAddress; | |
import java.net.ServerSocket; | |
import java.net.Socket; | |
import java.nio.charset.StandardCharsets; | |
import java.security.KeyFactory; | |
import java.security.KeyStore; | |
import java.security.PrivateKey; | |
import java.security.cert.Certificate; | |
import java.security.cert.CertificateException; | |
import java.security.cert.CertificateFactory; | |
import java.security.cert.X509Certificate; | |
import java.security.spec.PKCS8EncodedKeySpec; | |
import java.util.Base64; | |
import java.util.Collection; | |
import javax.net.SocketFactory; | |
import javax.net.ssl.KeyManager; | |
import javax.net.ssl.KeyManagerFactory; | |
import javax.net.ssl.SSLContext; | |
import javax.net.ssl.SSLSession; | |
import javax.net.ssl.SSLSocket; | |
import javax.net.ssl.SSLSocketFactory; | |
import javax.net.ssl.TrustManager; | |
import javax.net.ssl.TrustManagerFactory; | |
import javax.net.ssl.X509KeyManager; | |
import javax.net.ssl.X509TrustManager; | |
/** | |
* This test demonstrates that {@link SSLSession#getPeerCertificates} throws on Java 11 when a | |
* handshake was negotiated with the pre_shared_key extension. | |
* | |
* <p>This test completes normally on Java 8 but crashes on Java 11. | |
*/ | |
public final class PreSharedKeyTest { | |
private char[] password = "password".toCharArray(); // Any password will work. | |
public static void main(String[] args) throws Exception { | |
PreSharedKeyTest preSharedKeyTest = new PreSharedKeyTest(); | |
int port = preSharedKeyTest.runServer(); | |
preSharedKeyTest.runClient(port); | |
} | |
int runServer() throws Exception { | |
SSLSocketFactory sslSocketFactory = newSslSocketFactory(true); | |
ServerSocket serverSocket = new ServerSocket(); | |
serverSocket.setReuseAddress(true); | |
serverSocket.bind(new InetSocketAddress("localhost", 0), 50); | |
new Thread("server") { | |
@Override public void run() { | |
try { | |
for (int i = 0; i < 2; i++) { | |
serverHandshake(sslSocketFactory, serverSocket); | |
} | |
serverSocket.close(); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
} | |
}.start(); | |
return serverSocket.getLocalPort(); | |
} | |
void serverHandshake( | |
SSLSocketFactory sslSocketFactory, ServerSocket serverSocket) throws Exception { | |
try (Socket rawSocket = serverSocket.accept(); | |
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket( | |
rawSocket, null, true)) { | |
sslSocket.setUseClientMode(false); | |
sslSocket.startHandshake(); | |
} | |
} | |
void runClient(int port) throws Exception { | |
SSLSocketFactory sslSocketFactory = newSslSocketFactory(false); | |
clientHandshake(sslSocketFactory, "localhost", port); | |
clientHandshake(sslSocketFactory, "localhost", port); | |
} | |
void clientHandshake(SSLSocketFactory sslSocketFactory, String host, int port) throws Exception { | |
try (Socket rawSocket = SocketFactory.getDefault().createSocket(host, port); | |
SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket( | |
rawSocket, host, port, true)) { | |
if (false) { | |
// Workaround by removing the `if (false)` here. | |
sslSocket.setEnabledProtocols(new String[] { "TLSv1.2" }); | |
} | |
sslSocket.startHandshake(); | |
SSLSession session = sslSocket.getSession(); | |
sslSocket.getInputStream().read(); | |
Certificate[] peerCertificates = session.getPeerCertificates(); // Crash here on Java 11. | |
System.out.println("handshake success: peer=" | |
+ ((X509Certificate) peerCertificates[0]).getSubjectX500Principal().getName()); | |
} | |
} | |
SSLSocketFactory newSslSocketFactory(boolean server) throws Exception { | |
Certificate certificate = decodePem("" | |
+ "-----BEGIN CERTIFICATE-----\n" | |
+ "MIIBMjCB2qADAgECAgEBMAoGCCqGSM49BAMCMBQxEjAQBgNVBAMTCWxvY2FsaG9z\n" | |
+ "dDAgFw0xOTAzMTEwMDU3MzVaGA8yMTE5MDIxNTAwNTczNVowFDESMBAGA1UEAxMJ\n" | |
+ "bG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEFmkkkDjWmtErc3NI\n" | |
+ "7WnUXDHz8TuBPHVyk1OPEexcQhIFaabFCqO6CLwwiEm3Nmcbkw2c1Y0MKQXSLyPd\n" | |
+ "uBF4EaMbMBkwFwYDVR0RAQH/BA0wC4IJbG9jYWxob3N0MAoGCCqGSM49BAMCA0cA\n" | |
+ "MEQCIC/3TRDB7PUtDo685hjNhWMrOZADvl8ZXFxTLBWoeRmwAiBVkoKiATUShtqo\n" | |
+ "aMx+zeozvmB//hu5LL2Ll/WbbWSWVQ==\n" | |
+ "-----END CERTIFICATE-----"); | |
X509TrustManager trustManager = newTrustManager(certificate); | |
KeyManager[] keyManagers = null; | |
if (server) { | |
PrivateKey privateKey = decodePkcs8("MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJz" | |
+ "AlAgEBBCBOV/y8HlypWRB6axJz9uoevM+Oe/8IzTBW/OzCPNy04A=="); | |
keyManagers = new KeyManager[] { newKeyManager(certificate, privateKey) }; | |
} | |
SSLContext sslContext = SSLContext.getInstance("TLS"); | |
sslContext.init(keyManagers, new TrustManager[] {trustManager}, null); | |
return sslContext.getSocketFactory(); | |
} | |
Certificate decodePem(String pem) throws CertificateException { | |
Collection<? extends Certificate> certificates = CertificateFactory.getInstance("X.509") | |
.generateCertificates(new ByteArrayInputStream(pem.getBytes(StandardCharsets.US_ASCII))); | |
return certificates.iterator().next(); | |
} | |
PrivateKey decodePkcs8(String base64pkcs8) throws Exception { | |
byte[] privateKeyBytes = Base64.getDecoder().decode(base64pkcs8); | |
return KeyFactory.getInstance("EC").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); | |
} | |
X509KeyManager newKeyManager(Certificate certificate, PrivateKey privateKey) throws Exception { | |
KeyStore keyStore = newEmptyKeyStore(); | |
keyStore.setKeyEntry("private", privateKey, password, new Certificate[] {certificate}); | |
KeyManagerFactory factory = KeyManagerFactory.getInstance( | |
KeyManagerFactory.getDefaultAlgorithm()); | |
factory.init(keyStore, password); | |
return (X509KeyManager) factory.getKeyManagers()[0]; | |
} | |
X509TrustManager newTrustManager(Certificate certificate) throws Exception { | |
KeyStore keyStore = newEmptyKeyStore(); | |
keyStore.setCertificateEntry("localhost", certificate); | |
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( | |
KeyManagerFactory.getDefaultAlgorithm()); | |
keyManagerFactory.init(keyStore, password); | |
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( | |
TrustManagerFactory.getDefaultAlgorithm()); | |
trustManagerFactory.init(keyStore); | |
return (X509TrustManager) trustManagerFactory.getTrustManagers()[0]; | |
} | |
KeyStore newEmptyKeyStore() throws Exception { | |
try { | |
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); | |
keyStore.load(null, password); | |
return keyStore; | |
} catch (IOException e) { | |
throw new AssertionError(e); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment