From 9639cb7bdf602887899feccdd639406e4c9323ca Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Mon, 28 Mar 2016 00:33:12 +0300 Subject: [PATCH] Refactor CertUtils. Support ECDSA and PrivateKey. --- .../core/util/CertificateUtils.java | 206 +++++++++++------- 1 file changed, 128 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java b/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java index 562a954a7..6e1925630 100644 --- a/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java +++ b/src/main/java/com/github/dockerjava/core/util/CertificateUtils.java @@ -2,30 +2,38 @@ import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; import java.security.KeyFactory; -import java.security.KeyPair; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; -import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.List; -import org.apache.commons.io.IOUtils; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.CheckForNull; + +import static java.util.Objects.requireNonNull; public class CertificateUtils { + private static final Logger LOG = LoggerFactory.getLogger(CertificateUtils.class); + private CertificateUtils() { // utility class } @@ -41,115 +49,157 @@ public static boolean verifyCertificatesExist(String dockerCertPath) { return result; } + /** + * @param dockerCertPath with standard named files. + */ public static KeyStore createKeyStore(final String dockerCertPath) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, CertificateException, KeyStoreException { - KeyPair keyPair = loadPrivateKey(dockerCertPath); - List privateCertificates = loadCertificates(dockerCertPath); + return createKeyStore("key.pem", "cert.pem"); + } + + + @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") + public static KeyStore createKeyStore(final String keypem, final String certpem) throws NoSuchAlgorithmException, + InvalidKeySpecException, IOException, CertificateException, KeyStoreException { + PrivateKey privateKey = loadPrivateKey(keypem); + requireNonNull(privateKey); + List privateCertificates = loadCertificates(certpem); KeyStore keyStore = KeyStore.getInstance("JKS"); keyStore.load(null); - keyStore.setKeyEntry("docker", keyPair.getPrivate(), "docker".toCharArray(), - privateCertificates.toArray(new Certificate[privateCertificates.size()])); + keyStore.setKeyEntry("docker", + privateKey, + "docker".toCharArray(), + privateCertificates.toArray(new Certificate[privateCertificates.size()]) + ); + return keyStore; } - public static KeyStore createTrustStore(final String dockerCertPath) throws IOException, CertificateException, - KeyStoreException, NoSuchAlgorithmException { - File caPath = new File(dockerCertPath, "ca.pem"); - BufferedReader reader = new BufferedReader(new FileReader(caPath)); - PEMParser pemParser = null; - - try { - pemParser = new PEMParser(reader); - X509CertificateHolder certificateHolder = (X509CertificateHolder) pemParser.readObject(); - Certificate caCertificate = new JcaX509CertificateConverter().setProvider("BC").getCertificate( - certificateHolder); - - KeyStore trustStore = KeyStore.getInstance("JKS"); - trustStore.load(null); - trustStore.setCertificateEntry("ca", caCertificate); - return trustStore; - - } finally { - if (pemParser != null) { - IOUtils.closeQuietly(pemParser); - } - - if (reader != null) { - IOUtils.closeQuietly(reader); - } + /** + * from "cert.pem" String + */ + private static List loadCertificates(final String certpem) throws IOException, + CertificateException { + final StringReader certReader = new StringReader(certpem); + try (BufferedReader reader = new BufferedReader(certReader)) { + return loadCertificates(reader); } - } - private static List loadCertificates(final String dockerCertPath) throws IOException, + /** + * "cert.pem" from reader + */ + private static List loadCertificates(final Reader reader) throws IOException, CertificateException { - File certificate = new File(dockerCertPath, "cert.pem"); - BufferedReader reader = new BufferedReader(new FileReader(certificate)); - PEMParser pemParser = null; - - try { + try (PEMParser pemParser = new PEMParser(reader)) { List certificates = new ArrayList<>(); - pemParser = new PEMParser(reader); + JcaX509CertificateConverter certificateConverter = new JcaX509CertificateConverter().setProvider("BC"); Object certObj = pemParser.readObject(); - while (certObj != null) { + if (certObj instanceof X509CertificateHolder) { X509CertificateHolder certificateHolder = (X509CertificateHolder) certObj; certificates.add(certificateConverter.getCertificate(certificateHolder)); - - certObj = pemParser.readObject(); } return certificates; - } finally { - if (pemParser != null) { - IOUtils.closeQuietly(pemParser); - } - - if (reader != null) { - IOUtils.closeQuietly(reader); - } } - } - private static KeyPair loadPrivateKey(final String dockerCertPath) throws IOException, NoSuchAlgorithmException, - InvalidKeySpecException { - File certificate = new File(dockerCertPath, "key.pem"); - BufferedReader reader = new BufferedReader(new FileReader(certificate)); - PEMParser pemParser = null; + /** + * Return private key ("key.pem") from Reader + */ + @CheckForNull + private static PrivateKey loadPrivateKey(final Reader reader) throws IOException, NoSuchAlgorithmException, + InvalidKeySpecException { + try (PEMParser pemParser = new PEMParser(reader)) { + Object readObject = pemParser.readObject(); + while (readObject != null) { + if (readObject instanceof PEMKeyPair) { + PEMKeyPair pemKeyPair = (PEMKeyPair) readObject; + PrivateKey privateKey = guessKey(pemKeyPair.getPrivateKeyInfo().getEncoded()); + if (privateKey != null) { + return privateKey; + } + } else if (readObject instanceof PrivateKeyInfo) { + PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) readObject; + PrivateKey privateKey = guessKey(privateKeyInfo.getEncoded()); + if (privateKey != null) { + return privateKey; + } + } else if (readObject instanceof ASN1ObjectIdentifier) { + // no idea how it can be used + final ASN1ObjectIdentifier asn1ObjectIdentifier = (ASN1ObjectIdentifier) readObject; + LOG.trace("Ignoring asn1ObjectIdentifier {}", asn1ObjectIdentifier); + } else { + LOG.warn("Unknown object '{}' from PEMParser", readObject); + } + + readObject = pemParser.readObject(); + } + } - try { - pemParser = new PEMParser(reader); + return null; + } - PEMKeyPair pemKeyPair = (PEMKeyPair) pemParser.readObject(); + @CheckForNull + private static PrivateKey guessKey(byte[] encodedKey) throws NoSuchAlgorithmException { + //no way to know, so iterate + for (String guessFactory : new String[]{"RSA", "ECDSA"}) { + try { + KeyFactory factory = KeyFactory.getInstance(guessFactory); - byte[] pemPrivateKeyEncoded = pemKeyPair.getPrivateKeyInfo().getEncoded(); - byte[] pemPublicKeyEncoded = pemKeyPair.getPublicKeyInfo().getEncoded(); + PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey); + return factory.generatePrivate(privateKeySpec); + } catch (InvalidKeySpecException ignore) { + } + } - KeyFactory factory = KeyFactory.getInstance("RSA"); + return null; + } - X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(pemPublicKeyEncoded); - PublicKey publicKey = factory.generatePublic(publicKeySpec); + /** + * Return KeyPair from "key.pem" + */ + @CheckForNull + private static PrivateKey loadPrivateKey(final String keypem) throws IOException, NoSuchAlgorithmException, + InvalidKeySpecException { + try (StringReader certReader = new StringReader(keypem); + BufferedReader reader = new BufferedReader(certReader)) { + return loadPrivateKey(reader); + } + } - PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(pemPrivateKeyEncoded); - PrivateKey privateKey = factory.generatePrivate(privateKeySpec); + /** + * "ca.pem" from String + */ + public static KeyStore createTrustStore(String capem) throws IOException, CertificateException, + KeyStoreException, NoSuchAlgorithmException { + try (Reader certReader = new StringReader(capem)) { + return createTrustStore(certReader); + } + } - return new KeyPair(publicKey, privateKey); + /** + * "ca.pem" from Reader + */ + public static KeyStore createTrustStore(final Reader certReader) throws IOException, CertificateException, + KeyStoreException, NoSuchAlgorithmException { + try (PEMParser pemParser = new PEMParser(certReader)) { + X509CertificateHolder certificateHolder = (X509CertificateHolder) pemParser.readObject(); + Certificate caCertificate = new JcaX509CertificateConverter() + .setProvider("BC") + .getCertificate(certificateHolder); - } finally { - if (pemParser != null) { - IOUtils.closeQuietly(pemParser); - } + KeyStore trustStore = KeyStore.getInstance("JKS"); + trustStore.load(null); + trustStore.setCertificateEntry("ca", caCertificate); - if (reader != null) { - IOUtils.closeQuietly(reader); - } + return trustStore; } - } }