You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2015/03/04 20:12:54 UTC

svn commit: r1664116 - in /lucene/dev/trunk/solr/core/src: java/org/apache/solr/cloud/CloudUtil.java java/org/apache/solr/util/CryptoKeys.java test/org/apache/solr/cloud/TestCryptoKeys.java

Author: noble
Date: Wed Mar  4 19:12:53 2015
New Revision: 1664116

URL: http://svn.apache.org/r1664116
Log:
SOLR-7126: Utility classes for Crypto

Added:
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java   (with props)
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestCryptoKeys.java   (with props)
Modified:
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java?rev=1664116&r1=1664115&r2=1664116&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/cloud/CloudUtil.java Wed Mar  4 19:12:53 2015
@@ -19,6 +19,10 @@ package org.apache.solr.cloud;
 
 import java.io.File;
 import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 
 import org.apache.commons.io.FileUtils;
@@ -26,10 +30,12 @@ import org.apache.solr.common.SolrExcept
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.cloud.SolrZkClient;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.core.SolrResourceLoader;
+import org.apache.zookeeper.KeeperException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -99,4 +105,27 @@ public class CloudUtil {
             ((ZkSolrResourceLoader) loader).getConfigSetZkPath() + "/" :
             loader.getConfigDir();
   }
+
+  /**Read the list of public keys from ZK
+   */
+
+  public static Map<String, byte[]> getTrustedKeys(SolrZkClient zk){
+     Map<String,byte[]> result =  new HashMap<>();
+    try {
+      List<String> children = zk.getChildren("/keys", null, true);
+      for (String key : children) {
+        result.put(key, zk.getData("/keys/"+key,null,null,true));
+      }
+    } catch (KeeperException.NoNodeException e) {
+      log.warn("Error fetching key names");
+      return Collections.EMPTY_MAP;
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      throw new SolrException(ErrorCode.SERVER_ERROR,"Unable to read crypto keys",e );
+    } catch (KeeperException e) {
+      throw new SolrException(ErrorCode.SERVER_ERROR,"Unable to read crypto keys",e );
+    }
+    return result;
+
+  }
 }

Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java?rev=1664116&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CryptoKeys.java Wed Mar  4 19:12:53 2015
@@ -0,0 +1,107 @@
+package org.apache.solr.util;
+
+/*
+ * 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.
+ */
+
+import java.nio.ByteBuffer;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.common.util.Base64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**A utility class to verify signatures
+ *
+ */
+public final class CryptoKeys {
+  private static final Logger log = LoggerFactory.getLogger(CryptoKeys.class);
+
+  private final Map<String, PublicKey> keys;
+
+
+  public CryptoKeys(Map<String, byte[]> trustedKeys) throws Exception {
+    HashMap<String, PublicKey> m = new HashMap<>();
+    for (Map.Entry<String, byte[]> e : trustedKeys.entrySet()) {
+      m.put(e.getKey(), getX509PublicKey(e.getValue()));
+
+    }
+    this.keys = m;
+  }
+
+  /**
+   * Try with all signatures and return the name of the signature that matched
+   */
+  public String verify(String sig, byte[] data) {
+
+    for (Map.Entry<String, PublicKey> entry : keys.entrySet()) {
+      boolean verified;
+      try {
+        verified = CryptoKeys.verify(entry.getValue(), Base64.base64ToByteArray(sig), ByteBuffer.wrap(data));
+        log.info("verified {} ", verified);
+        if (verified) return entry.getKey();
+      } catch (Exception e) {
+        log.info("NOT verified  ");
+      }
+
+    }
+
+    return null;
+  }
+
+
+  /**
+   * Create PublicKey from a .DER file
+   */
+  public static PublicKey getX509PublicKey(byte[] buf)
+      throws Exception {
+    X509EncodedKeySpec spec = new X509EncodedKeySpec(buf);
+    KeyFactory kf = KeyFactory.getInstance("RSA");
+    return kf.generatePublic(spec);
+  }
+
+  /**
+   * Verify the signature of a file
+   *
+   * @param publicKey the public key used to sign this
+   * @param sig       the signature
+   * @param data      The data tha is signed
+   */
+  public static boolean verify(PublicKey publicKey, byte[] sig, ByteBuffer data) throws InvalidKeyException, SignatureException {
+    Signature signature = null;
+    try {
+      signature = Signature.getInstance("SHA1withRSA");
+      signature.initVerify(publicKey);
+      signature.update(data);
+      boolean verify = signature.verify(sig);
+      return verify;
+
+    } catch (NoSuchAlgorithmException e) {
+      //will not happen
+    }
+    return false;
+  }
+
+
+}

Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestCryptoKeys.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestCryptoKeys.java?rev=1664116&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestCryptoKeys.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/cloud/TestCryptoKeys.java Wed Mar  4 19:12:53 2015
@@ -0,0 +1,117 @@
+package org.apache.solr.cloud;
+
+/*
+ * 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.
+ */
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.util.CryptoKeys;
+import org.apache.zookeeper.CreateMode;
+import org.apache.zookeeper.KeeperException;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TestCryptoKeys extends AbstractFullDistribZkTestBase {
+  private static final Logger logger = LoggerFactory.getLogger(TestCryptoKeys.class);
+
+
+  @Override
+  public void distribSetUp() throws Exception {
+    super.distribSetUp();
+    System.setProperty("numShards", Integer.toString(sliceCount));
+  }
+
+  public TestCryptoKeys() {
+    super();
+    sliceCount = 1;
+  }
+
+  @Test
+  public void test() throws Exception {
+    String pk1sig = "G8LEW7uJ1is81Aqqfl3Sld3qDtOxPuVFeTLJHFJWecgDvUkmJNFXmf7nkHOVlXnDWahp1vqZf0W02VHXg37lBw==";
+    String pk2sig = "pCyBQycB/0YvLVZfKLDIIqG1tFwM/awqzkp2QNpO7R3ThTqmmrj11wEJFDRLkY79efuFuQPHt40EE7jrOKoj9jLNELsfEqvU3jw9sZKiDONY+rV9Bj9QPeW8Pgt+F9Y1";
+    String wrongKeySig = "xTk2hTipfpb+J5s4x3YZGOXkmHWtnJz05Vvd8RTm/Q1fbQVszR7vMk6dQ1URxX08fcg4HvxOo8g9bG2TSMOGjg==";
+    String result = null;
+    CryptoKeys cryptoKeys = null;
+    SolrZkClient zk = getCommonCloudSolrClient().getZkStateReader().getZkClient();
+    cryptoKeys = new CryptoKeys(CloudUtil.getTrustedKeys(zk));
+    byte[] samplefile = readFile("samplefile.bin");
+    //there are no keys
+
+    result = cryptoKeys.verify( pk1sig,samplefile);
+    assertNull(result);
+
+    zk.makePath("/keys", true);
+
+    createNode(zk, "pubk1.der");
+    createNode(zk, "pubk2.der");
+
+    Map<String, byte[]> trustedKeys = CloudUtil.getTrustedKeys(zk);
+
+
+    cryptoKeys = new CryptoKeys(trustedKeys);
+
+
+    result = cryptoKeys.verify(pk2sig, samplefile);
+    assertEquals("pubk2.der", result);
+
+
+    result = cryptoKeys.verify(pk1sig, samplefile);
+    assertEquals("pubk1.der", result);
+
+    try {
+      result = cryptoKeys.verify(wrongKeySig,samplefile);
+      assertNull(result);
+    } catch (Exception e) {
+      //pass
+    }
+
+
+    try {
+      result = cryptoKeys.verify( "SGVsbG8gV29ybGQhCg==", samplefile);
+      assertNull(result);
+    } catch (Exception e) {
+      //pass
+
+    }
+
+
+  }
+
+
+
+  private void createNode(SolrZkClient zk, String fname) throws IOException, KeeperException, InterruptedException {
+    byte[] buf = readFile(fname);
+    zk.create("/keys/" + fname, buf, CreateMode.PERSISTENT, true);
+
+  }
+
+  private byte[] readFile(String fname) throws IOException {
+    byte[] buf = null;
+    try (FileInputStream fis = new FileInputStream(getFile("cryptokeys/" + fname))) {
+      buf = new byte[fis.available()];
+      fis.read(buf);
+    }
+    return buf;
+  }
+
+
+}