blob: 42a945b3c49041e6ca2b44d949f9a82c6be93a97 [file] [log] [blame]
/*
* 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.geode.cache.ssl;
import static java.util.stream.Collectors.toList;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.InetAddress;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
public class TestSSLUtils {
public static KeyPair generateKeyPair(String algorithm) throws NoSuchAlgorithmException {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algorithm);
keyGen.initialize(1024);
return keyGen.genKeyPair();
}
private static KeyStore createEmptyKeyStore() throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null, null); // initialize
return ks;
}
public static void createKeyStore(String filename,
String password, String alias,
Key privateKey, Certificate cert) throws GeneralSecurityException, IOException {
KeyStore ks = createEmptyKeyStore();
ks.setKeyEntry(alias, privateKey, password.toCharArray(), new Certificate[] {cert});
try (OutputStream out = Files.newOutputStream(Paths.get(filename))) {
ks.store(out, password.toCharArray());
}
}
public static <T extends Certificate> void createTrustStore(
String filename, String password, Map<String, T> certs)
throws GeneralSecurityException, IOException {
KeyStore ks = KeyStore.getInstance("JKS");
try (InputStream in = Files.newInputStream(Paths.get(filename))) {
ks.load(in, password.toCharArray());
} catch (EOFException e) {
ks = createEmptyKeyStore();
}
for (Map.Entry<String, T> cert : certs.entrySet()) {
ks.setCertificateEntry(cert.getKey(), cert.getValue());
}
try (OutputStream out = Files.newOutputStream(Paths.get(filename))) {
ks.store(out, password.toCharArray());
}
}
public static class CertificateBuilder {
private final int days;
private final String algorithm;
private String name;
private List<String> dnsNames;
private List<InetAddress> ipAddresses;
public CertificateBuilder() {
this(30, "SHA1withRSA");
}
public CertificateBuilder(int days, String algorithm) {
this.days = days;
this.algorithm = algorithm;
this.dnsNames = new ArrayList<>();
this.ipAddresses = new ArrayList<>();
}
private static GeneralName dnsGeneralName(String name) {
return new GeneralName(GeneralName.dNSName, name);
}
private static GeneralName ipGeneralName(InetAddress hostAddress) {
return new GeneralName(GeneralName.iPAddress,
new DEROctetString(hostAddress.getAddress()));
}
public CertificateBuilder commonName(String cn) {
this.name = "CN=" + cn + ", O=Geode";
return this;
}
public CertificateBuilder sanDnsName(String hostName) {
this.dnsNames.add(hostName);
return this;
}
public CertificateBuilder sanIpAddress(InetAddress hostAddress) {
this.ipAddresses.add(hostAddress);
return this;
}
private byte[] san() throws IOException {
List<GeneralName> names = dnsNames.stream()
.map(CertificateBuilder::dnsGeneralName)
.collect(toList());
names.addAll(ipAddresses.stream()
.map(CertificateBuilder::ipGeneralName)
.collect(toList()));
return names.isEmpty() ? null
: new GeneralNames(names.toArray(new GeneralName[] {})).getEncoded();
}
public X509Certificate generate(KeyPair keyPair) throws CertificateException {
return this.generate(this.name, keyPair);
}
public X509Certificate generate(String dn, KeyPair keyPair) throws CertificateException {
try {
Security.addProvider(new BouncyCastleProvider());
AlgorithmIdentifier sigAlgId =
new DefaultSignatureAlgorithmIdentifierFinder().find(algorithm);
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
AsymmetricKeyParameter privateKeyAsymKeyParam =
PrivateKeyFactory.createKey(keyPair.getPrivate().getEncoded());
SubjectPublicKeyInfo subPubKeyInfo =
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
ContentSigner sigGen =
new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(privateKeyAsymKeyParam);
X500Name name = new X500Name(dn);
Date from = new Date();
Date to = new Date(from.getTime() + days * 86400000L);
BigInteger sn = new BigInteger(64, new SecureRandom());
X509v3CertificateBuilder v3CertGen =
new X509v3CertificateBuilder(name, sn, from, to, name, subPubKeyInfo);
byte[] subjectAltName = san();
if (subjectAltName != null) {
v3CertGen.addExtension(Extension.subjectAlternativeName, false, subjectAltName);
}
X509CertificateHolder certificateHolder = v3CertGen.build(sigGen);
return new JcaX509CertificateConverter().setProvider("BC")
.getCertificate(certificateHolder);
} catch (CertificateException ce) {
throw ce;
} catch (Exception e) {
throw new CertificateException(e);
}
}
}
}