You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mu...@apache.org on 2013/12/12 07:44:32 UTC
git commit: updated refs/heads/4.3 to fb89a2d
Updated Branches:
refs/heads/4.3 326a46d0a -> fb89a2d8f
CLOUDSTACK-5296: Add certificate chain support for netscaler.
adds support for trust chains in the netscaler
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/fb89a2d8
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/fb89a2d8
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/fb89a2d8
Branch: refs/heads/4.3
Commit: fb89a2d8f6c75d92ac926e9728ef9fa974ffcdd1
Parents: 326a46d
Author: Syed Ahmed <sa...@cloudops.com>
Authored: Thu Dec 12 12:11:20 2013 +0530
Committer: Murali Reddy <mu...@gmail.com>
Committed: Thu Dec 12 12:13:43 2013 +0530
----------------------------------------------------------------------
.gitignore | 2 +-
.../com/cloud/network/lb/LoadBalancingRule.java | 15 +-
.../com/cloud/network/dao/SslCertDaoImpl.java | 2 +-
.../network/resource/NetscalerResource.java | 235 ++++++++++++++++---
.../lb/LoadBalancingRulesManagerImpl.java | 8 +-
.../cloudstack/network/lb/CertServiceImpl.java | 92 +++++---
.../cloud/utils/security/CertificateHelper.java | 56 +++++
7 files changed, 326 insertions(+), 84 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fb89a2d8/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 74739b2..2af2d17 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-G# Licensed to the Apache Software Foundation (ASF) under one
+# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fb89a2d8/api/src/com/cloud/network/lb/LoadBalancingRule.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java
index 39c969c..36f3a44 100644
--- a/api/src/com/cloud/network/lb/LoadBalancingRule.java
+++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java
@@ -439,16 +439,17 @@ public class LoadBalancingRule {
public static class LbSslCert {
private String cert;
private String key;
- private String password=null;
- private String chain=null;
+ private String password = null;
+ private String chain = null;
+ private String fingerprint = null;
private boolean revoked;
-
- public LbSslCert(String cert, String key, String password, String chain, boolean revoked) {
+ public LbSslCert(String cert, String key, String password, String chain, String fingerprint, boolean revoked) {
this.cert = cert;
this.key = key;
this.password = password;
this.chain = chain;
+ this.fingerprint = fingerprint;
this.revoked = revoked;
}
@@ -469,7 +470,11 @@ public class LoadBalancingRule {
return chain;
}
- public boolean isRevoked(){
+ public String getFingerprint() {
+ return fingerprint;
+ }
+
+ public boolean isRevoked() {
return revoked;
}
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fb89a2d8/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java
----------------------------------------------------------------------
diff --git a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java
index af0d970..5fd6cfb 100644
--- a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java
+++ b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java
@@ -34,7 +34,7 @@ public class SslCertDaoImpl extends GenericDaoBase<SslCertVO, Long> implements S
listByAccountId = createSearchBuilder();
listByAccountId.and("accountId", listByAccountId.entity().getAccountId(), SearchCriteria.Op.EQ);
listByAccountId.done();
- }
+ }
@Override
public List<SslCertVO> listByAccountId(Long accountId) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fb89a2d8/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java
index e48d31d..4cd70cb 100644
--- a/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java
+++ b/plugins/network-elements/netscaler/src/com/cloud/network/resource/NetscalerResource.java
@@ -16,6 +16,9 @@
// under the License.
package com.cloud.network.resource;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Formatter;
import java.util.HashMap;
@@ -26,9 +29,14 @@ import java.util.Map;
import javax.naming.ConfigurationException;
import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey;
+import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey_sslvserver_binding;
+import com.citrix.netscaler.nitro.resource.config.ssl.sslcertlink;
import com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding;
import com.cloud.network.lb.LoadBalancingRule.LbSslCert;
+import com.cloud.utils.security.CertificateHelper;
import com.cloud.utils.ssh.SshHelper;
+import com.google.common.collect.Lists;
+import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.log4j.Logger;
import com.citrix.netscaler.nitro.exception.nitro_exception;
@@ -119,6 +127,7 @@ import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.ExecutionException;
import com.cloud.utils.net.NetUtils;
+import org.bouncycastle.openssl.PEMWriter;
class NitroError {
static final int NS_RESOURCE_EXISTS = 273;
@@ -664,25 +673,61 @@ public class NetscalerResource implements ServerResource {
}
-
- if(sslCert != null && lbProtocol.equals(NetUtils.SSL_PROTO)) {
- if ( sslCert.isRevoked() ){
+ if (sslCert != null && lbProtocol.equalsIgnoreCase(NetUtils.SSL_PROTO)) {
+ if (sslCert.isRevoked()) {
deleteCert = true;
} else{
- String certName = generateSslCertName(srcIp, srcPort);
- String keyName = generateSslKeyName(srcIp, srcPort);
- String certKeyName = generateSslCertKeyName(srcIp, srcPort);
+ // If there is a chain, that should go first to the NS
+
+ String previousCertKeyName = null;
+
+ if ( sslCert.getChain() != null ) {
+ List<Certificate> chainList = CertificateHelper.parseChain(sslCert.getChain());
+ // go from ROOT to intermediate CAs
+ for ( Certificate intermediateCert : Lists.reverse(chainList)){
+
+ String fingerPrint=CertificateHelper.generateFingerPrint(intermediateCert);
+ String intermediateCertKeyName = generateSslCertKeyName(fingerPrint);
+ String intermediateCertFileName = intermediateCertKeyName + ".pem";
+
+ if (! SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName)) {
+ byte[] certData= intermediateCert.getEncoded();
+ StringWriter textWriter = new StringWriter();
+ PEMWriter pemWriter = new PEMWriter(textWriter);
+ pemWriter.writeObject(intermediateCert);
+ pemWriter.flush();
- if ( SSL.isSslCertKeyPresent(_netscalerService, certKeyName)){
- SSL.deleteSslCertKey(_netscalerService, certKeyName);
+ SSL.uploadCert(_ip, _username, _password, intermediateCertFileName, textWriter.toString().getBytes());
+ SSL.createSslCertKey(_netscalerService, intermediateCertFileName, null, intermediateCertKeyName, null);
+ }
+
+ if ( previousCertKeyName != null && ! SSL.certLinkExists(_netscalerService, intermediateCertKeyName, previousCertKeyName)){
+ SSL.linkCerts(_netscalerService, intermediateCertKeyName, previousCertKeyName);
+ }
+
+ previousCertKeyName = intermediateCertKeyName;
+ }
}
+ String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+ String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+ String certKeyName = generateSslCertKeyName(sslCert.getFingerprint());
- SSL.uploadCert(_ip, _username, _password, certName, sslCert.getCert().getBytes());
- SSL.uploadKey(_ip, _username, _password, keyName, sslCert.getKey().getBytes());
+ ByteArrayOutputStream certDataStream = new ByteArrayOutputStream( );
+ certDataStream.write(sslCert.getCert().getBytes());
+
+ if (! SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) {
+
+ SSL.uploadCert(_ip, _username, _password, certFilename, certDataStream.toByteArray());
+ SSL.uploadKey(_ip, _username, _password, keyFilename, sslCert.getKey().getBytes());
+ SSL.createSslCertKey(_netscalerService, certFilename, keyFilename, certKeyName, sslCert.getPassword());
+ }
+
+ if (previousCertKeyName != null && ! SSL.certLinkExists(_netscalerService, certKeyName, previousCertKeyName)){
+ SSL.linkCerts(_netscalerService, certKeyName, previousCertKeyName);
+ }
- SSL.createSslCertKey(_netscalerService, certName, keyName, certKeyName, sslCert.getPassword());
SSL.bindCertKeyToVserver(_netscalerService, certKeyName, nsVirtualServerName);
}
@@ -773,18 +818,50 @@ public class NetscalerResource implements ServerResource {
}
if ( sslCert != null && deleteCert){
- String certName = generateSslCertName(srcIp, srcPort);
- String keyName = generateSslKeyName(srcIp, srcPort);
- String certKeyName = generateSslCertKeyName(srcIp, srcPort);
+ String certFilename = generateSslCertName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+ String keyFilename = generateSslKeyName(sslCert.getFingerprint()) + ".pem"; //netscaler uses ".pem" format for "bundle" files
+ String certKeyName = generateSslCertKeyName(sslCert.getFingerprint());
// unbind before deleting
- if ( nsVirtualServerExists(nsVirtualServerName) ){
+ if (nsVirtualServerExists(nsVirtualServerName) &&
+ SSL.isSslCertKeyPresent(_netscalerService, certKeyName) &&
+ SSL.isBoundToVserver(_netscalerService, certKeyName, nsVirtualServerName)) {
SSL.unbindCertKeyFromVserver(_netscalerService, certKeyName, nsVirtualServerName);
}
- SSL.deleteSslCertKey(_netscalerService, certKeyName);
- SSL.deleteCertFile(_ip, _username, _password, certName);
- SSL.deleteKeyFile(_ip, _username, _password, keyName);
+ if (SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) {
+
+ SSL.deleteSslCertKey(_netscalerService, certKeyName);
+ SSL.deleteCertFile(_ip, _username, _password, certFilename);
+ SSL.deleteKeyFile(_ip, _username, _password, keyFilename);
+ }
+
+
+ /*
+ * Check and delete intermediate certs:
+ * we can delete an intermediate cert if no other
+ * cert references it as the athority
+ */
+
+ if ( sslCert.getChain() != null ) {
+ List<Certificate> chainList = CertificateHelper.parseChain(sslCert.getChain());
+ //go from intermediate CAs to ROOT
+ for ( Certificate intermediateCert : chainList){
+
+ String fingerPrint=CertificateHelper.generateFingerPrint(intermediateCert);
+ String intermediateCertKeyName = generateSslCertKeyName(fingerPrint);
+ String intermediateCertFileName = intermediateCertKeyName + ".pem";
+
+ if (SSL.isSslCertKeyPresent(_netscalerService, intermediateCertKeyName) &&
+ ! SSL.isCaforCerts(_netscalerService, intermediateCertKeyName)) {
+ SSL.deleteSslCertKey(_netscalerService, intermediateCertKeyName);
+ SSL.deleteCertFile(_ip, _username, _password, intermediateCertFileName);
+ }else {
+ break;// if this cert has another certificate as a child then stop at this point because we need the whole chain
+ }
+
+ }
+ }
}
}
@@ -1737,7 +1814,7 @@ public class NetscalerResource implements ServerResource {
return false;
}
- private static void deleteSslCertKey(nitro_service ns, String certKeyName) throws ExecutionException {
+ private static void deleteSslCertKey(nitro_service ns, String certKeyName) throws ExecutionException {
try {
sslcertkey certkey = new sslcertkey();
@@ -1752,21 +1829,23 @@ public class NetscalerResource implements ServerResource {
}
- private static void deleteCertFile(String nsIp, String username, String password, String certName) throws Exception {
- SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + certName);
+ private static void deleteCertFile(String nsIp, String username, String password, String certFilename) throws Exception {
+ SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + certFilename);
}
- private static void deleteKeyFile(String nsIp, String username, String password, String keyName) throws Exception {
- SshHelper.sshExecute(nsIp,SSH_PORT,username,null,password,"shell rm " + SSL_CERT_PATH + keyName);
+ private static void deleteKeyFile(String nsIp, String username, String password, String keyFilename) throws Exception {
+ SshHelper.sshExecute(nsIp, SSH_PORT, username, null, password, "shell rm " + SSL_CERT_PATH + keyFilename);
}
- private static void createSslCertKey(nitro_service ns, String certName, String keyName, String certKeyName, String password) throws ExecutionException {
+ private static void createSslCertKey(nitro_service ns, String certFilename, String keyFilename, String certKeyName, String password) throws ExecutionException {
s_logger.debug("Adding cert to netscaler");
try {
sslcertkey certkey = new sslcertkey();
certkey.set_certkey(certKeyName);
- certkey.set_cert(SSL_CERT_PATH + certName);
- certkey.set_key(SSL_CERT_PATH + keyName);
+ certkey.set_cert(SSL_CERT_PATH + certFilename);
+
+ if ( keyFilename != null )
+ certkey.set_key(SSL_CERT_PATH + keyFilename);
if( password != null ) {
certkey.set_passplain(password);
@@ -1832,19 +1911,18 @@ public class NetscalerResource implements ServerResource {
}
-
- private static void uploadCert(String nsIp, String user, String password, String certName, byte[] certData) throws ExecutionException {
+ private static void uploadCert(String nsIp, String user, String password, String certFilename, byte[] certData) throws ExecutionException {
try {
- SshHelper.scpTo(nsIp,SSH_PORT,user,null,password, SSL_CERT_PATH, certData, certName, null);
+ SshHelper.scpTo(nsIp,SSH_PORT,user,null,password, SSL_CERT_PATH, certData, certFilename, null);
} catch (Exception e){
throw new ExecutionException("Failed to copy private key to device " + e.getMessage());
}
}
- private static void uploadKey(String nsIp, String user, String password, String keyName, byte[] keyData) throws ExecutionException {
+ private static void uploadKey(String nsIp, String user, String password, String keyFilename, byte[] keyData) throws ExecutionException {
try {
- SshHelper.scpTo(nsIp, SSH_PORT, user, null, password, SSL_CERT_PATH, keyData, keyName, null);
- } catch (Exception e){
+ SshHelper.scpTo(nsIp, SSH_PORT, user, null, password, SSL_CERT_PATH, keyData, keyFilename, null);
+ } catch (Exception e) {
throw new ExecutionException("Failed to copy private key to device " + e.getMessage());
}
}
@@ -1853,7 +1931,7 @@ public class NetscalerResource implements ServerResource {
private static void enableSslFeature(nitro_service ns) throws ExecutionException {
try {
base_response result = ns.enable_features(new String[]{"SSL"});
- if( result.errorcode != 0 )
+ if (result.errorcode != 0)
throw new ExecutionException("Unable to enable SSL on LB");
} catch (nitro_exception e){
throw new ExecutionException("Failed to enable ssl feature on load balancer due to " + e.getMessage());
@@ -1880,7 +1958,80 @@ public class NetscalerResource implements ServerResource {
}
}
+ public static boolean certLinkExists(nitro_service ns, String userCertName, String caCertName) throws ExecutionException {
+ try {
+ // check if there is a link from userCertName to caCertName
+
+ sslcertkey userCert = sslcertkey.get(ns,userCertName);
+ String nsCaCert = userCert.get_linkcertkeyname();
+ if (nsCaCert != null && nsCaCert.equals(caCertName))
+ return true;
+
+ } catch (nitro_exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+ } catch (Exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+ }
+ return false;
+ }
+
+ public static void linkCerts(nitro_service ns, String userCertName, String caCertName) throws ExecutionException {
+ try {
+
+ // the assumption is that that both userCertName and caCertName are present on NS
+
+ sslcertkey caCert = sslcertkey.get(ns, caCertName);
+ sslcertkey userCert = sslcertkey.get(ns, userCertName);
+
+ sslcertkey linkResource = new sslcertkey();
+
+ // link user cert to CA cert
+ linkResource.set_certkey(userCert.get_certkey());
+ linkResource.set_linkcertkeyname(caCert.get_certkey());
+ sslcertkey.link(ns, linkResource);
+
+ } catch (nitro_exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+ } catch (Exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+ }
+
+ }
+
+ public static boolean isCaforCerts(nitro_service ns, String caCertName) throws ExecutionException {
+ // check if this certificate serves as a CA for other certificates
+ try {
+ sslcertlink[] childLinks = sslcertlink.get_filtered(ns,"linkcertkeyname:" + caCertName);
+ if(childLinks != null && childLinks.length > 0){
+ return true;
+ }
+
+ } catch (nitro_exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+ } catch (Exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+ }
+ return false;
+
+ }
+
+ public static boolean isBoundToVserver(nitro_service ns, String certKeyName, String nsVirtualServerName) throws ExecutionException {
+ try {
+
+ sslcertkey_sslvserver_binding[] cert_vs_binding = sslcertkey_sslvserver_binding.get_filtered(ns, certKeyName, "vservername:" + nsVirtualServerName);
+ if(cert_vs_binding != null && cert_vs_binding.length > 0){
+ return true;
+ }
+
+ } catch (nitro_exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer to " + e.getMessage());
+ } catch (Exception e) {
+ throw new ExecutionException("Failed to check cert link on load balancer due to " + e.getMessage());
+ }
+ return false;
+
+ }
}
@@ -3624,16 +3775,22 @@ public class NetscalerResource implements ServerResource {
return counterName.replace(' ', '_');
}
- private String generateSslCertName(String srcIp, long srcPort) {
+ private String generateSslCertName(String fingerPrint) {
// maximum length supported by NS is 31
- return genObjectName("Cloud-Cert", srcIp, srcPort);
+ // the first 20 characters of the SHA-1 checksum are the unique id
+ String uniqueId = fingerPrint.replace(":","").substring(0,20);
+
+ return genObjectName("Cloud-Cert", uniqueId);
}
- private String generateSslKeyName(String srcIp, long srcPort) {
- return genObjectName("Cloud-Key", srcIp, srcPort);
+ private String generateSslKeyName(String fingerPrint) {
+ String uniqueId = fingerPrint.replace(":","").substring(0,20);
+ return genObjectName("Cloud-Key", uniqueId);
}
- private String generateSslCertKeyName(String srcIp, long srcPort) {
- return genObjectName("Cloud-CertKey", srcIp, srcPort);
+
+ private String generateSslCertKeyName(String fingerPrint){
+ String uniqueId = fingerPrint.replace(":","").substring(0,20);
+ return genObjectName("Cloud-Cert", uniqueId);
}
private String genObjectName(Object... args) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fb89a2d8/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
index a1650e0..bd58e39 100755
--- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
+++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java
@@ -1121,8 +1121,7 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
return null;
}
- return new LbSslCert(certVO.getCertificate(), certVO.getKey(),
- certVO.getChain(), certVO.getPassword(), lbCertMap.isRevoke());
+ return new LbSslCert(certVO.getCertificate(), certVO.getKey(), certVO.getPassword(), certVO.getChain(), certVO.getFingerPrint(), lbCertMap.isRevoke());
}
@Override
@@ -1174,11 +1173,6 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
LoadBalancerCertMapVO certMap = new LoadBalancerCertMapVO(lbRuleId,certId,false);
_lbCertMapDao.persist(certMap);
applyLoadBalancerConfig(loadBalancer.getId());
- /*s_logger.warn("Failed to apply Ssl Cert to LB " + loadBalancer.getId());
- CloudRuntimeException ex = new CloudRuntimeException(
- "Failed to apply Ssl Cert to LB " + loadBalancer.getId());
- ex.addProxyObject(loadBalancer.getUuid(), "loadBalancerId");
- throw ex;*/
success = true;
} catch (ResourceUnavailableException e) {
if (isRollBackAllowedForProvider(loadBalancer)) {
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fb89a2d8/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java
index 74adb37..b699fc5 100644
--- a/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java
+++ b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java
@@ -16,14 +16,60 @@
// under the License.
package org.apache.cloudstack.network.lb;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertStore;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+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.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.ejb.Local;
+import javax.inject.Inject;
+
import com.cloud.event.ActionEvent;
import com.cloud.event.EventTypes;
-import com.cloud.network.dao.*;
+import com.cloud.network.dao.LoadBalancerCertMapDao;
+import com.cloud.network.dao.LoadBalancerCertMapVO;
+import com.cloud.network.dao.LoadBalancerVO;
+import com.cloud.network.dao.SslCertDao;
+import com.cloud.network.dao.SslCertVO;
import com.cloud.network.lb.CertService;
import com.cloud.network.rules.LoadBalancer;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.db.EntityManager;
import com.cloud.utils.exception.CloudRuntimeException;
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.openssl.PEMReader;
+import org.bouncycastle.openssl.PasswordFinder;
import org.apache.cloudstack.api.command.user.loadbalancer.DeleteSslCertCmd;
import org.apache.cloudstack.api.command.user.loadbalancer.ListSslCertsCmd;
@@ -37,30 +83,6 @@ import com.cloud.utils.db.DB;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.context.CallContext;
-import org.apache.commons.io.IOUtils;
-import org.apache.log4j.Logger;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openssl.PEMReader;
-import org.bouncycastle.openssl.PasswordFinder;
-
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.ejb.Local;
-import javax.inject.Inject;
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.security.*;
-import java.security.cert.*;
-import java.security.cert.Certificate;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
@Local(value = {CertService.class})
public class CertServiceImpl implements CertService {
@@ -68,10 +90,14 @@ public class CertServiceImpl implements CertService {
private static final Logger s_logger = Logger.getLogger(CertServiceImpl.class);
@Inject AccountManager _accountMgr;
- @Inject AccountDao _accountDao;
- @Inject SslCertDao _sslCertDao;
- @Inject LoadBalancerCertMapDao _lbCertDao;
- @Inject EntityManager _entityMgr;
+ @Inject
+ AccountDao _accountDao;
+ @Inject
+ SslCertDao _sslCertDao;
+ @Inject
+ LoadBalancerCertMapDao _lbCertDao;
+ @Inject
+ EntityManager _entityMgr;
@@ -92,6 +118,7 @@ public class CertServiceImpl implements CertService {
validate(cert, key, password, chain);
s_logger.debug("Certificate Validation succeeded");
+
String fingerPrint = generateFingerPrint(parseCertificate(cert));
Long accountId = CallContext.current().getCallingAccount().getId();
@@ -365,14 +392,17 @@ public class CertServiceImpl implements CertService {
params = new PKIXBuilderParameters(anchors, target);
params.setRevocationEnabled(false);
params.addCertStore(CertStore.getInstance("Collection", new CollectionCertStoreParameters(certs)));
- CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
+ CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC");
builder.build(params);
+
} catch (InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException("Invalid certificate chain", e);
} catch (CertPathBuilderException e) {
throw new IllegalArgumentException("Invalid certificate chain", e);
} catch (NoSuchAlgorithmException e) {
throw new IllegalArgumentException("Invalid certificate chain", e);
+ } catch (NoSuchProviderException e) {
+ throw new CloudRuntimeException("No provider for certificate validation", e);
}
}
@@ -485,4 +515,4 @@ public class CertServiceImpl implements CertService {
return password_requested;
}
}
-}
\ No newline at end of file
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/fb89a2d8/utils/src/com/cloud/utils/security/CertificateHelper.java
----------------------------------------------------------------------
diff --git a/utils/src/com/cloud/utils/security/CertificateHelper.java b/utils/src/com/cloud/utils/security/CertificateHelper.java
index 8344d72..e1edbbd 100644
--- a/utils/src/com/cloud/utils/security/CertificateHelper.java
+++ b/utils/src/com/cloud/utils/security/CertificateHelper.java
@@ -20,21 +20,28 @@ import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.StringReader;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
+import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
import java.util.List;
+import com.cloud.utils.exception.CloudRuntimeException;
import org.apache.commons.codec.binary.Base64;
import com.cloud.utils.Ternary;
+import org.bouncycastle.openssl.PEMReader;
public class CertificateHelper {
public static byte[] buildAndSaveKeystore(String alias, String cert, String privateKey, String storePassword) throws KeyStoreException, CertificateException,
@@ -105,4 +112,53 @@ public class CertificateHelper {
PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec (Base64.decodeBase64(base64EncodedKeyContent));
return kf.generatePrivate (keysp);
}
+
+ public static List<Certificate> parseChain(String chain) throws IOException {
+
+ List<Certificate> certs = new ArrayList<Certificate>();
+ PEMReader reader = new PEMReader(new StringReader(chain));
+
+ Certificate crt = null;
+
+ while ((crt = (Certificate)reader.readObject()) != null) {
+ if (crt instanceof X509Certificate) {
+ certs.add(crt);
+ }
+ }
+ if (certs.size() == 0)
+ throw new IllegalArgumentException("Unable to decode certificate chain");
+
+ return certs;
+ }
+
+ public static String generateFingerPrint(Certificate cert) {
+
+ final char[] HEX = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ StringBuilder buffer = new StringBuilder(60);
+ try {
+
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ byte[] data = md.digest(cert.getEncoded());
+
+ for (int i = 0; i < data.length; i++) {
+ if (buffer.length() > 0) {
+ buffer.append(":");
+ }
+
+ buffer.append(HEX[(0xF0 & data[i]) >>> 4]);
+ buffer.append(HEX[0x0F & data[i]]);
+ }
+
+ } catch (CertificateEncodingException e) {
+ throw new CloudRuntimeException("Bad certificate encoding");
+ } catch (NoSuchAlgorithmException e) {
+ throw new CloudRuntimeException("Bad certificate algorithm");
+ }
+
+ return buffer.toString();
+ }
+
+
+
}