[ https://issues.apache.org/jira/browse/ZOOKEEPER-236?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15958104#comment-15958104 ]
ASF GitHub Bot commented on ZOOKEEPER-236: ------------------------------------------ Github user hanm commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/184#discussion_r110057980 --- Diff: src/java/main/org/apache/zookeeper/common/X509UtilTest.java --- @@ -0,0 +1,231 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.zookeeper.common; + +import org.apache.zookeeper.ZKTestCase; +import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.server.ServerCnxnFactory; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.KeyUsage; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import java.io.FileOutputStream; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.Security; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Calendar; +import java.util.Date; +import java.util.Random; + +import static org.apache.zookeeper.test.ClientBase.createTmpDir; + +public class X509UtilTest extends ZKTestCase { + + private static final char[] PASSWORD = "password".toCharArray(); + private X509Certificate rootCertificate; + + private String truststorePath; + private String keystorePath; + private static KeyPair rootKeyPair; + + private X509Util x509Util; + + @BeforeClass + public static void createKeyPair() throws Exception { + Security.addProvider(new BouncyCastleProvider()); + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME); + keyPairGenerator.initialize(4096); + rootKeyPair = keyPairGenerator.genKeyPair(); + } + + @AfterClass + public static void removeBouncyCastleProvider() throws Exception { + Security.removeProvider("BC"); + } + + @Before + public void setUp() throws Exception { + rootCertificate = createSelfSignedCertifcate(rootKeyPair); + + String tmpDir = createTmpDir().getAbsolutePath(); + truststorePath = tmpDir + "/truststore.jks"; + keystorePath = tmpDir + "/keystore.jks"; + + x509Util = new ClientX509Util(); + + writeKeystore(rootCertificate, rootKeyPair, keystorePath); + + System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY, "org.apache.zookeeper.server.NettyServerCnxnFactory"); + System.setProperty(ZKClientConfig.ZOOKEEPER_CLIENT_CNXN_SOCKET, "org.apache.zookeeper.ClientCnxnSocketNetty"); + System.setProperty(x509Util.getSslKeystoreLocationProperty(), keystorePath); + System.setProperty(x509Util.getSslKeystorePasswdProperty(), new String(PASSWORD)); + System.setProperty(x509Util.getSslTruststoreLocationProperty(), truststorePath); + System.setProperty(x509Util.getSslTruststorePasswdProperty(), new String(PASSWORD)); + System.setProperty(x509Util.getSslHostnameVerificationEnabledProperty(), "false"); + + writeTrustStore(PASSWORD); + } + + private void writeKeystore(X509Certificate certificate, KeyPair keyPair, String path) throws Exception { + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null, PASSWORD); + keyStore.setKeyEntry("alias", keyPair.getPrivate(), PASSWORD, new Certificate[] { certificate }); + FileOutputStream outputStream = new FileOutputStream(path); + keyStore.store(outputStream, PASSWORD); + outputStream.flush(); + outputStream.close(); + } + + private void writeTrustStore(char[] password) throws Exception { + KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + trustStore.load(null, password); + trustStore.setCertificateEntry(rootCertificate.getSubjectDN().toString(), rootCertificate); + FileOutputStream outputStream = new FileOutputStream(truststorePath); + if (password == null) { + trustStore.store(outputStream, new char[0]); + } else { + trustStore.store(outputStream, password); + } + outputStream.flush(); + outputStream.close(); + } + + private X509Certificate createSelfSignedCertifcate(KeyPair keyPair) throws Exception { + X500NameBuilder nameBuilder = new X500NameBuilder(BCStyle.INSTANCE); + nameBuilder.addRDN(BCStyle.CN, "localhost"); + Date notBefore = new Date(); // time from which certificate is valid + Calendar cal = Calendar.getInstance(); + cal.setTime(notBefore); + cal.add(Calendar.YEAR, 1); + Date notAfter = cal.getTime(); + BigInteger serialNumber = new BigInteger(128, new Random()); + + X509v3CertificateBuilder certificateBuilder = + new JcaX509v3CertificateBuilder(nameBuilder.build(), serialNumber, notBefore, notAfter, nameBuilder.build(), keyPair.getPublic()) + .addExtension(Extension.basicConstraints, true, new BasicConstraints(0)) + .addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); + + ContentSigner contentSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate()); + + return new JcaX509CertificateConverter().getCertificate(certificateBuilder.build(contentSigner)); + } + + @After + public void cleanUp() throws Exception { + System.clearProperty(x509Util.getSslKeystoreLocationProperty()); + System.clearProperty(x509Util.getSslKeystorePasswdProperty()); + System.clearProperty(x509Util.getSslTruststoreLocationProperty()); + System.clearProperty(x509Util.getSslTruststorePasswdProperty()); + System.clearProperty(x509Util.getSslHostnameVerificationEnabledProperty()); + System.clearProperty(x509Util.getSslOcspEnabledProperty()); + System.clearProperty(x509Util.getSslCrlEnabledProperty()); + System.clearProperty("com.sun.net.ssl.checkRevocation"); + System.clearProperty("com.sun.security.enableCRLDP"); + Security.setProperty("com.sun.security.enableCRLDP", "false"); + } + + @Test --- End diff -- Just in case if any of these test method run for a long time (which I doubt) then it'll be good to specify a timeout value annotation. > SSL Support for Atomic Broadcast protocol > ----------------------------------------- > > Key: ZOOKEEPER-236 > URL: https://issues.apache.org/jira/browse/ZOOKEEPER-236 > Project: ZooKeeper > Issue Type: New Feature > Components: quorum, server > Reporter: Benjamin Reed > Assignee: Abraham Fine > Priority: Minor > > We should have the ability to use SSL to authenticate and encrypt the traffic > between ZooKeeper servers. For the most part this is a very easy change. We > would probably only want to support this for TCP based leader elections. -- This message was sent by Atlassian JIRA (v6.3.15#6346)