You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ro...@apache.org on 2018/05/04 07:07:32 UTC

[cloudstack] 02/08: ca: Fixes #2530 have all IPs from KVM host in issued X509 cert

This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch 4.11
in repository https://gitbox.apache.org/repos/asf/cloudstack.git

commit eb75c1eff51e4e121f7ef690cb56b8b22d43f143
Author: Rohit Yadav <ro...@shapeblue.com>
AuthorDate: Mon Apr 30 17:40:20 2018 +0530

    ca: Fixes #2530 have all IPs from KVM host in issued X509 cert
    
    This ensures that certificate setup includes all the IP addresses (v4
    and v6) when a (KVM) host is added to CloudStack. This fixes #2530.
    
    Signed-off-by: Rohit Yadav <ro...@shapeblue.com>
---
 .../cloudstack/ca/provider/RootCAProvider.java     | 49 +++++++++++++++++++---
 scripts/util/keystore-setup                        |  3 +-
 .../cloudstack/utils/security/CertUtils.java       |  5 ++-
 3 files changed, 49 insertions(+), 8 deletions(-)

diff --git a/plugins/ca/root-ca/src/org/apache/cloudstack/ca/provider/RootCAProvider.java b/plugins/ca/root-ca/src/org/apache/cloudstack/ca/provider/RootCAProvider.java
index 6584b35..f36d067 100644
--- a/plugins/ca/root-ca/src/org/apache/cloudstack/ca/provider/RootCAProvider.java
+++ b/plugins/ca/root-ca/src/org/apache/cloudstack/ca/provider/RootCAProvider.java
@@ -20,6 +20,7 @@ package org.apache.cloudstack.ca.provider;
 import java.io.IOException;
 import java.io.StringReader;
 import java.math.BigInteger;
+import java.net.InetAddress;
 import java.security.InvalidKeyException;
 import java.security.KeyManagementException;
 import java.security.KeyPair;
@@ -34,6 +35,7 @@ import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 import java.security.spec.InvalidKeySpecException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -45,6 +47,7 @@ import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
+import javax.xml.bind.DatatypeConverter;
 
 import org.apache.cloudstack.ca.CAManager;
 import org.apache.cloudstack.framework.ca.CAProvider;
@@ -55,9 +58,15 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.utils.security.CertUtils;
 import org.apache.cloudstack.utils.security.KeyStoreUtils;
 import org.apache.log4j.Logger;
-import org.bouncycastle.jce.PKCS10CertificationRequest;
+import org.bouncycastle.asn1.pkcs.Attribute;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.Extensions;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
 import org.bouncycastle.util.io.pem.PemObject;
 import org.bouncycastle.util.io.pem.PemReader;
 
@@ -137,7 +146,17 @@ public final class RootCAProvider extends AdapterBase implements CAProvider, Con
         return new Certificate(clientCertificate, keyPair.getPrivate(), Collections.singletonList(caCertificate));
     }
 
-    private Certificate generateCertificateUsingCsr(final String csr, final List<String> domainNames, final List<String> ipAddresses, final int validityDays) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, CertificateException, SignatureException, IOException, OperatorCreationException {
+    private Certificate generateCertificateUsingCsr(final String csr, final List<String> names, final List<String> ips, final int validityDays) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, CertificateException, SignatureException, IOException, OperatorCreationException {
+        final List<String> dnsNames = new ArrayList<>();
+        final List<String> ipAddresses = new ArrayList<>();
+
+        if (names != null) {
+            dnsNames.addAll(names);
+        }
+        if (ips != null) {
+            ipAddresses.addAll(ips);
+        }
+
         PemObject pemObject = null;
 
         try {
@@ -151,13 +170,33 @@ public final class RootCAProvider extends AdapterBase implements CAProvider, Con
             throw new CloudRuntimeException("Unable to read/process CSR: " + csr);
         }
 
-        final PKCS10CertificationRequest request = new PKCS10CertificationRequest(pemObject.getContent());
+        final JcaPKCS10CertificationRequest request = new JcaPKCS10CertificationRequest(pemObject.getContent());
+        final String subject = request.getSubject().toString();
+        for (final Attribute attribute : request.getAttributes()) {
+            if (attribute == null) {
+                continue;
+            }
+            if (attribute.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest)) {
+                final Extensions extensions = Extensions.getInstance(attribute.getAttrValues().getObjectAt(0));
+                final GeneralNames gns = GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName);
+                if (gns != null && gns.getNames() != null && gns.getNames().length > 0) {
+                    for (final GeneralName name : gns.getNames()) {
+                        if (name.getTagNo() == GeneralName.dNSName) {
+                            dnsNames.add(name.getName().toString());
+                        }
+                        if (name.getTagNo() == GeneralName.iPAddress) {
+                            final InetAddress address = InetAddress.getByAddress(DatatypeConverter.parseHexBinary(name.getName().toString().substring(1)));
+                            ipAddresses.add(address.toString().replace("/", ""));
+                        }
+                    }
+                }
+            }
+        }
 
