From ff017bf2ac6c1981d0f594f4aa4cd27ffe123c9a Mon Sep 17 00:00:00 2001 From: Laszlo Bodor Date: Sun, 24 Oct 2021 23:59:00 +0200 Subject: [PATCH 1/2] TEZ-4342: TestSecureShuffle is broken --- .../apache/tez/test/TestSecureShuffle.java | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java b/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java index aed240997e..997880a00f 100644 --- a/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java +++ b/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java @@ -25,14 +25,19 @@ import java.io.File; import java.io.IOException; import java.io.OutputStreamWriter; +import java.math.BigInteger; import java.net.InetAddress; import java.security.KeyPair; +import java.security.SecureRandom; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; +import java.util.Date; import java.util.HashMap; import java.util.Map; +import javax.security.auth.x500.X500Principal; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FSDataOutputStream; import org.apache.hadoop.fs.FileSystem; @@ -46,6 +51,10 @@ import org.apache.tez.dag.api.TezConfiguration; import org.apache.tez.mapreduce.examples.TestOrderedWordCount; import org.apache.tez.runtime.library.api.TezRuntimeConfiguration; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.asn1.x509.X509Extensions; +import org.bouncycastle.x509.X509V3CertificateGenerator; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -222,7 +231,7 @@ private static void setupKeyStores() throws Exception { * (as discussed in https://github.com/AsyncHttpClient/async-http-client/issues/928), that's why * it cannot be set for an async http connection. So instead of hacking an ALLOW_ALL verifier * somehow (which cannot be propagated to netty), a valid certificate with the actual hostname - * should be generated in setupSSLConfig, so the only change is the usage of + * should be generated in setupSSLConfig, so the change is the usage of * "InetAddress.getLocalHost().getHostName()". */ public static void setupSSLConfig(String keystoresDir, String sslConfDir, Configuration config, @@ -242,7 +251,7 @@ public static void setupSSLConfig(String keystoresDir, String sslConfDir, Config if (useClientCert) { KeyPair cKP = KeyStoreTestUtil.generateKeyPair("RSA"); X509Certificate cCert = - KeyStoreTestUtil.generateCertificate("CN=localhost, O=client", cKP, 30, "SHA1withRSA"); + generateCertificate("CN=localhost, O=client", cKP, 30, "SHA1withRSA"); KeyStoreTestUtil.createKeyStore(clientKS, clientPassword, "client", cKP.getPrivate(), cCert); certs.put("client", cCert); } @@ -250,7 +259,7 @@ public static void setupSSLConfig(String keystoresDir, String sslConfDir, Config String localhostName = InetAddress.getLocalHost().getHostName(); KeyPair sKP = KeyStoreTestUtil.generateKeyPair("RSA"); X509Certificate sCert = - KeyStoreTestUtil.generateCertificate("CN="+localhostName+", O=server", sKP, 30, "SHA1withRSA"); + generateCertificate("CN="+localhostName+", O=server", sKP, 30, "SHA1withRSA"); KeyStoreTestUtil.createKeyStore(serverKS, serverPassword, "server", sKP.getPrivate(), sCert); certs.put("server", sCert); @@ -274,4 +283,31 @@ public static void setupSSLConfig(String keystoresDir, String sslConfDir, Config config.set(SSLFactory.SSL_SERVER_CONF_KEY, sslServerConfFile.getName()); config.setBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY, useClientCert); } + + public static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm) + throws Exception { + + Date from = new Date(); + Date to = new Date(from.getTime() + days * 86400000l); + BigInteger sn = new BigInteger(64, new SecureRandom()); + KeyPair keyPair = pair; + X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + + String hostAddress = InetAddress.getLocalHost().getHostAddress(); + certGen.addExtension(X509Extensions.SubjectAlternativeName, false, + new GeneralNames(new GeneralName(GeneralName.iPAddress, hostAddress))); + + X500Principal dnName = new X500Principal(dn); + + certGen.setSerialNumber(sn); + certGen.setIssuerDN(dnName); + certGen.setNotBefore(from); + certGen.setNotAfter(to); + certGen.setSubjectDN(dnName); + certGen.setPublicKey(keyPair.getPublic()); + certGen.setSignatureAlgorithm(algorithm); + + X509Certificate cert = certGen.generate(pair.getPrivate()); + return cert; + } } From 0198510039f17edb938728a4b0f1ecd5ae96d175 Mon Sep 17 00:00:00 2001 From: Laszlo Bodor Date: Mon, 25 Oct 2021 07:35:52 +0200 Subject: [PATCH 2/2] comment + checkstyle --- .../java/org/apache/tez/test/TestSecureShuffle.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java b/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java index 997880a00f..2b2221230f 100644 --- a/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java +++ b/tez-tests/src/test/java/org/apache/tez/test/TestSecureShuffle.java @@ -231,8 +231,9 @@ private static void setupKeyStores() throws Exception { * (as discussed in https://github.com/AsyncHttpClient/async-http-client/issues/928), that's why * it cannot be set for an async http connection. So instead of hacking an ALLOW_ALL verifier * somehow (which cannot be propagated to netty), a valid certificate with the actual hostname - * should be generated in setupSSLConfig, so the change is the usage of - * "InetAddress.getLocalHost().getHostName()". + * should be generated in setupSSLConfig. So, one change is the usage of + * InetAddress.getLocalHost().getHostName(), the other is using local generateCertificate, + * which fixes another issue. */ public static void setupSSLConfig(String keystoresDir, String sslConfDir, Configuration config, boolean useClientCert, boolean trustStore, String excludeCiphers) throws Exception { @@ -284,11 +285,16 @@ public static void setupSSLConfig(String keystoresDir, String sslConfDir, Config config.setBoolean(SSLFactory.SSL_REQUIRE_CLIENT_CERT_KEY, useClientCert); } + /** + * This is a copied version of hadoop's KeyStoreTestUtil.generateCertificate, which takes care of setting + * IP address as a SSL Subject Alternative Name (SAN). Without this, SSL shuffle failed with async http client. + * Introduced by TEZ-4342. + */ public static X509Certificate generateCertificate(String dn, KeyPair pair, int days, String algorithm) throws Exception { Date from = new Date(); - Date to = new Date(from.getTime() + days * 86400000l); + Date to = new Date(from.getTime() + days * 86400000L); BigInteger sn = new BigInteger(64, new SecureRandom()); KeyPair keyPair = pair; X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();