diff --git a/.gitignore b/.gitignore index dab1b3fc0b9..f50f2e3c9e6 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 diff --git a/api/src/com/cloud/network/lb/LoadBalancingRule.java b/api/src/com/cloud/network/lb/LoadBalancingRule.java index 4b2f9c4237b..be69332ea78 100644 --- a/api/src/com/cloud/network/lb/LoadBalancingRule.java +++ b/api/src/com/cloud/network/lb/LoadBalancingRule.java @@ -437,13 +437,15 @@ public class LoadBalancingRule { private String key; private String password = null; private String chain = null; + private String fingerprint; 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; } @@ -464,6 +466,10 @@ public class LoadBalancingRule { return chain; } + public String getFingerprint() { + return fingerprint; + } + public boolean isRevoked() { return revoked; } diff --git a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java index 99354c5dbc2..cab001bf922 100644 --- a/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java +++ b/engine/schema/src/com/cloud/network/dao/SslCertDaoImpl.java @@ -33,7 +33,7 @@ public class SslCertDaoImpl extends GenericDaoBase implements S listByAccountId = createSearchBuilder(); listByAccountId.and("accountId", listByAccountId.entity().getAccountId(), SearchCriteria.Op.EQ); listByAccountId.done(); - } + } @Override public List listByAccountId(Long accountId) { 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 7dac9a008aa..e8272986c99 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; @@ -25,6 +28,15 @@ 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; @@ -61,8 +73,6 @@ import com.citrix.netscaler.nitro.resource.config.ns.nshardware; import com.citrix.netscaler.nitro.resource.config.ns.nsip; import com.citrix.netscaler.nitro.resource.config.ns.nstimer; import com.citrix.netscaler.nitro.resource.config.ns.nstimer_autoscalepolicy_binding; -import com.citrix.netscaler.nitro.resource.config.ssl.sslcertkey; -import com.citrix.netscaler.nitro.resource.config.ssl.sslvserver_sslcertkey_binding; import com.citrix.netscaler.nitro.resource.stat.lb.lbvserver_stats; import com.citrix.netscaler.nitro.service.nitro_service; import com.citrix.netscaler.nitro.util.filtervalue; @@ -111,7 +121,6 @@ import com.cloud.agent.api.to.LoadBalancerTO.StickinessPolicyTO; import com.cloud.agent.api.to.StaticNatRuleTO; import com.cloud.host.Host; import com.cloud.host.Host.Type; -import com.cloud.network.lb.LoadBalancingRule.LbSslCert; import com.cloud.network.rules.LbStickinessMethod.StickinessMethodType; import com.cloud.resource.ServerResource; import com.cloud.serializer.GsonHelper; @@ -119,7 +128,7 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.exception.ExecutionException; import com.cloud.utils.net.NetUtils; -import com.cloud.utils.ssh.SshHelper; +import org.bouncycastle.openssl.PEMWriter; class NitroError { static final int NS_RESOURCE_EXISTS = 273; @@ -665,23 +674,61 @@ public class NetscalerResource implements ServerResource { } - if (sslCert != null && lbProtocol.equals(NetUtils.SSL_PROTO)) { + 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 - if (SSL.isSslCertKeyPresent(_netscalerService, certKeyName)) { - SSL.deleteSslCertKey(_netscalerService, certKeyName); + String previousCertKeyName = null; + + if ( sslCert.getChain() != null ) { + List 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(); + + 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; + } } - SSL.uploadCert(_ip, _username, _password, certName, sslCert.getCert().getBytes()); - SSL.uploadKey(_ip, _username, _password, keyName, sslCert.getKey().getBytes()); + 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()); + + 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); } @@ -778,18 +825,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 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 + } + + } + } } } @@ -1718,7 +1797,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(); @@ -1733,21 +1812,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); @@ -1813,17 +1894,17 @@ 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); - } catch (Exception e) { + 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); + 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()); } @@ -1831,7 +1912,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"}); + base_response result = ns.enable_features(new String[]{"SSL"}); if (result.errorcode != 0) throw new ExecutionException("Unable to enable SSL on LB"); } catch (nitro_exception e) { @@ -1859,6 +1940,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; + + } } private void enableVPXInterfaces(String publicIf, String privateIf, ns ns_obj) { @@ -3588,17 +3743,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) { diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index a2eba0754b3..501bb14c193 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -1074,7 +1074,7 @@ public class LoadBalancingRulesManagerImpl 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 @@ -1124,11 +1124,6 @@ public class LoadBalancingRulesManagerImpl 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)) { diff --git a/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java index 17f88bdd4aa..ae3d17939de 100644 --- a/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java +++ b/server/src/org/apache/cloudstack/network/lb/CertServiceImpl.java @@ -25,6 +25,7 @@ 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; @@ -115,6 +116,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(); @@ -379,14 +381,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); } } diff --git a/utils/src/com/cloud/utils/security/CertificateHelper.java b/utils/src/com/cloud/utils/security/CertificateHelper.java index e8d20b0e9ce..5d8f6ad310d 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, @@ -106,4 +113,53 @@ public class CertificateHelper { PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec(Base64.decodeBase64(base64EncodedKeyContent)); return kf.generatePrivate(keysp); } + + public static List parseChain(String chain) throws IOException { + + List certs = new ArrayList(); + 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(); + } + + + }