Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added developments from Nimbus and updated README: 1) Can create Java…

… key store (JKS) from X509, 2) empty CRL can now be created which helps with some software that fails without one
  • Loading branch information...
commit b86298e7010e375c9734bb7f80b4031b4d845e61 1 parent 3303eea
Tim Freeman timf authored
35 README
View
@@ -21,24 +21,35 @@ Usage example of the bin/ samples:
# Create CA cert/key
-CA_BASENAME=fakeca
-mkdir /tmp/123
-./bin/create-ca.sh /tmp/123 $CA_BASENAME
+CA_BASENAME=testca
+mkdir /tmp/ezpz_test
+./bin/create-ca.sh /tmp/ezpz_test $CA_BASENAME
# Create a trusted certificate directory with expected file names
-CA_HASH=`openssl x509 -hash -noout -in /tmp/123/$CA_BASENAME.0`
-CA_PUB=$CAHASH.0
-CA_SP=$CAHASH.signing_policy
-mkdir /tmp/trusted-certs
-cp /tmp/123/$CA_BASENAME.0 /tmp/trusted-certs/$CA_PUB
-cp /tmp/123/$CA_BASENAME.signing_policy /tmp/trusted-certs/$CA_SP
+mkdir /tmp/ezpz_test/trusted-certs
+CA_HASH=`openssl x509 -hash -noout -in /tmp/ezpz_test/$CA_BASENAME.0`
+CA_PUB="/tmp/ezpz_test/trusted-certs/$CA_HASH.0"
+CA_SP="/tmp/ezpz_test/trusted-certs/$CA_HASH.signing_policy"
+cp /tmp/ezpz_test/$CA_BASENAME.0 $CA_PUB
+cp /tmp/ezpz_test/$CA_BASENAME.signing_policy $CA_SP
# Create a cert
-CAPRIV=/tmp/123/private-key-$CA_BASENAME.pem
+CA_PRIV=/tmp/ezpz_test/private-key-$CA_BASENAME.pem
HOSTNAME=example.com
-mkdir /tmp/hostcertdir
-./bin/create-cert.sh /tmp/hostcertdir $HOSTNAME hostcert.pem hostkey.pem $CA_PUB $CAPRIV
+mkdir /tmp/ezpz_test/hostcertdir
+./bin/create-cert.sh /tmp/ezpz_test/hostcertdir $HOSTNAME hostcert.pem hostkey.pem $CA_PUB $CA_PRIV
+
+
+# Create a JKS keystore for the host cert
+
+HOSTCERT=/tmp/ezpz_test/hostcertdir/hostcert.pem
+HOSTKEY=/tmp/ezpz_test/hostcertdir/hostkey.pem
+JKS_TO_CREATE=/tmp/ezpz_test/hostcertdir/hostcert.jks
+JKS_PASSWORD="3con12oij32d"
+
+./bin/create-jks.sh $HOSTCERT $HOSTKEY $JKS_TO_CREATE $JKS_PASSWORD
+
9 bin/create-ca.sh
View
@@ -12,17 +12,20 @@ source $LIBDIR/common-env.sh
if [ ! -d $1 ]; then
echo "Directory does not exist: $1" >&2
+ echo "See README" >&2
exit 1
fi
$JAVA_BIN $JAVA_OPTS $EXE_CREATE_NEW_CA $1 $2
if [ $? -ne 0 ]; then
echo "Problem creating new certificate authority, exiting." >&2
+ echo "See README" >&2
exit 1
fi
CA_PUBPEM="$1/$2.pem"
CA_PUBPEM2="$1/$2.0"
+CA_CRL="$1/$2.r0"
CA_SIGNING_POLICY="$1/$2.signing_policy"
CA_PRIVPEM="$1/private-key-$2.pem"
@@ -38,6 +41,12 @@ if [ $? -ne 0 ]; then
exit 1
fi
+$JAVA_BIN $JAVA_OPTS $EXE_CREATE_CRL $CA_CRL $CA_PUBPEM $CA_PRIVPEM
+if [ $? -ne 0 ]; then
+ echo "Problem creating new certificate authority revocation list, exiting." >&2
+ exit 1
+fi
+
cp $CA_PUBPEM $CA_PUBPEM2
if [ $? -ne 0 ]; then
echo "Problem creating certificate authority, exiting." >&2
9 bin/create-cert.sh
View
@@ -8,6 +8,11 @@ if [ ! -f $LIBDIR/common-env.sh ]; then
fi
source $LIBDIR/common-env.sh
+if [ $# -ne 6 ]; then
+ echo "Not enough arguments, see README" >&2
+ exit 1
+fi
+
TARGET_DIR=$1
NEW_CN=$2
PUBPEM=$3
@@ -20,7 +25,7 @@ PRIVCA=$6
HOSTDN=`$JAVA_BIN $JAVA_OPTS $EXE_CREATE_NEW_CERT $TARGET_DIR $NEW_CN $PUBPEM $PRIVPEM $PUBCA $PRIVCA`
if [ $? -ne 0 ]; then
- echo "Problem creating cert, exiting."
+ echo "Problem creating cert, exiting." >&2
exit 1
fi
@@ -28,7 +33,7 @@ NEW_PRIVPEM="$TARGET_DIR/$PRIVPEM"
chmod 400 $NEW_PRIVPEM
if [ $? -ne 0 ]; then
- echo "Problem setting permissions on $NEW_PRIVPEM"
+ echo "Problem setting permissions on $NEW_PRIVPEM" >&2
exit 1
fi
35 bin/create-jks.sh
View
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+THISDIR="`dirname $0`"
+LIBDIR="$THISDIR/../etc/"
+if [ ! -f $LIBDIR/common-env.sh ]; then
+ echo "Failure, cannot find environment definitions" >&2
+ exit 1
+fi
+source $LIBDIR/common-env.sh
+
+if [ $# -ne 4 ]; then
+ echo "Not enough arguments, see README" >&2
+ exit 1
+fi
+
+CERT_PATH=$1
+KEY_PATH=$2
+STORE_PATH=$3
+PASSWORD=$4
+
+# ----------------------------------------------------------------------------
+
+$JAVA_BIN $JAVA_OPTS $EXE_KEYSTORE_FROM_PEM $CERT_PATH $KEY_PATH $STORE_PATH $PASSWORD
+if [ $? -ne 0 ]; then
+ echo "Problem creating keystore, exiting." >&2
+ exit 1
+fi
+
+chmod 600 $STORE_PATH
+if [ $? -ne 0 ]; then
+ echo "Problem setting permissions on $STORE_PATH" >&2
+ exit 1
+fi
+
+echo "Created keystore @ $STORE_PATH"
6 etc/common-env.sh
View
@@ -79,6 +79,12 @@ export EXE_CREATE_NEW_CERT
EXE_WRITE_SIGNING_POLICY="org.nimbustools.auto_common.ezpz_ca.SigningPolicy"
export EXE_WRITE_SIGNING_POLICY
+EXE_CREATE_CRL="org.nimbustools.auto_common.ezpz_ca.GenerateCRL"
+export EXE_CREATE_CRL
+
+EXE_KEYSTORE_FROM_PEM="org.nimbustools.auto_common.ezpz_ca.KeystoreFromPEM"
+export EXE_KEYSTORE_FROM_PEM
+
EXE_FIND_CA_PUBPEM="org.nimbustools.auto_common.ezpz_ca.FindCAPubFile"
EXE_FIND_CA_PRIVPEM="org.nimbustools.auto_common.ezpz_ca.FindCAPrivFile"
export EXE_FIND_CA_PUBPEM EXE_FIND_CA_PRIVPEM
82 src/org/nimbustools/auto_common/ezpz_ca/CertDN.java
View
@@ -0,0 +1,82 @@
+/*
+ * Copyright 1999-2009 University of Chicago
+ *
+ * Licensed 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.nimbustools.auto_common.ezpz_ca;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.FileReader;
+import java.security.cert.X509Certificate;
+import java.security.Security;
+
+import org.bouncycastle.openssl.PEMReader;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.globus.gsi.CertUtil;
+
+import javax.security.auth.x500.X500Principal;
+
+public class CertDN {
+
+
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public static String dnFromPath(String path) throws IOException {
+
+ final File certFile = new File(path);
+ if (!certFile.canRead()) {
+ final String msg = "File '" + path + "' can not be read.";
+ throw new IOException(msg);
+ }
+
+ final FileReader fr = new FileReader(certFile);
+ try {
+ final PEMReader reader =
+ new PEMReader(fr, null, BouncyCastleProvider.PROVIDER_NAME);
+ try {
+ final X509Certificate cert = (X509Certificate) reader.readObject();
+ final X500Principal principal = cert.getSubjectX500Principal();
+ final String DN = principal.getName(X500Principal.RFC2253);
+
+ return CertUtil.toGlobusID(DN, false);
+
+ } finally {
+ reader.close();
+ }
+ } finally {
+ fr.close();
+ }
+ }
+
+
+ public static void main(String[] args) {
+
+ if (args == null || args.length != 1) {
+ System.err.println("Needs these arguments:\n" +
+ "1 - the certificate file");
+ System.exit(1);
+ }
+
+ try {
+ final String dn = dnFromPath(args[0]);
+ System.out.println(dn);
+ } catch (Throwable t) {
+ System.err.println("Problem: " + t.getMessage());
+ t.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
19 src/org/nimbustools/auto_common/ezpz_ca/CertWriter.java
View
@@ -34,7 +34,8 @@
public static final String certFooter = "-----END CERTIFICATE-----";
public static final String keyHeader = "-----BEGIN RSA PRIVATE KEY-----";
public static final String keyFooter = "-----END RSA PRIVATE KEY-----";
-
+ public static final String crlHeader = "-----BEGIN X509 CRL-----";
+ public static final String crlFooter = "-----END X509 CRL-----";
public void writeCert(X509Certificate cert,
KeyPair keyPair,
@@ -79,17 +80,23 @@ public void writeCert(X509Certificate cert,
* @return string
*/
public static String certToPEMString(String base64Data) {
- return toStringImpl(base64Data, false);
+ return toStringImpl(base64Data, false, false);
}
- private static String toStringImpl(String base64Data, boolean isKey) {
+ public static String crlToPEMString(String base64Data) {
+ return toStringImpl(base64Data, false, true);
+ }
+
+ private static String toStringImpl(String base64Data, boolean isKey, boolean isCRL) {
int length = LINE_LENGTH;
int offset = 0;
final StringBuffer buf = new StringBuffer(2048);
- if (isKey) {
+ if (isCRL) {
+ buf.append(crlHeader);
+ } else if (isKey) {
buf.append(keyHeader);
} else {
buf.append(certHeader);
@@ -106,7 +113,9 @@ private static String toStringImpl(String base64Data, boolean isKey) {
offset = offset + LINE_LENGTH;
}
- if (isKey) {
+ if (isCRL) {
+ buf.append(crlFooter);
+ } else if (isKey) {
buf.append(keyFooter);
} else {
buf.append(certFooter);
40 src/org/nimbustools/auto_common/ezpz_ca/EzPzCA.java
View
@@ -16,9 +16,14 @@
package org.nimbustools.auto_common.ezpz_ca;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.CRLNumber;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.globus.gsi.CertUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.X509V3CertificateGenerator;
+import org.bouncycastle.jce.X509V2CRLGenerator;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.KeyUsage;
@@ -26,6 +31,7 @@
import org.bouncycastle.asn1.x509.X509Name;
import javax.security.auth.x500.X500Principal;
+import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
@@ -36,6 +42,8 @@
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.InvalidKeyException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.CertificateException;
@@ -56,6 +64,8 @@
private final X509Name caX509Name;
private final String targetString;
private final CertificateFactory factory;
+ private final X509V2CRLGenerator crlGen;
+
static {
Security.addProvider(new BouncyCastleProvider());
@@ -99,7 +109,7 @@ protected EzPzCA(X509Certificate caCert,
this.caPrivate = caPrivateKey;
this.caX509Name = new X509Principal(
- caX509.getIssuerX500Principal().getEncoded());
+ this.caX509.getIssuerX500Principal().getEncoded());
this.initializeGenerator();
@@ -113,6 +123,10 @@ protected EzPzCA(X509Certificate caCert,
"and Globus style DN = '" + globusCADN + "'. " +
"New DNs will look like this (RFC2253): '" +
this.targetString + "'";
+
+ this.crlGen = new X509V2CRLGenerator();
+ this.crlGen.setIssuerDN(this.caX509Name);
+ this.crlGen.setSignatureAlgorithm("SHA1withRSA");
}
public static String deriveSigningTargetString(X509Certificate caCert) throws CertificateException {
@@ -188,6 +202,30 @@ public X509Certificate signNewCertificate(String cnString,
return x509Cert;
}
+ public X509CRL generateCRL()
+ throws SignatureException, InvalidKeyException, NoSuchProviderException,
+ CertificateEncodingException {
+
+ this.crlGen.setThisUpdate(new Date());
+ final Calendar expires = Calendar.getInstance();
+ // this is fake, expiration does not matter
+ expires.add(Calendar.MONTH, GenerateNewCert.VALIDITY_MONTHS);
+ this.crlGen.setNextUpdate(expires.getTime());
+
+ // this is how you'd actually add an entry if we wanted one:
+ //this.crlGen.addCRLEntry(BigInteger.ONE, new Date(), CRLReason.PRIVILEGE_WITHDRAWN);
+
+ this.crlGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
+ new AuthorityKeyIdentifier(
+ new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier("RSA"), this.caX509.getEncoded())));
+
+ this.crlGen.addExtension(X509Extensions.CRLNumber,
+ false, new CRLNumber(BigInteger.ONE));
+
+ return this.crlGen.generateX509CRL(this.caPrivate, "BC");
+ }
+
private String getTargetDN(String cnString) {
return getTargetDNfromSchema(this.targetString, "CN=" + cnString);
}
110 src/org/nimbustools/auto_common/ezpz_ca/GenerateCRL.java
View
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1999-2010 University of Chicago
+ *
+ * Licensed 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.nimbustools.auto_common.ezpz_ca;
+
+import org.apache.axis.encoding.Base64;
+import org.globus.gsi.GlobusCredential;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.OutputStreamWriter;
+import java.security.PrivateKey;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+
+public class GenerateCRL {
+
+ // -------------------------------------------------------------------------
+ // GENERATE
+ // -------------------------------------------------------------------------
+
+ public void generateCRL(String targetPath,
+ String caPubPemPath,
+ String caPrivPemPath) throws Exception {
+
+ if (targetPath == null) {
+ throw new IllegalArgumentException("targetPath may not be null");
+ }
+ if (caPubPemPath == null) {
+ throw new IllegalArgumentException("caPubPemPath may not be null");
+ }
+ if (caPrivPemPath == null) {
+ throw new IllegalArgumentException("caPrivPemPath may not be null");
+ }
+
+ final File crlFileCheck = new File(targetPath);
+ if (crlFileCheck.exists()) {
+ throw new Exception("File already exists: " + targetPath);
+ }
+
+ File certFile = new File(caPubPemPath);
+ if (!certFile.canRead()) {
+ final String msg = "Configured CA certificate path ('" +
+ caPubPemPath + "') can not be read.";
+ throw new Exception(msg);
+ }
+
+ certFile = new File(caPrivPemPath);
+ if (!certFile.canRead()) {
+ final String msg = "Configured CA key path ('" +
+ caPrivPemPath + "') can not be read.";
+ throw new Exception(msg);
+ }
+
+ final GlobusCredential caGlobusCred =
+ new GlobusCredential(caPubPemPath, caPrivPemPath);
+
+ final X509Certificate caCert = caGlobusCred.getIdentityCertificate();
+ final PrivateKey caPrivateKey = caGlobusCred.getPrivateKey();
+
+ final EzPzCA ca = new EzPzCA(caCert, caPrivateKey,
+ caGlobusCred.getIdentity());
+
+ final X509CRL crl = ca.generateCRL();
+
+ final String crlPEM = CertWriter.crlToPEMString(Base64.encode(crl.getEncoded()));
+ final OutputStreamWriter crlFile = new FileWriter(targetPath);
+ crlFile.write(crlPEM);
+ crlFile.close();
+ }
+
+
+ // -------------------------------------------------------------------------
+ // MAIN
+ // -------------------------------------------------------------------------
+
+ public static void main(String[] args) throws Exception {
+
+ if (args == null || args.length != 3) {
+ System.err.println("Needs these arguments:\n" +
+ "1 - the target path to write CRL\n" +
+ "2 - the pub pem of EzPz CA\n" +
+ "3 - the priv pem of EzPz CA");
+ System.exit(1);
+ }
+
+ new GenerateCRL().generateCRL(args[0], args[1], args[2]);
+
+ try {
+
+
+ } catch (Exception e) {
+ System.err.println("Problem creating CRL: " + e.getMessage());
+ System.exit(1);
+ }
+ }
+}
135 src/org/nimbustools/auto_common/ezpz_ca/KeystoreFromPEM.java
View
@@ -0,0 +1,135 @@
+/*
+ * Copyright 1999-2010 University of Chicago
+ *
+ * Licensed 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.nimbustools.auto_common.ezpz_ca;
+
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMReader;
+
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.io.*;
+import java.util.Arrays;
+
+/**
+ * Creates a Java Keystore from PEM encoded cert and private key
+ */
+public class KeystoreFromPEM {
+
+ public final static String ENTRY_ALIAS = "";
+
+ static {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public static KeyStore createJavaKeystore(X509Certificate cert, PrivateKey key, String password)
+ throws Exception {
+
+ KeyStore store = KeyStore.getInstance("JKS", "SUN");
+ store.load(null, password.toCharArray());
+ store.setKeyEntry(ENTRY_ALIAS, key, password.toCharArray(),
+ new Certificate[] {cert});
+
+ return store;
+ }
+
+ public static void createJavaKeystore(File certFile, File keyFile,
+ File keystoreFile, String password)
+ throws Exception {
+
+ X509Certificate cert = (X509Certificate) readPemObject(certFile);
+ KeyPair keypair = (KeyPair) readPemObject(keyFile);
+ KeyStore store = createJavaKeystore(cert, keypair.getPrivate(), password);
+ OutputStream outStream = new FileOutputStream(keystoreFile);
+ try {
+ store.store(outStream, password.toCharArray());
+ } finally {
+ outStream.close();
+ }
+ }
+
+ public static boolean checkJavaKeystore(File certFile, File keyFile,
+ File keystoreFile, String password) throws Exception {
+ X509Certificate cert = (X509Certificate) readPemObject(certFile);
+ KeyPair keypair = (KeyPair) readPemObject(keyFile);
+ PrivateKey privateKey = keypair.getPrivate();
+ KeyStore store = KeyStore.getInstance("JKS", "SUN");
+ final char[] passwordChars = password.toCharArray();
+
+ InputStream inStream = new FileInputStream(keystoreFile);
+ try {
+ store.load(inStream, passwordChars);
+ } finally {
+ inStream.close();
+ }
+ final Certificate curCert = store.getCertificate(ENTRY_ALIAS);
+ if (curCert == null ||
+ !Arrays.equals(curCert.getEncoded(), cert.getEncoded())) {
+ return false;
+ }
+ final Key curKey = store.getKey(ENTRY_ALIAS, passwordChars);
+ return curKey != null &&
+ Arrays.equals(curKey.getEncoded(), privateKey.getEncoded());
+ }
+
+ private static Object readPemObject(File file) throws IOException {
+ FileReader reader = new FileReader(file);
+ try {
+ PEMReader pemReader = new PEMReader(reader, null, BouncyCastleProvider.PROVIDER_NAME);
+ return pemReader.readObject();
+ } finally {
+ reader.close();
+ }
+ }
+
+ public static void main(String[] args) {
+
+ if (args == null || args.length != 4) {
+ System.err.println("Needs these arguments:\n" +
+ "1 - the certificate file\n" +
+ "2 = the private key file\n" +
+ "3 - the destination file\n" +
+ "4 - the keystore password\n"
+ );
+ System.exit(1);
+ }
+
+ try {
+ File certFile = new File(args[0]);
+ File keyFile = new File(args[1]);
+ File keystoreFile = new File(args[2]);
+ String password = args[3];
+
+ if (keystoreFile.exists()) {
+ if (checkJavaKeystore(certFile, keyFile,
+ keystoreFile, password)) {
+ System.exit(0);
+ } else {
+ System.err.println("The keystore exists but does not " +
+ "contain the correct key and certificate");
+ System.exit(2);
+ }
+ }
+
+ createJavaKeystore(certFile, keyFile, keystoreFile, password);
+
+ } catch (Throwable t) {
+ System.err.println("Problem: " + t.getMessage());
+ t.printStackTrace();
+ System.exit(1);
+ }
+ }
+}
Please sign in to comment.
Something went wrong with that request. Please try again.