mirror of https://github.com/apache/lucene.git
SOLR-7126: Utility classes for Crypto
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1664116 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
4becc8868c
commit
82e72c8d19
|
@ -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.SolrException;
|
|||
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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
Loading…
Reference in New Issue