package org.openstack.atlas.util.ca.chain; import java.io.BufferedReader; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.security.KeyPair; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.Date; import java.util.List; import org.bouncycastle.crypto.params.KeyParameter; import org.bouncycastle.jce.PKCS10CertificationRequest; import org.bouncycastle.jce.provider.X509CertificateObject; import org.openstack.atlas.util.ca.CertUtils; import org.openstack.atlas.util.ca.CsrUtils; import org.openstack.atlas.util.ca.PemUtils; import org.openstack.atlas.util.ca.RSAKeyUtils; import org.openstack.atlas.util.ca.exceptions.NotAnX509CertificateException; import org.openstack.atlas.util.ca.exceptions.RsaException; import org.openstack.atlas.util.ca.primitives.PemBlock; import org.openstack.atlas.util.ca.util.X509ChainEntry; import org.openstack.atlas.util.ca.util.X509Inspector; import org.openstack.atlas.util.ca.util.X509PathBuilder; import org.openstack.atlas.util.debug.Debug; import org.openstack.atlas.util.staticutils.StaticDateTimeUtils; import org.openstack.atlas.util.staticutils.StaticFileUtils; public class ChainBuilderMain { private static final double MILLIS_PER_SEC = 1000.0; public static final int PAGESIZE = 4096; public static final int BUFFSIZE = 1024 * 64; public static void main(String[] args) throws IOException, NotAnX509CertificateException, RsaException { ChainConfig conf; String confFile; if (args.length <= 0) { System.out.printf("usage is %s <config_file> [notAfterSecs] [notBeforeSecs]\n", Debug.getProgName(ChainBuilderMain.class)); System.out.printf("\n"); System.out.printf("Builds a certificate based on the criteria in the config_file\n"); System.out.printf("An example configuration file is:\n"); System.out.printf("%s", ChainConfig.getConfExample()); return; } //BufferedReader stdin = StaticFileUtils.inputStreamToBufferedReader(System.in, PAGESIZE); //System.out.printf("press enter to confinute"); //stdin.readLine(); confFile = args[0]; try { conf = ChainConfig.loadChainerConfig(confFile); } catch (Exception ex) { System.out.printf("%s\n", Debug.getExtendedStackTrace(ex)); return; } if (args.length >= 2) { conf.setNotAfter(Double.parseDouble(args[1])); } if (args.length >= 3) { conf.setNotBefore(Double.parseDouble(args[2])); } System.out.printf("using config: %s\n", conf.toString()); KeyPair rootKey = null; X509CertificateObject rootCrt = null; List<PemBlock> pemBlocks; pemBlocks = PemUtils.parseMultiPem(StaticFileUtils.readFile(conf.getRootKeyFile())); for (PemBlock pemBlock : pemBlocks) { System.out.printf("block class in %s = %s\n", conf.getRootKeyFile(), pemBlock.getDecodedObject().getClass().getName()); if (pemBlock.getDecodedObject() instanceof KeyPair) { rootKey = (KeyPair) pemBlock.getDecodedObject(); break; } } pemBlocks = PemUtils.parseMultiPem(StaticFileUtils.readFile(conf.getRootCrtFile())); for (PemBlock pemBlock : pemBlocks) { System.out.printf("block class in %s = %s\n", conf.getCrtFile(), pemBlock.getDecodedObject().getClass().getName()); if (pemBlock.getDecodedObject() instanceof X509CertificateObject) { rootCrt = (X509CertificateObject) pemBlock.getDecodedObject(); break; } } if (rootKey == null || rootCrt == null) { System.out.printf("could not decode root key or crt\n"); return; } List<String> issuerNames = conf.getIssuers(); Date now = new Date(System.currentTimeMillis()); Date notBefore = secsFromDate(now, conf.getNotBefore()); Date notAfter = secsFromDate(now, conf.getNotAfter()); List<X509ChainEntry> chainEntries = X509PathBuilder.newChain(rootKey, rootCrt, issuerNames, conf.getKeySize(), notBefore, notAfter); KeyPair finalSigningKey; X509CertificateObject finalIssueingCrt; System.out.printf("RootCrt:\n%s\n", inspectCrt(rootCrt)); System.out.printf("Imd crts:\n"); if (!chainEntries.isEmpty()) { for (X509ChainEntry entry : chainEntries) { System.out.printf("%s\n\n", inspectCrt(entry.getX509obj())); } finalSigningKey = chainEntries.get(chainEntries.size() - 1).getKey(); finalIssueingCrt = chainEntries.get(chainEntries.size() - 1).getX509obj(); } else { finalSigningKey = rootKey; finalIssueingCrt = rootCrt; } String keyFile = StaticFileUtils.expandUser(conf.getKeyFile()); String crtFile = StaticFileUtils.expandUser(conf.getCrtFile()); String imdFile = StaticFileUtils.expandUser(conf.getImdFile()); System.out.printf("Saving imd chain to file %s\n", imdFile); Collections.reverse(chainEntries); OutputStream os; os = StaticFileUtils.openOutputFile(imdFile, BUFFSIZE); for (X509ChainEntry entry : chainEntries) { String x509Pem = PemUtils.toPemString(entry.getX509obj()); os.write(x509Pem.getBytes("utf-8")); } os.close(); System.out.printf("imd file saved\n"); System.out.printf("Generating %d bit key for userKey\n", conf.getKeySize()); KeyPair key = RSAKeyUtils.genKeyPair(conf.getKeySize()); System.out.printf("user key generated\n"); String keyPem = PemUtils.toPemString(key); System.out.printf("%s\n", keyPem); System.out.printf("Saving key top %s\n", keyFile); os = StaticFileUtils.openOutputFile(keyFile, BUFFSIZE); os.write(keyPem.getBytes("utf-8")); os.close(); System.out.printf("key saved\n"); System.out.printf("Generating csr for key with subjName: %s\n", conf.getSubjName()); PKCS10CertificationRequest csr = CsrUtils.newCsr(conf.getSubjName(), key, false); System.out.printf("CSR generated\n"); String csrPem = PemUtils.toPemString(csr); System.out.printf("%s\n", csrPem); System.out.printf("Signing CSR with crt %s\n", inspectCrt(finalIssueingCrt)); X509CertificateObject crt = (X509CertificateObject) CertUtils.signCSR(csr, finalSigningKey, finalIssueingCrt, notBefore, notAfter, BigInteger.ZERO); System.out.printf("Certificate signed\n%s\n", inspectCrt((X509CertificateObject) crt)); String crtPem = PemUtils.toPemString(crt); System.out.printf("%s\n", crtPem); System.out.printf("Saving crt to file %s\n", crtFile); os = StaticFileUtils.openOutputFile(crtFile, BUFFSIZE); os.write(crtPem.getBytes("utf-8")); os.close(); System.out.printf("crt saved\n"); } public static Date secsFromDate(Date now, double secs) { return new Date((long) ((double) (now.getTime()) + secs * MILLIS_PER_SEC)); } public static String inspectCrt(X509CertificateObject crt) throws NotAnX509CertificateException { StringBuilder sb = new StringBuilder(); X509Inspector xi = new X509Inspector(crt); String notBefore = StaticDateTimeUtils.toSqlTime(StaticDateTimeUtils.toDate(xi.getNotBefore())); String notAfter = StaticDateTimeUtils.toSqlTime(StaticDateTimeUtils.toDate(xi.getNotAfter())); String serial = xi.getSerial().toString(16); sb.append("issuer=").append(xi.getIssuerName()).append("\n"). append("subj=").append(xi.getSubjectName()).append("\n"). append("serial=").append(serial).append("\n"). append("notBefore=").append(notBefore).append("\n"). append("notAfter=").append(notAfter).append("\n"). append("authKey=").append(inspectAuthKey(xi)).append("\n"). append("subjKey=").append(xi.getSubjKeyId()).append("\n"); return sb.toString(); } public static String inspectAuthKey(X509Inspector xi) { StringBuilder sb = new StringBuilder(); sb.append("{"). append("id=").append((xi.getAuthKeyId() == null) ? "null" : xi.getAuthKeyId()). append(", serial=").append((xi.getAuthKeyIdSerial() == null) ? "null" : xi.getAuthKeyIdSerial().toString(16)). append(", dirName=").append((xi.getAuthKeyIdDirname() == null) ? "null" : xi.getAuthKeyIdDirname()). append("}"); return sb.toString(); } }