-        final String subject = request.getCertificationRequestInfo().getSubject().toString();
         final X509Certificate clientCertificate = CertUtils.generateV3Certificate(
                 caCertificate, caKeyPair, request.getPublicKey(),
                 subject, CAManager.CertSignatureAlgorithm.value(),
-                validityDays, domainNames, ipAddresses);
+                validityDays, dnsNames, ipAddresses);
         return new Certificate(clientCertificate, null, Collections.singletonList(caCertificate));
     }
 
diff --git a/scripts/util/keystore-setup b/scripts/util/keystore-setup
index 48ce062..ce96336 100755
--- a/scripts/util/keystore-setup
+++ b/scripts/util/keystore-setup
@@ -42,7 +42,8 @@ keytool -genkey -storepass "$KS_PASS" -keypass "$KS_PASS" -alias "$ALIAS" -keyal
 
 # Generate CSR
 rm -f "$CSR_FILE"
-keytool -certreq -storepass "$KS_PASS" -alias "$ALIAS" -file $CSR_FILE -keystore "$KS_FILE" > /dev/null 2>&1
+addresses=$(ip address | grep inet | awk '{print $2}' | sed 's/\/.*//g' | grep -v '^169.254.' | grep -v '^127.0.0.1' | grep -v '^::1' | sed 's/^/ip:/g' | tr '\r\n' ',')
+keytool -certreq -storepass "$KS_PASS" -alias "$ALIAS" -file $CSR_FILE -keystore "$KS_FILE" -ext san="$addresses" > /dev/null 2>&1
 cat "$CSR_FILE"
 
 # Fix file permissions
diff --git a/utils/src/main/java/org/apache/cloudstack/utils/security/CertUtils.java b/utils/src/main/java/org/apache/cloudstack/utils/security/CertUtils.java
index 7e78362..aea65a7 100644
--- a/utils/src/main/java/org/apache/cloudstack/utils/security/CertUtils.java
+++ b/utils/src/main/java/org/apache/cloudstack/utils/security/CertUtils.java
@@ -40,6 +40,7 @@ import java.security.spec.InvalidKeySpecException;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 
 import javax.security.auth.x500.X500Principal;
@@ -219,7 +220,7 @@ public class CertUtils {
 
         final List<ASN1Encodable> subjectAlternativeNames = new ArrayList<ASN1Encodable>();
         if (publicIPAddresses != null) {
-            for (final String publicIPAddress: publicIPAddresses) {
+            for (final String publicIPAddress: new HashSet<>(publicIPAddresses)) {
                 if (Strings.isNullOrEmpty(publicIPAddress)) {
                     continue;
                 }
@@ -227,7 +228,7 @@ public class CertUtils {
             }
         }
         if (dnsNames != null) {
-            for (final String dnsName : dnsNames) {
+            for (final String dnsName : new HashSet<>(dnsNames)) {
                 if (Strings.isNullOrEmpty(dnsName)) {
                     continue;
                 }

-- 
To stop receiving notification emails like this one, please contact
rohit@apache.org.