Hello Alon Bar-Lev,
I'd like you to do a code review. Please visit
http://gerrit.ovirt.org/35830
to review the following change.
Change subject: uutils: introduce CertificateChain
......................................................................
uutils: introduce CertificateChain
Chain related utilities.
Change-Id: I20fd6ea1436f22eae40c572f8fbed5d13391ffbc
Signed-off-by: Alon Bar-Lev <[email protected]>
---
A
backend/manager/modules/uutils/src/main/java/org/ovirt/engine/core/uutils/crypto/CertificateChain.java
1 file changed, 226 insertions(+), 0 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/30/35830/1
diff --git
a/backend/manager/modules/uutils/src/main/java/org/ovirt/engine/core/uutils/crypto/CertificateChain.java
b/backend/manager/modules/uutils/src/main/java/org/ovirt/engine/core/uutils/crypto/CertificateChain.java
new file mode 100644
index 0000000..d505c75
--- /dev/null
+++
b/backend/manager/modules/uutils/src/main/java/org/ovirt/engine/core/uutils/crypto/CertificateChain.java
@@ -0,0 +1,226 @@
+package org.ovirt.engine.core.uutils.crypto;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.file.FileSystems;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertStore;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Certificate chain related tools.
+ * Example:
+ * <pre>
+ * CertificateChain.completeChain(CertificateChain.getSSLPeerCertificates(new
URL("https://www.google.com")), null)
+ * </pre>
+ */
+public class CertificateChain {
+
+ /**
+ * Returns trust anchors out of key store.
+ * @param keystore KeyStore to use.
+ * @return TrustAnchor
+ */
+ public static Set<TrustAnchor> keyStoreToTrustAnchors(KeyStore keystore)
throws KeyStoreException {
+ Set<TrustAnchor> ret = new HashSet<>();
+
+ for (String alias : Collections.list(keystore.aliases())) {
+ try {
+ KeyStore.Entry entry = keystore.getEntry(alias, null);
+ if (entry instanceof KeyStore.TrustedCertificateEntry) {
+ Certificate c =
((KeyStore.TrustedCertificateEntry)entry).getTrustedCertificate();
+ if (c instanceof X509Certificate) {
+ c.verify(c.getPublicKey());
+ ret.add(new TrustAnchor((X509Certificate)c, null));
+ }
+ }
+ } catch(Exception e) {
+ // ignore
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Returns trust anchors for the default java key store.
+ * @return TrustAnchor
+ */
+ public static Set<TrustAnchor> getDefaultTrustAnchors() throws
GeneralSecurityException, IOException {
+ try (
+ InputStream is = new FileInputStream(
+ System.getProperty(
+ "javax.net.ssl.trustStore",
+ FileSystems.getDefault().getPath(
+ System.getProperty("java.home"),
+ "lib",
+ "security",
+ "cacerts"
+ ).toString()
+ )
+ )
+ ) {
+ KeyStore trustStore = KeyStore.getInstance(
+ System.getProperty(
+ "javax.net.ssl.trustStoreType",
+ KeyStore.getDefaultType()
+ )
+ );
+ trustStore.load(
+ is,
+ System.getProperty(
+ "javax.net.ssl.trustStorePassword",
+ "changeit"
+ ).toCharArray()
+ );
+
+ return keyStoreToTrustAnchors(trustStore);
+ }
+ }
+
+ /**
+ * Builds CertsPath object out of chain candidate.
+ * Throws CertPathBuilderException exception if fails among other
exceptions.
+ * @param chain chain candidate, first end certificate last issuer.
+ * @param trustAnchors trust anchors to use.
+ * @return CertPath
+ */
+ public static CertPath buildCertPath(
+ List<Certificate> chain,
+ Set<TrustAnchor> trustAnchors
+ ) throws GeneralSecurityException {
+ X509CertSelector selector = new X509CertSelector();
+ selector.setCertificate((X509Certificate)chain.get(0));
+ PKIXBuilderParameters pkixParams = new PKIXBuilderParameters(
+ trustAnchors,
+ selector
+ );
+ pkixParams.setRevocationEnabled(false);
+ pkixParams.setMaxPathLength(-1);
+ pkixParams.addCertStore(
+ CertStore.getInstance(
+ "Collection",
+ new CollectionCertStoreParameters(chain)
+ )
+ );
+ return
CertPathBuilder.getInstance("PKIX").build(pkixParams).getCertPath();
+ }
+
+ /**
+ * Complete certificate chain candidate up to root if possible.
+ * @param chain chain candidate, first end certificate last issuer.
+ * @param extraTrustAnchors extra trust anchors to use.
+ * @return Built chain
+ */
+ public static List<Certificate> completeChain(
+ List<Certificate> chain,
+ Set<TrustAnchor> extraTrustAnchors
+ ) throws GeneralSecurityException, IOException {
+ List<Certificate> ret = chain;
+
+ if (ret != null) {
+ Certificate top = ret.get(ret.size()-1);
+ boolean topIsRoot = false;
+ try {
+ top.verify(top.getPublicKey());
+ topIsRoot = true;
+ } catch(Exception e) {
+ // ignore
+ }
+
+ if (!topIsRoot && ret.get(0) instanceof X509Certificate) {
+ try {
+ Set<TrustAnchor> trustAnchors = getDefaultTrustAnchors();
+ if (extraTrustAnchors != null) {
+ trustAnchors.addAll(extraTrustAnchors);
+ }
+ ret = new ArrayList<>(buildCertPath(ret,
trustAnchors).getCertificates());
+ top = ret.get(ret.size()-1);
+ for (TrustAnchor t : trustAnchors) {
+ try {
+ Certificate c= t.getTrustedCert();
+ top.verify(c.getPublicKey());
+ ret.add(c);
+ break;
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ } catch (CertPathBuilderException e) {
+ // ignore
+ }
+ }
+ }
+
+ return ret;
+ }
+
+ /**
+ * Retrieve SSL peer certificate.
+ * @param url URL to use.
+ * @return Chain received from peer.
+ */
+ public static List<Certificate> getSSLPeerCertificates(URL url) throws
GeneralSecurityException, IOException {
+ List<Certificate> ret = null;
+
+ if ("https".equals(url.getProtocol())) {
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ ctx.init(
+ null,
+ new TrustManager[]{
+ new X509TrustManager() {
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[] {};
+ }
+ public void checkClientTrusted(
+ X509Certificate[] certs,
+ String authType
+ ) {
+ }
+ public void checkServerTrusted(
+ X509Certificate[] certs,
+ String authType
+ ) {
+ }
+ }
+ },
+ null
+ );
+
+ try (
+ SSLSocket sock =
(SSLSocket)ctx.getSocketFactory().createSocket(
+ url.getHost(),
+ url.getPort() != -1 ? url.getPort() : url.getDefaultPort()
+ )
+ ) {
+ sock.setSoTimeout(60*1000);
+ sock.startHandshake();
+ ret = Arrays.asList(sock.getSession().getPeerCertificates());
+ }
+ }
+
+ return ret;
+ }
+
+}
--
To view, visit http://gerrit.ovirt.org/35830
To unsubscribe, visit http://gerrit.ovirt.org/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I20fd6ea1436f22eae40c572f8fbed5d13391ffbc
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.5
Gerrit-Owner: Yair Zaslavsky <[email protected]>
Gerrit-Reviewer: Alon Bar-Lev <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches