From 4dd1fc92fe3536518a77e1d69cbc6ba39d367604 Mon Sep 17 00:00:00 2001 From: Edison Su Date: Thu, 9 Feb 2012 11:50:43 -0800 Subject: [PATCH] add cert chain in db, and also open the api to upload a cert chain --- .../agent/api/SecStorageSetupCommand.java | 44 +++- .../commands/UploadCustomCertificateCmd.java | 16 +- console-proxy/scripts/config_ssl.sh | 106 ++++++++-- .../ConsoleProxySecureServerFactoryImpl.java | 6 +- .../resource/NfsSecondaryStorageResource.java | 65 +++++- .../consoleproxy/ConsoleProxyManagerImpl.java | 200 ++++++++++++------ .../src/com/cloud/keystore/KeystoreDao.java | 5 + .../com/cloud/keystore/KeystoreDaoImpl.java | 41 ++++ .../com/cloud/keystore/KeystoreManager.java | 4 + .../cloud/keystore/KeystoreManagerImpl.java | 50 ++++- server/src/com/cloud/keystore/KeystoreVO.java | 11 + .../cloud/server/ManagementServerImpl.java | 22 +- .../SecondaryStorageManagerImpl.java | 15 +- .../cloud/upgrade/dao/Upgrade2213to2214.java | 170 +++++++++++++++ setup/db/create-schema.sql | 3 +- setup/db/db/schema-2213to2214.sql | 4 +- .../utils/security/CertificateHelper.java | 30 +++ 17 files changed, 697 insertions(+), 95 deletions(-) diff --git a/api/src/com/cloud/agent/api/SecStorageSetupCommand.java b/api/src/com/cloud/agent/api/SecStorageSetupCommand.java index 73a9d4e350b..aac0f4366aa 100644 --- a/api/src/com/cloud/agent/api/SecStorageSetupCommand.java +++ b/api/src/com/cloud/agent/api/SecStorageSetupCommand.java @@ -17,16 +17,51 @@ */ package com.cloud.agent.api; +import com.cloud.agent.api.LogLevel.Log4jLevel; + public class SecStorageSetupCommand extends Command { private String secUrl; + private Certificates certs; + + public static class Certificates { + @LogLevel(Log4jLevel.Off) + private String privKey; + @LogLevel(Log4jLevel.Off) + private String privCert; + @LogLevel(Log4jLevel.Off) + private String certChain; + + public Certificates() { + + } + + public Certificates(String prvKey, String privCert, String certChain) { + this.privKey = prvKey; + this.privCert = privCert; + this.certChain = certChain; + } + + public String getPrivKey() { + return this.privKey; + } + + public String getPrivCert() { + return this.privCert; + } + + public String getCertChain() { + return this.certChain; + } + } public SecStorageSetupCommand() { super(); } - - public SecStorageSetupCommand(String secUrl) { + + public SecStorageSetupCommand(String secUrl, Certificates certs) { super(); this.secUrl = secUrl; + this.certs = certs; } @Override @@ -37,8 +72,13 @@ public class SecStorageSetupCommand extends Command { public String getSecUrl() { return secUrl; } + + public Certificates getCerts() { + return this.certs; + } public void setSecUrl(String secUrl) { this.secUrl = secUrl; + } } diff --git a/api/src/com/cloud/api/commands/UploadCustomCertificateCmd.java b/api/src/com/cloud/api/commands/UploadCustomCertificateCmd.java index 5511a54d1b4..e94e31ea734 100644 --- a/api/src/com/cloud/api/commands/UploadCustomCertificateCmd.java +++ b/api/src/com/cloud/api/commands/UploadCustomCertificateCmd.java @@ -37,8 +37,14 @@ public class UploadCustomCertificateCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.CERTIFICATE,type=CommandType.STRING,required=true,description="the custom cert to be uploaded") private String certificate; + + @Parameter(name=ApiConstants.ID,type=CommandType.INTEGER,required=false,description="the custom cert id in the chain") + private Integer index; + + @Parameter(name=ApiConstants.NAME,type=CommandType.STRING,required=false,description="the alias of the certificate") + private String alias; - @Parameter(name=ApiConstants.PRIVATE_KEY,type=CommandType.STRING,required=true,description="the private key for the certificate") + @Parameter(name=ApiConstants.PRIVATE_KEY,type=CommandType.STRING,required=false,description="the private key for the certificate") private String privateKey; @Parameter(name=ApiConstants.DOMAIN_SUFFIX,type=CommandType.STRING,required=true,description="DNS domain suffix that the certificate is granted for") @@ -55,6 +61,14 @@ public class UploadCustomCertificateCmd extends BaseAsyncCmd { public String getDomainSuffix() { return domainSuffix; } + + public Integer getCertIndex() { + return index; + } + + public String getAlias() { + return alias; + } @Override public String getEventType() { diff --git a/console-proxy/scripts/config_ssl.sh b/console-proxy/scripts/config_ssl.sh index 754631b6139..70021ef4f44 100755 --- a/console-proxy/scripts/config_ssl.sh +++ b/console-proxy/scripts/config_ssl.sh @@ -19,7 +19,12 @@ # along with this program. If not, see . # - +help() { + printf " -c use customized key/cert\n" + printf " -k path of private key\n" + printf " -p path of certificate of public key\n" + printf " -t path of certificate chain\n" +} config_httpd_conf() { @@ -46,33 +51,102 @@ config_apache2_conf() { sed -i -e "s/Listen .*:80/Listen $ip:80/g" /etc/apache2/ports.conf sed -i -e "s/Listen .*:443/Listen $ip:443/g" /etc/apache2/ports.conf sed -i -e "s/NameVirtualHost .*:80/NameVirtualHost $ip:80/g" /etc/apache2/ports.conf - sed -i 's/ssl-cert-snakeoil.key/realhostip.key/' /etc/apache2/sites-available/default-ssl - sed -i 's/ssl-cert-snakeoil.pem/realhostip.crt/' /etc/apache2/sites-available/default-ssl + sed -i 's/ssl-cert-snakeoil.key/cert_apache.key/' /etc/apache2/sites-available/default-ssl + sed -i 's/ssl-cert-snakeoil.pem/cert_apache.crt/' /etc/apache2/sites-available/default-ssl } copy_certs() { local certdir=$(dirname $0)/certs local mydir=$(dirname $0) - if [ -d $certdir ] && [ -f $certdir/realhostip.key ] && [ -f $certdir/realhostip.crt ] ; then - mkdir -p /etc/httpd/ssl/keys && mkdir -p /etc/httpd/ssl/certs && cp $certdir/realhostip.key /etc/httpd/ssl/keys && cp $certdir/realhostip.crt /etc/httpd/ssl/certs + if [ -d $certdir ] && [ -f $customPrivKey ] && [ -f $customPrivCert ] ; then + mkdir -p /etc/httpd/ssl/keys && mkdir -p /etc/httpd/ssl/certs && cp $customprivKey /etc/httpd/ssl/keys && cp $customPrivCert /etc/httpd/ssl/certs return $? fi + if [ ! -z customCertChain ] && [ -f $customCertChain ] ; then + cp $customCertChain /etc/httpd/ssl/certs + fi return 1 } copy_certs_apache2() { local certdir=$(dirname $0)/certs local mydir=$(dirname $0) - if [ -d $certdir ] && [ -f $certdir/realhostip.key ] && [ -f $certdir/realhostip.crt ] ; then - cp $certdir/realhostip.key /etc/ssl/private/ && cp $certdir/realhostip.crt /etc/ssl/certs/ - return $? + if [ -f $customPrivKey ] && [ -f $customPrivCert ] ; then + cp $customPrivKey /etc/ssl/private/cert_apache.key && cp $customPrivCert /etc/ssl/certs/cert_apache.crt fi - return 1 + if [ ! -z "$customCertChain" ] && [ -f "$customCertChain" ] ; then + cp $customCertChain /etc/ssl/certs/cert_apache_chain.crt + fi + return 0 } -if [ $# -ne 2 ] ; then - echo $"Usage: `basename $0` ipaddr servername " - exit 0 + +cflag= +cpkflag= +cpcflag= +cccflag= +customPrivKey=$(dirname $0)/certs/realhostip.key +customPrivCert=$(dirname $0)/certs/realhostip.crt +customCertChain= +publicIp= +hostName= +while getopts 'i:h:k:p:t:c' OPTION +do + case $OPTION in + c) cflag=1 + ;; + k) cpkflag=1 + customPrivKey="$OPTARG" + ;; + p) cpcflag=1 + customPrivCert="$OPTARG" + ;; + t) cccflag=1 + customCertChain="$OPTARG" + ;; + i) publicIp="$OPTARG" + ;; + h) hostName="$OPTARG" + ;; + ?) help + ;; + esac +done + + +if [ -z "$publicIp" ] || [ -z "$hostName" ] +then + help + exit 1 +fi + +if [ "$cflag" == "1" ] +then + if [ "$cpkflag$cpcflag" != "11" ] + then + help + exit 1 + fi + if [ ! -f "$customPrivKey" ] + then + printf "priviate key file is not exist\n" + exit 2 + fi + + if [ ! -f "$customPrivCert" ] + then + printf "public certificate is not exist\n" + exit 3 + fi + + if [ "$cccflag" == "1" ] + then + if [ ! -f "$customCertChain" ] + then + printf "certificate chain is not exist\n" + exit 4 + fi + fi fi if [ -d /etc/apache2 ] @@ -90,7 +164,11 @@ fi if [ -d /etc/apache2 ] then - config_apache2_conf $1 $2 + config_apache2_conf $publicIp $hostName + /etc/init.d/apache2 stop + /etc/init.d/apache2 start else - config_httpd_conf $1 $2 + config_httpd_conf $publicIp $hostName fi + + diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java index e5aa7af1d91..42e5787c895 100644 --- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java +++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxySecureServerFactoryImpl.java @@ -50,7 +50,7 @@ public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFa public void init(byte[] ksBits, String ksPassword) { s_logger.info("Start initializing SSL"); - // if(ksBits == null) { + if(ksBits == null) { try { s_logger.info("Initializing SSL from built-in default certificate"); @@ -76,7 +76,7 @@ public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFa } catch (Exception ioe) { s_logger.error(ioe.toString(), ioe); } -/* + } else { char[] passphrase = ksPassword != null ? ksPassword.toCharArray() : null; try { @@ -100,7 +100,7 @@ public class ConsoleProxySecureServerFactoryImpl implements ConsoleProxyServerFa s_logger.error("Unable to init factory due to exception ", e); } } -*/ + } public HttpServer createHttpServerInstance(int port) throws IOException { diff --git a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java index 57068b18ecd..46a31055296 100755 --- a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java +++ b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java @@ -17,8 +17,10 @@ */ package com.cloud.storage.resource; +import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; @@ -52,6 +54,7 @@ import com.cloud.agent.api.ReadyCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand; import com.cloud.agent.api.SecStorageSetupAnswer; import com.cloud.agent.api.SecStorageSetupCommand; +import com.cloud.agent.api.SecStorageSetupCommand.Certificates; import com.cloud.agent.api.StartupSecondaryStorageCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand.PortConfig; import com.cloud.agent.api.SecStorageVMSetupCommand; @@ -208,6 +211,38 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S return new Answer(cmd, true, checksum); } + private void configCerts(Certificates certs) { + if (certs == null) { + configureSSL(); + } else { + String prvKey = certs.getPrivKey(); + String pubCert = certs.getPrivCert(); + String certChain = certs.getCertChain(); + + try { + File prvKeyFile = File.createTempFile("prvkey", null); + String prvkeyPath = prvKeyFile.getAbsolutePath(); + BufferedWriter out = new BufferedWriter(new FileWriter(prvKeyFile)); + out.write(prvKey); + out.close(); + + File pubCertFile = File.createTempFile("pubcert", null); + String pubCertFilePath = pubCertFile.getAbsolutePath(); + + out = new BufferedWriter(new FileWriter(pubCertFile)); + out.write(pubCert); + out.close(); + + configureSSL(prvkeyPath, pubCertFilePath, null); + + prvKeyFile.delete(); + pubCertFile.delete(); + + } catch (IOException e) { + s_logger.debug("Failed to config ssl: " + e.toString()); + } + } + } private Answer execute(SecStorageSetupCommand cmd) { if (!_inSystemVM){ @@ -226,6 +261,9 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S String dir = UUID.nameUUIDFromBytes(nfsPath.getBytes()).toString(); String root = _parent + "/" + dir; mount(root, nfsPath); + + configCerts(cmd.getCerts()); + return new SecStorageSetupAnswer(dir); } catch (Exception e) { String msg = "GetRootDir for " + secUrl + " failed due to " + e.toString(); @@ -556,13 +594,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S } } - String useSsl = (String)params.get("sslcopy"); - if (useSsl != null) { - _sslCopy = Boolean.parseBoolean(useSsl); - if (_sslCopy) { - configureSSL(); - } - } + startAdditionalServices(); _params.put("install.numthreads", "50"); _params.put("secondary.storage.vm", "true"); @@ -639,8 +671,23 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S private void configureSSL() { Script command = new Script(_configSslScr); - command.add(_publicIp); - command.add(_hostname); + command.add("-i", _publicIp); + command.add("-h", _hostname); + String result = command.execute(); + if (result != null) { + s_logger.warn("Unable to configure httpd to use ssl"); + } + } + + private void configureSSL(String prvkeyPath, String prvCertPath, String certChainPath) { + Script command = new Script(_configSslScr); + command.add("-i", _publicIp); + command.add("-h", _hostname); + command.add("-k", prvkeyPath); + command.add("-p", prvCertPath); + if (certChainPath != null) { + command.add("-t", certChainPath); + } String result = command.execute(); if (result != null) { s_logger.warn("Unable to configure httpd to use ssl"); diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 8fa485be9a5..218016129ab 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -259,66 +259,142 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx + "fJ6GBCs1XgZLuhkKS8fPf+YmG2ZjHzYDjYoSx7paDXgEm+kbYIZdCK51lA0BUAjP\n" + "9ZMGhsu/PpAbh5U/DtcIqxY0xeqD4TeGsBzXg6uLhv+jKHDtXg5fYPe+z0n5DCEL\n" + "k0fLF4+i/pt9hVCz0QrZ28RUhXf825+EOL0Gw+Uzt+7RV2cCaJrlu4cDrDom2FRy\n" + "E8I=\n" + "-----END CERTIFICATE-----\n"; */ - private final String keyContent = - "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCGu5REMZSFQ6wD\n" + - "Fr7NPp9iibCYHZ6d1IV7s6Yvs6yvXmYw46c9JaJ8FN0NoHVzzDD2dELfpBxXRN7e\n" + - "q1rcP3ISDdDkhjngJoXEd2xaqgp0UxOS+AaamGG6sOleACn0XBF+XXaaD5vnFw7Y\n" + - "nDUyJioWR5KdTzVajLVkdEP3uPmJbRdveEu8HMZpwhZyY4uAcH5nHxMJEj/mkZtF\n" + - "ZJDi26ZjeonVOwnGm0NTbGCrfCneQEZC/SENua3BklHXc07zl3TrWu8xhrVWGRbc\n" + - "knw0VmGaPmehtuzL9WsieWGG4KH9G1LC2w2mbib64nSluBEcHRCKOT2aMzo2FonK\n" + - "AZkkIE53AgMBAAECggEAXLH3awd1eE47rRBcC1d3TtMOVUmjlFDf2WCbCJykRS88\n" + - "PYySxgX7iUTNZQ+tXxLv6M/KJpWBDiWK9EWOSJO6BmPNATy72tSGGcpUGPh+ItP5\n" + - "Vpcf7ALE0i3fENYqBz3Ep1zkOVBd4ZrCkxK9opgRQqzRWTtiqL7AGbHIBUoVHI+b\n" + - "Dk0bfl0936JpEMiFcI88KqckdFbY/cw+Uq7pRHPfUM5pB1AeMGqFVlqZbiDgMJm4\n" + - "GJRqXU8Qrue9UB6YypS9q7x9Q7sB/W3ghTLefYLrWVyeX417xcdKpaI7jo/KqT9F\n" + - "3m5uIphLe64HPLX50iWj9mIQ1vclsae3nIk/TObMcQKBgQC7FSgZdLdhxfPAC450\n" + - "EVM4Wmhiq0LmI63IbdIO+exsOQmOsCaGDNgWD8/YFSO+71dXRCB2WFUWg5G0Fl6w\n" + - "LKkQiSaNenJzT2NhL61+O4G2PPM3Sq1rlY0eB+8yq8tHxS1vO+zOcSdsUO+ES3FV\n" + - "E36cQMXixVnfvAdp+wUbkNZxyQKBgQC4XY9ZpSWnhIma/4HLF34tAZKCoVJAvHYk\n" + - "UpVIu9pixjQsmsEliTERvsWIfJQTpdsgkjkFHB3LzOsF2Wd2pXhBcMokLe8H9VNY\n" + - "MTi0i9zeZMV4V9UzRhgs9n41MAN3bgg0Pgt6W5qNvguEl5aQp9inwqyVmFS4NGit\n" + - "LNa8Kj7ePwKBgQCJ6LupoD96pMjdfediKk9VkFe4vJTRP+XghQw/G/8rfBROig2r\n" + - "7ZXxFXDa0iKKoraYztC7TLxUn2JuBbuBVTq/xMqVqnjqBdC1mMbk8grZgy6rSLJ0\n" + - "R0dCpwiuKrPsUS7/+4XCXOl50GPv+wktdPR1TM5TL7Xj1yEEABYwzuE1+QKBgHxy\n" + - "uybZ8VbogjJcMnKywvsCSrFez7TfAih2jkpwc3OlMubA94us1bCSw6fj39h7ZjTQ\n" + - "PykR15MQGbzzCYHvJAOYbPqK/wSyNrYbU5mbp1V/VERtlX5s3DjNkle4tz5Qybzp\n" + - "/Ll1SBhRpli0MnAmvHpRUEoSb22AAwCSeci+A33lAoGBAJNAVW8kE9ocXw3I4aac\n" + - "GI19ihoXr+8tRJilMCRQp4iFdi7acnek3/u0MaZ0ct8cVh9oMO+zVmTrpxJNTL6H\n" + - "He0z1VA4w/j4J5Z2P0KNLnKvRpayGWcf86YgSEmgU/ScwWzGL+cNgEKih74lSL4Z\n" + - "OK2Ayxxw3vbRyxQg6r1JUIKS\n"; + public static final String keyContent = + "-----BEGIN PRIVATE KEY-----\n" + + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ\n" + + "0+GgsybNHheU+JpL39LMTZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX\n" + + "1FIpOBGph9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/oCfTl\n" + + "XJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo2JUl8ekNLsOi8/cP\n" + + "tfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4j9cBpE+MfUE+35Dq121sTpsSgF85\n" + + "Mz+pVhn2S633AgMBAAECggEAH/Szd9RxbVADenCA6wxKSa3KErRyq1YN8ksJeCKMAj0FIt0caruE\n" + + "qO11DebWW8cwQu1Otl/cYI6pmg24/BBldMrp9IELX/tNJo+lhPpRyGAxxC0eSXinFfoASb8d+jJd\n" + + "Bd1mmemM6fSxqRlxSP4LrzIhjhR1g2CiyYuTsiM9UtoVKGyHwe7KfFwirUOJo3Mr18zUVNm7YqY4\n" + + "IVhOSq59zkH3ULBlYq4bG50jpxa5mNSCZ7IpafPY/kE/CbR+FWNt30+rk69T+qb5abg6+XGm+OAm\n" + + "bnQ18yZEqX6nJLk7Ch0cfA5orGgrTMOrM71wK7tBBDQ308kOxDGebx6j0qD36QKBgQDTRDr8kuhA\n" + + "9sUyKr9vk2DQCMpNvEeiwI3JRMqmmxpNAtg01aJ3Ya57vX5Fc+zcuV87kP6FM1xgpHQvnw5LWo2J\n" + + "s7ANwQcP8ricEW5zkZhSjI4ssMeAubmsHOloGxmLFYZqwx0JI7CWViGTLMcUlqKblmHcjeQDeDfP\n" + + "P1TaCItFmwKBgQCfHZwVvIcaDs5vxVpZ4ftvflIrW8qq0uOVK6QIf9A/YTGhCXl2qxxTg2A6+0rg\n" + + "ZqI7zKzUDxIbVv0KlgCbpHDC9d5+sdtDB3wW2pimuJ3p1z4/RHb4n/lDwXCACZl1S5l24yXX2pFZ\n" + + "wdPCXmy5PYkHMssFLNhI24pprUIQs66M1QKBgQDQwjAjWisD3pRXESSfZRsaFkWJcM28hdbVFhPF\n" + + "c6gWhwQLmTp0CuL2RPXcPUPFi6sN2iWWi3zxxi9Eyz+9uBn6AsOpo56N5MME/LiOnETO9TKb+Ib6\n" + + "rQtKhjshcv3XkIqFPo2XdVvOAgglPO7vajX91iiXXuH7h7RmJud6l0y/lwKBgE+bi90gLuPtpoEr\n" + + "VzIDKz40ED5bNYHT80NNy0rpT7J2GVN9nwStRYXPBBVeZq7xCpgqpgmO5LtDAWULeZBlbHlOdBwl\n" + + "NhNKKl5wzdEUKwW0yBL1WSS5PQgWPwgARYP25/ggW22sj+49WIo1neXsEKPGWObk8e050f1fTt92\n" + + "Vo1lAoGAb1gCoyBCzvi7sqFxm4V5oapnJeiQQJFjhoYWqGa26rQ+AvXXNuBcigIeDXNJPctSF0Uc\n" + + "p11KbbCgiruBbckvM1vGsk6Sx4leRk+IFHRpJktFUek4o0eUg0shOsyyvyet48Dfg0a8FvcxROs0\n" + + "gD+IYds5doiob/hcm1hnNB/3vk4=\n" + + "-----END PRIVATE KEY-----\n" ; - private final String certContent = - "-----BEGIN CERTIFICATE-----\n" + - "MIIFZTCCBE2gAwIBAgIHK35JiCqLMjANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" + - "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" + - "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" + - "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" + - "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" + - "ODcwHhcNMTIwMjAyMDExMDE5WhcNMTcwMjA3MDUxMTIzWjBZMRkwFwYDVQQKDBAq\n" + - "LnJlYWxob3N0aXAuY29tMSEwHwYDVQQLDBhEb21haW4gQ29udHJvbCBWYWxpZGF0\n" + - "ZWQxGTAXBgNVBAMMECoucmVhbGhvc3RpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n" + - "A4IBDwAwggEKAoIBAQCGu5REMZSFQ6wDFr7NPp9iibCYHZ6d1IV7s6Yvs6yvXmYw\n" + - "46c9JaJ8FN0NoHVzzDD2dELfpBxXRN7eq1rcP3ISDdDkhjngJoXEd2xaqgp0UxOS\n" + - "+AaamGG6sOleACn0XBF+XXaaD5vnFw7YnDUyJioWR5KdTzVajLVkdEP3uPmJbRdv\n" + - "eEu8HMZpwhZyY4uAcH5nHxMJEj/mkZtFZJDi26ZjeonVOwnGm0NTbGCrfCneQEZC\n" + - "/SENua3BklHXc07zl3TrWu8xhrVWGRbcknw0VmGaPmehtuzL9WsieWGG4KH9G1LC\n" + - "2w2mbib64nSluBEcHRCKOT2aMzo2FonKAZkkIE53AgMBAAGjggG+MIIBujAPBgNV\n" + - "HRMBAf8EBTADAQEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV\n" + - "HQ8BAf8EBAMCBaAwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5\n" + - "LmNvbS9nZHMxLTYzLmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcBMDkwNwYI\n" + - "KwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3Np\n" + - "dG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\n" + - "Z29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdv\n" + - "ZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSME\n" + - "GDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAqLnJlYWxob3N0\n" + - "aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUwjwYIABbqSlCbCDr9E6F\n" + - "htB12TAwDQYJKoZIhvcNAQEFBQADggEBALxCXsUGaxTwWIvQEJu6D4lIMrkYyQuy\n" + - "Z2Cfd1/RLyX87ZkBR4iCO9MTezVFgDQj2rfSQGhnVLxD/1cGoivHKm3hmRX8gWh1\n" + - "d3vPco55XF8wWtQee822RB55h015kmrcv68yUIllrjDDuGfMc+QdIkxjIzDRWlEF\n" + - "mq8xEGIfabuflT2C58OU1ZHgQvBvK2iWGNgXSE9h0Bf8xwu/uYHgoWi5dBFm+woo\n" + - "GVNHaLNZBjwvKGvJN8zcmjjpYuYEfGVezm+kgGTBLpKthx5HV8vTrKnkmt0h/4pf\n" + - "ZumhNAbOBj753mNCMnNLo/+OAQNPR5QIGhjd4zMgUJT0e9GnQok7V98=\n" + - "-----END CERTIFICATE-----\n"; + public static final String certContent = + "-----BEGIN CERTIFICATE-----\n" + + "MIIFZTCCBE2gAwIBAgIHKBCduBUoKDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" + + "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" + + "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" + + "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" + + "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" + + "ODcwHhcNMTIwMjAzMDMzMDQwWhcNMTcwMjA3MDUxMTIzWjBZMRkwFwYDVQQKDBAq\n" + + "LnJlYWxob3N0aXAuY29tMSEwHwYDVQQLDBhEb21haW4gQ29udHJvbCBWYWxpZGF0\n" + + "ZWQxGTAXBgNVBAMMECoucmVhbGhvc3RpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ0+GgsybNHheU+JpL39LM\n" + + "TZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX1FIpOBGp\n" + + "h9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/o\n" + + "CfTlXJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo\n" + + "2JUl8ekNLsOi8/cPtfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4\n" + + "j9cBpE+MfUE+35Dq121sTpsSgF85Mz+pVhn2S633AgMBAAGjggG+MIIBujAPBgNV\n" + + "HRMBAf8EBTADAQEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV\n" + + "HQ8BAf8EBAMCBaAwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5\n" + + "LmNvbS9nZHMxLTY0LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcBMDkwNwYI\n" + + "KwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3Np\n" + + "dG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\n" + + "Z29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdv\n" + + "ZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSME\n" + + "GDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAqLnJlYWxob3N0\n" + + "aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUZyJz9/QLy5TWIIscTXID\n" + + "E8Xk47YwDQYJKoZIhvcNAQEFBQADggEBAKiUV3KK16mP0NpS92fmQkCLqm+qUWyN\n" + + "BfBVgf9/M5pcT8EiTZlS5nAtzAE/eRpBeR3ubLlaAogj4rdH7YYVJcDDLLoB2qM3\n" + + "qeCHu8LFoblkb93UuFDWqRaVPmMlJRnhsRkL1oa2gM2hwQTkBDkP7w5FG1BELCgl\n" + + "gZI2ij2yxjge6pOEwSyZCzzbCcg9pN+dNrYyGEtB4k+BBnPA3N4r14CWbk+uxjrQ\n" + + "6j2Ip+b7wOc5IuMEMl8xwTyjuX3lsLbAZyFI9RCyofwA9NqIZ1GeB6Zd196rubQp\n" + + "93cmBqGGjZUs3wMrGlm7xdjlX6GQ9UvmvkMub9+lL99A5W50QgCmFeI=\n" + + "-----END CERTIFICATE-----\n"; + + public static final String rootCa = + "-----BEGIN CERTIFICATE-----\n" + + "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx\n" + + "ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g\n" + + "RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw\n" + + "MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH\n" + + "QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j\n" + + "b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j\n" + + "b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj\n" + + "YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN\n" + + "AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H\n" + + "KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm\n" + + "VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR\n" + + "SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT\n" + + "cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ\n" + + "6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu\n" + + "MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS\n" + + "kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB\n" + + "BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f\n" + + "BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv\n" + + "c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH\n" + + "AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO\n" + + "BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG\n" + + "OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU\n" + + "A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o\n" + + "0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX\n" + + "RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH\n" + + "qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV\n" + + "U+4=\n" + + "-----END CERTIFICATE-----\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh\n" + + "bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe\n" + + "BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX\n" + + "DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE\n" + + "YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0\n" + + "aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC\n" + + "ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv\n" + + "2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q\n" + + "N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO\n" + + "r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN\n" + + "f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH\n" + + "U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU\n" + + "TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb\n" + + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg\n" + + "SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv\n" + + "biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg\n" + + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw\n" + + "AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv\n" + + "ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu\n" + + "Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd\n" + + "IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv\n" + + "bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1\n" + + "QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O\n" + + "WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf\n" + + "SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==\n" + + "-----END CERTIFICATE-----\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz\n" + + "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y\n" + + "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG\n" + + "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy\n" + + "NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y\n" + + "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs\n" + + "YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\n" + + "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\n" + + "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY\n" + + "dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9\n" + + "WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS\n" + + "v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v\n" + + "UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu\n" + + "IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + + "-----END CERTIFICATE-----\n"; @Inject private KeystoreDao _ksDao; @@ -1224,6 +1300,12 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, ConsoleProx KeystoreVO ksVo = _ksDao.findByName(CERTIFICATE_NAME); if (ksVo == null) { _ksDao.save(CERTIFICATE_NAME, certContent, keyContent, "realhostip.com"); + KeystoreVO caRoot = new KeystoreVO(); + caRoot.setCertificate(rootCa); + caRoot.setDomainSuffix("realhostip.com"); + caRoot.setName("root"); + caRoot.setIndex(0); + _ksDao.persist(caRoot); } lock.unlock(); } diff --git a/server/src/com/cloud/keystore/KeystoreDao.java b/server/src/com/cloud/keystore/KeystoreDao.java index d1b2889eb9e..4206730aa6e 100644 --- a/server/src/com/cloud/keystore/KeystoreDao.java +++ b/server/src/com/cloud/keystore/KeystoreDao.java @@ -18,9 +18,14 @@ package com.cloud.keystore; +import java.util.List; + import com.cloud.utils.db.GenericDao; public interface KeystoreDao extends GenericDao { KeystoreVO findByName(String name); void save(String name, String certificate, String key, String domainSuffix); + void save(String alias, String certificate, Integer index, + String domainSuffix); + List findCertChain(); } diff --git a/server/src/com/cloud/keystore/KeystoreDaoImpl.java b/server/src/com/cloud/keystore/KeystoreDaoImpl.java index 22421a9c55c..6399caf3aa6 100644 --- a/server/src/com/cloud/keystore/KeystoreDaoImpl.java +++ b/server/src/com/cloud/keystore/KeystoreDaoImpl.java @@ -18,6 +18,8 @@ package com.cloud.keystore; import java.sql.PreparedStatement; +import java.util.Comparator; +import java.util.List; import javax.ejb.Local; @@ -29,14 +31,33 @@ import com.cloud.utils.db.SearchCriteria.Op; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import edu.emory.mathcs.backport.java.util.Collections; + @Local(value={KeystoreDao.class}) public class KeystoreDaoImpl extends GenericDaoBase implements KeystoreDao { protected final SearchBuilder FindByNameSearch; + protected final SearchBuilder CertChainSearch; public KeystoreDaoImpl() { FindByNameSearch = createSearchBuilder(); FindByNameSearch.and("name", FindByNameSearch.entity().getName(), Op.EQ); FindByNameSearch.done(); + + CertChainSearch = createSearchBuilder(); + CertChainSearch.and("key", CertChainSearch.entity().getKey(), Op.NULL); + CertChainSearch.done(); + } + + @Override + public List findCertChain() { + SearchCriteria sc = CertChainSearch.create(); + List ks = listBy(sc); + Collections.sort(ks, new Comparator() { public int compare(Object o1, Object o2) { + Integer seq1 = ((KeystoreVO)o1).getIndex(); + Integer seq2 = ((KeystoreVO)o2).getIndex(); + return seq1.compareTo(seq2); + }}); + return ks; } @Override @@ -72,4 +93,24 @@ public class KeystoreDaoImpl extends GenericDaoBase implements throw new CloudRuntimeException("Unable to save certificate under name " + name + " due to exception", e); } } + + @Override + @DB + public void save(String alias, String certificate, Integer index, String domainSuffix) { + KeystoreVO ks = this.findByName(alias); + if (ks != null) { + ks.setCertificate(certificate); + ks.setName(alias); + ks.setIndex(index); + ks.setDomainSuffix(domainSuffix); + this.update(ks.getId(), ks); + } else { + KeystoreVO newks = new KeystoreVO(); + newks.setCertificate(certificate); + newks.setName(alias); + newks.setIndex(index); + newks.setDomainSuffix(domainSuffix); + this.persist(newks); + } + } } diff --git a/server/src/com/cloud/keystore/KeystoreManager.java b/server/src/com/cloud/keystore/KeystoreManager.java index 44491af07e8..78ab6fd2118 100644 --- a/server/src/com/cloud/keystore/KeystoreManager.java +++ b/server/src/com/cloud/keystore/KeystoreManager.java @@ -18,10 +18,14 @@ package com.cloud.keystore; +import com.cloud.agent.api.SecStorageSetupCommand.Certificates; import com.cloud.utils.component.Manager; public interface KeystoreManager extends Manager { boolean validateCertificate(String certificate, String key, String domainSuffix); void saveCertificate(String name, String certificate, String key, String domainSuffix); byte[] getKeystoreBits(String name, String aliasForCertificateInStore, String storePassword); + void saveCertificate(String name, String certificate, Integer index, + String domainSuffix); + Certificates getCertificates(String name); } diff --git a/server/src/com/cloud/keystore/KeystoreManagerImpl.java b/server/src/com/cloud/keystore/KeystoreManagerImpl.java index 6fa2a690cfc..9495812b59b 100644 --- a/server/src/com/cloud/keystore/KeystoreManagerImpl.java +++ b/server/src/com/cloud/keystore/KeystoreManagerImpl.java @@ -23,6 +23,8 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -32,6 +34,8 @@ import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.agent.api.SecStorageSetupCommand; +import com.cloud.utils.Ternary; import com.cloud.utils.component.Inject; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.security.CertificateHelper; @@ -99,6 +103,17 @@ public class KeystoreManagerImpl implements KeystoreManager { _ksDao.save(name, certificate, key, domainSuffix); } + @Override + public void saveCertificate(String name, String certificate, Integer index, String domainSuffix) { + if(name == null || name.isEmpty() || + certificate == null || certificate.isEmpty() || + index == null || + domainSuffix == null || domainSuffix.isEmpty()) + throw new CloudRuntimeException("invalid parameter in saveCerticate"); + + _ksDao.save(name, certificate, index, domainSuffix); + } + @Override public byte[] getKeystoreBits(String name, String aliasForCertificateInStore, String storePassword) { assert(name != null); @@ -109,8 +124,19 @@ public class KeystoreManagerImpl implements KeystoreManager { if(ksVo == null) throw new CloudRuntimeException("Unable to find keystore " + name); + List> certs = new ArrayList>(); + List certChains = _ksDao.findCertChain(); + + for (KeystoreVO ks : certChains) { + Ternary cert = new Ternary(ks.getName(), ks.getCertificate(), null); + certs.add(cert); + } + + Ternary cert = new Ternary(ksVo.getName(), ksVo.getCertificate(), getKeyContent(ksVo.getKey())); + certs.add(cert); + try { - return CertificateHelper.buildAndSaveKeystore(aliasForCertificateInStore, ksVo.getCertificate(), getKeyContent(ksVo.getKey()), storePassword); + return CertificateHelper.buildAndSaveKeystore(certs, storePassword); } catch(KeyStoreException e) { s_logger.warn("Unable to build keystore for " + name + " due to KeyStoreException"); } catch(CertificateException e) { @@ -125,6 +151,28 @@ public class KeystoreManagerImpl implements KeystoreManager { return null; } + @Override + public SecStorageSetupCommand.Certificates getCertificates(String name) { + KeystoreVO ksVo = _ksDao.findByName(name); + if (ksVo == null) { + return null; + } + String prvKey = ksVo.getKey(); + String prvCert = ksVo.getCertificate(); + String certChain = null; + List certchains = _ksDao.findCertChain(); + if (certchains.size() > 0) { + StringBuilder chains = new StringBuilder(); + for (KeystoreVO cert : certchains) { + chains.append(cert.getCertificate()); + chains.append("\n"); + } + certChain = chains.toString(); + } + SecStorageSetupCommand.Certificates certs = new SecStorageSetupCommand.Certificates(prvKey, prvCert, certChain); + return certs; + } + private static String getKeyContent(String key) { Pattern regex = Pattern.compile("(^[\\-]+[^\\-]+[\\-]+[\\n]?)([^\\-]+)([\\-]+[^\\-]+[\\-]+$)"); Matcher m = regex.matcher(key); diff --git a/server/src/com/cloud/keystore/KeystoreVO.java b/server/src/com/cloud/keystore/KeystoreVO.java index 52e10b85fe1..4b252adfb56 100644 --- a/server/src/com/cloud/keystore/KeystoreVO.java +++ b/server/src/com/cloud/keystore/KeystoreVO.java @@ -44,6 +44,9 @@ public class KeystoreVO { @Column(name="domain_suffix") private String domainSuffix; + + @Column(name="seq") + private Integer index; public KeystoreVO() { } @@ -87,4 +90,12 @@ public class KeystoreVO { public void setDomainSuffix(String domainSuffix) { this.domainSuffix = domainSuffix; } + + public void setIndex(Integer index) { + this.index = index; + } + + public Integer getIndex() { + return this.index; + } } diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index ed1c562ccf7..7bafc01b036 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -4549,11 +4549,29 @@ public class ManagementServerImpl implements ManagementServer { @Override @DB public String uploadCertificate(UploadCustomCertificateCmd cmd) { - if (!_ksMgr.validateCertificate(cmd.getCertificate(), cmd.getPrivateKey(), cmd.getDomainSuffix())) { + if (cmd.getPrivateKey() != null && cmd.getAlias() != null) { + throw new InvalidParameterValueException("Can't change the alias for private key certification"); + } + + if (cmd.getPrivateKey() == null) { + if (cmd.getAlias() == null) { + throw new InvalidParameterValueException("alias can't be empty, if it's a certification chain"); + } + + if (cmd.getCertIndex() == null) { + throw new InvalidParameterValueException("index can't be empty, if it's a certifciation chain"); + } + } + + if (cmd.getPrivateKey() != null &&!_ksMgr.validateCertificate(cmd.getCertificate(), cmd.getPrivateKey(), cmd.getDomainSuffix())) { throw new InvalidParameterValueException("Failed to pass certificate validation check"); } - _ksMgr.saveCertificate(ConsoleProxyManager.CERTIFICATE_NAME, cmd.getCertificate(), cmd.getPrivateKey(), cmd.getDomainSuffix()); + if (cmd.getPrivateKey() != null) { + _ksMgr.saveCertificate(ConsoleProxyManager.CERTIFICATE_NAME, cmd.getCertificate(), cmd.getPrivateKey(), cmd.getDomainSuffix()); + } else { + _ksMgr.saveCertificate(cmd.getAlias(), cmd.getCertificate(), cmd.getCertIndex(), cmd.getDomainSuffix()); + } _consoleProxyMgr.setManagementState(ConsoleProxyManagementState.ResetSuspending); return "Certificate has been updated, we will stop all running console proxy VMs to propagate the new certificate, please give a few minutes for console access service to be up again"; diff --git a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java index fd7cd4f7af2..64f2625ac7d 100755 --- a/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java +++ b/server/src/com/cloud/storage/secondary/SecondaryStorageManagerImpl.java @@ -36,6 +36,7 @@ import com.cloud.agent.api.RebootCommand; import com.cloud.agent.api.SecStorageFirewallCfgCommand; import com.cloud.agent.api.SecStorageSetupAnswer; import com.cloud.agent.api.SecStorageSetupCommand; +import com.cloud.agent.api.SecStorageSetupCommand.Certificates; import com.cloud.agent.api.SecStorageVMSetupCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StopAnswer; @@ -48,6 +49,7 @@ import com.cloud.cluster.ManagementServerNode; import com.cloud.configuration.Config; import com.cloud.configuration.ZoneConfig; import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.consoleproxy.ConsoleProxyManager; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; @@ -65,6 +67,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.info.RunningHostCountInfo; import com.cloud.info.RunningHostInfoAgregator; import com.cloud.info.RunningHostInfoAgregator.ZoneHostInfo; +import com.cloud.keystore.KeystoreManager; import com.cloud.network.NetworkManager; import com.cloud.network.NetworkVO; import com.cloud.network.Networks.TrafficType; @@ -190,6 +193,8 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V @Inject UserVmDetailsDao _vmDetailsDao; + @Inject + KeystoreManager _keystoreMgr; private long _capacityScanInterval = DEFAULT_CAPACITY_SCAN_INTERVAL; private int _secStorageVmRamSize; @@ -250,7 +255,13 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V List ssHosts = _hostDao.listSecondaryStorageHosts(zoneId); for( HostVO ssHost : ssHosts ) { String secUrl = ssHost.getStorageUrl(); - SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl); + SecStorageSetupCommand setupCmd = null; + if (!_useSSlCopy) { + setupCmd = new SecStorageSetupCommand(secUrl, null); + } else { + Certificates certs = _keystoreMgr.getCertificates(ConsoleProxyManager.CERTIFICATE_NAME); + setupCmd = new SecStorageSetupCommand(secUrl, certs); + } Answer answer = _agentMgr.easySend(ssHostId, setupCmd); if (answer != null && answer.getResult()) { @@ -270,7 +281,7 @@ public class SecondaryStorageManagerImpl implements SecondaryStorageVmManager, V } else if( cssHost.getType() == Host.Type.SecondaryStorage ) { List alreadyRunning = _secStorageVmDao.getSecStorageVmListInStates(SecondaryStorageVm.Role.templateProcessor, zoneId, State.Running); String secUrl = cssHost.getStorageUrl(); - SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl); + SecStorageSetupCommand setupCmd = new SecStorageSetupCommand(secUrl, null); for ( SecondaryStorageVmVO ssVm : alreadyRunning ) { HostVO host = _hostDao.findByName(ssVm.getInstanceName()); Answer answer = _agentMgr.easySend(host.getId(), setupCmd); diff --git a/server/src/com/cloud/upgrade/dao/Upgrade2213to2214.java b/server/src/com/cloud/upgrade/dao/Upgrade2213to2214.java index bbc653ba1f1..644e5373a93 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade2213to2214.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade2213to2214.java @@ -20,18 +20,157 @@ package com.cloud.upgrade.dao; import java.io.File; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; +import com.cloud.consoleproxy.ConsoleProxyManagerImpl; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.Script; public class Upgrade2213to2214 implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade2213to2214.class); + private final String priviateKey = + "-----BEGIN CERTIFICATE-----\n" + + "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ\n" + + "0+GgsybNHheU+JpL39LMTZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX\n" + + "1FIpOBGph9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/oCfTl\n" + + "XJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo2JUl8ekNLsOi8/cP\n" + + "tfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4j9cBpE+MfUE+35Dq121sTpsSgF85\n" + + "Mz+pVhn2S633AgMBAAECggEAH/Szd9RxbVADenCA6wxKSa3KErRyq1YN8ksJeCKMAj0FIt0caruE\n" + + "qO11DebWW8cwQu1Otl/cYI6pmg24/BBldMrp9IELX/tNJo+lhPpRyGAxxC0eSXinFfoASb8d+jJd\n" + + "Bd1mmemM6fSxqRlxSP4LrzIhjhR1g2CiyYuTsiM9UtoVKGyHwe7KfFwirUOJo3Mr18zUVNm7YqY4\n" + + "IVhOSq59zkH3ULBlYq4bG50jpxa5mNSCZ7IpafPY/kE/CbR+FWNt30+rk69T+qb5abg6+XGm+OAm\n" + + "bnQ18yZEqX6nJLk7Ch0cfA5orGgrTMOrM71wK7tBBDQ308kOxDGebx6j0qD36QKBgQDTRDr8kuhA\n" + + "9sUyKr9vk2DQCMpNvEeiwI3JRMqmmxpNAtg01aJ3Ya57vX5Fc+zcuV87kP6FM1xgpHQvnw5LWo2J\n" + + "s7ANwQcP8ricEW5zkZhSjI4ssMeAubmsHOloGxmLFYZqwx0JI7CWViGTLMcUlqKblmHcjeQDeDfP\n" + + "P1TaCItFmwKBgQCfHZwVvIcaDs5vxVpZ4ftvflIrW8qq0uOVK6QIf9A/YTGhCXl2qxxTg2A6+0rg\n" + + "ZqI7zKzUDxIbVv0KlgCbpHDC9d5+sdtDB3wW2pimuJ3p1z4/RHb4n/lDwXCACZl1S5l24yXX2pFZ\n" + + "wdPCXmy5PYkHMssFLNhI24pprUIQs66M1QKBgQDQwjAjWisD3pRXESSfZRsaFkWJcM28hdbVFhPF\n" + + "c6gWhwQLmTp0CuL2RPXcPUPFi6sN2iWWi3zxxi9Eyz+9uBn6AsOpo56N5MME/LiOnETO9TKb+Ib6\n" + + "rQtKhjshcv3XkIqFPo2XdVvOAgglPO7vajX91iiXXuH7h7RmJud6l0y/lwKBgE+bi90gLuPtpoEr\n" + + "VzIDKz40ED5bNYHT80NNy0rpT7J2GVN9nwStRYXPBBVeZq7xCpgqpgmO5LtDAWULeZBlbHlOdBwl\n" + + "NhNKKl5wzdEUKwW0yBL1WSS5PQgWPwgARYP25/ggW22sj+49WIo1neXsEKPGWObk8e050f1fTt92\n" + + "Vo1lAoGAb1gCoyBCzvi7sqFxm4V5oapnJeiQQJFjhoYWqGa26rQ+AvXXNuBcigIeDXNJPctSF0Uc\n" + + "p11KbbCgiruBbckvM1vGsk6Sx4leRk+IFHRpJktFUek4o0eUg0shOsyyvyet48Dfg0a8FvcxROs0\n" + + "gD+IYds5doiob/hcm1hnNB/3vk4=\n" + + "-----END PRIVATE KEY----- |\n" ; + + private final String pubcertificate = + "-----BEGIN CERTIFICATE-----\n" + + "MIIFZTCCBE2gAwIBAgIHKBCduBUoKDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" + + "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" + + "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" + + "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" + + "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" + + "ODcwHhcNMTIwMjAzMDMzMDQwWhcNMTcwMjA3MDUxMTIzWjBZMRkwFwYDVQQKDBAq\n" + + "LnJlYWxob3N0aXAuY29tMSEwHwYDVQQLDBhEb21haW4gQ29udHJvbCBWYWxpZGF0\n" + + "ZWQxGTAXBgNVBAMMECoucmVhbGhvc3RpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUA\n" + + "A4IBDwAwggEKAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ0+GgsybNHheU+JpL39LM\n" + + "TZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX1FIpOBGp\n" + + "h9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/o\n" + + "CfTlXJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo\n" + + "2JUl8ekNLsOi8/cPtfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4\n" + + "j9cBpE+MfUE+35Dq121sTpsSgF85Mz+pVhn2S633AgMBAAGjggG+MIIBujAPBgNV\n" + + "HRMBAf8EBTADAQEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV\n" + + "HQ8BAf8EBAMCBaAwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5\n" + + "LmNvbS9nZHMxLTY0LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcBMDkwNwYI\n" + + "KwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3Np\n" + + "dG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au\n" + + "Z29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdv\n" + + "ZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSME\n" + + "GDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAqLnJlYWxob3N0\n" + + "aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUZyJz9/QLy5TWIIscTXID\n" + + "E8Xk47YwDQYJKoZIhvcNAQEFBQADggEBAKiUV3KK16mP0NpS92fmQkCLqm+qUWyN\n" + + "BfBVgf9/M5pcT8EiTZlS5nAtzAE/eRpBeR3ubLlaAogj4rdH7YYVJcDDLLoB2qM3\n" + + "qeCHu8LFoblkb93UuFDWqRaVPmMlJRnhsRkL1oa2gM2hwQTkBDkP7w5FG1BELCgl\n" + + "gZI2ij2yxjge6pOEwSyZCzzbCcg9pN+dNrYyGEtB4k+BBnPA3N4r14CWbk+uxjrQ\n" + + "6j2Ip+b7wOc5IuMEMl8xwTyjuX3lsLbAZyFI9RCyofwA9NqIZ1GeB6Zd196rubQp\n" + + "93cmBqGGjZUs3wMrGlm7xdjlX6GQ9UvmvkMub9+lL99A5W50QgCmFeI=\n" + + "-----END CERTIFICATE-----\n"; + + private final String rootCa = + "-----BEGIN CERTIFICATE-----\n" + + "MIIE3jCCA8agAwIBAgICAwEwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCVVMx\n" + + "ITAfBgNVBAoTGFRoZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28g\n" + + "RGFkZHkgQ2xhc3MgMiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjExMTYw\n" + + "MTU0MzdaFw0yNjExMTYwMTU0MzdaMIHKMQswCQYDVQQGEwJVUzEQMA4GA1UECBMH\n" + + "QXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5j\n" + + "b20sIEluYy4xMzAxBgNVBAsTKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j\n" + + "b20vcmVwb3NpdG9yeTEwMC4GA1UEAxMnR28gRGFkZHkgU2VjdXJlIENlcnRpZmlj\n" + + "YXRpb24gQXV0aG9yaXR5MREwDwYDVQQFEwgwNzk2OTI4NzCCASIwDQYJKoZIhvcN\n" + + "AQEBBQADggEPADCCAQoCggEBAMQt1RWMnCZM7DI161+4WQFapmGBWTtwY6vj3D3H\n" + + "KrjJM9N55DrtPDAjhI6zMBS2sofDPZVUBJ7fmd0LJR4h3mUpfjWoqVTr9vcyOdQm\n" + + "VZWt7/v+WIbXnvQAjYwqDL1CBM6nPwT27oDyqu9SoWlm2r4arV3aLGbqGmu75RpR\n" + + "SgAvSMeYddi5Kcju+GZtCpyz8/x4fKL4o/K1w/O5epHBp+YlLpyo7RJlbmr2EkRT\n" + + "cDCVw5wrWCs9CHRK8r5RsL+H0EwnWGu1NcWdrxcx+AuP7q2BNgWJCJjPOq8lh8BJ\n" + + "6qf9Z/dFjpfMFDniNoW1fho3/Rb2cRGadDAW/hOUoz+EDU8CAwEAAaOCATIwggEu\n" + + "MB0GA1UdDgQWBBT9rGEyk2xF1uLuhV+auud2mWjM5zAfBgNVHSMEGDAWgBTSxLDS\n" + + "kdRMEXGzYcs9of7dqGrU4zASBgNVHRMBAf8ECDAGAQH/AgEAMDMGCCsGAQUFBwEB\n" + + "BCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZ29kYWRkeS5jb20wRgYDVR0f\n" + + "BD8wPTA7oDmgN4Y1aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBv\n" + + "c2l0b3J5L2dkcm9vdC5jcmwwSwYDVR0gBEQwQjBABgRVHSAAMDgwNgYIKwYBBQUH\n" + + "AgEWKmh0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeTAO\n" + + "BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBANKGwOy9+aG2Z+5mC6IG\n" + + "OgRQjhVyrEp0lVPLN8tESe8HkGsz2ZbwlFalEzAFPIUyIXvJxwqoJKSQ3kbTJSMU\n" + + "A2fCENZvD117esyfxVgqwcSeIaha86ykRvOe5GPLL5CkKSkB2XIsKd83ASe8T+5o\n" + + "0yGPwLPk9Qnt0hCqU7S+8MxZC9Y7lhyVJEnfzuz9p0iRFEUOOjZv2kWzRaJBydTX\n" + + "RE4+uXR21aITVSzGh6O1mawGhId/dQb8vxRMDsxuxN89txJx9OjxUUAiKEngHUuH\n" + + "qDTMBqLdElrRhjZkAzVvb3du6/KFUJheqwNTrZEjYx8WnM25sgVjOuH0aBsXBTWV\n" + + "U+4=\n" + + "-----END CERTIFICATE-----\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIE+zCCBGSgAwIBAgICAQ0wDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh\n" + + "bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu\n" + + "Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g\n" + + "QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe\n" + + "BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MDYyMFoX\n" + + "DTI0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRoZSBHbyBE\n" + + "YWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3MgMiBDZXJ0\n" + + "aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC\n" + + "ggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCAPVYYYwhv\n" + + "2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6wwdhFJ2+q\n" + + "N1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXiEqITLdiO\n" + + "r18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMYavx4A6lN\n" + + "f4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+YihfukEH\n" + + "U1jPEX44dMX4/7VpkI+EdOqXG68CAQOjggHhMIIB3TAdBgNVHQ4EFgQU0sSw0pHU\n" + + "TBFxs2HLPaH+3ahq1OMwgdIGA1UdIwSByjCBx6GBwaSBvjCBuzEkMCIGA1UEBxMb\n" + + "VmFsaUNlcnQgVmFsaWRhdGlvbiBOZXR3b3JrMRcwFQYDVQQKEw5WYWxpQ2VydCwg\n" + + "SW5jLjE1MDMGA1UECxMsVmFsaUNlcnQgQ2xhc3MgMiBQb2xpY3kgVmFsaWRhdGlv\n" + + "biBBdXRob3JpdHkxITAfBgNVBAMTGGh0dHA6Ly93d3cudmFsaWNlcnQuY29tLzEg\n" + + "MB4GCSqGSIb3DQEJARYRaW5mb0B2YWxpY2VydC5jb22CAQEwDwYDVR0TAQH/BAUw\n" + + "AwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmdv\n" + + "ZGFkZHkuY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jZXJ0aWZpY2F0ZXMu\n" + + "Z29kYWRkeS5jb20vcmVwb3NpdG9yeS9yb290LmNybDBLBgNVHSAERDBCMEAGBFUd\n" + + "IAAwODA2BggrBgEFBQcCARYqaHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNv\n" + + "bS9yZXBvc2l0b3J5MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQC1\n" + + "QPmnHfbq/qQaQlpE9xXUhUaJwL6e4+PrxeNYiY+Sn1eocSxI0YGyeR+sBjUZsE4O\n" + + "WBsUs5iB0QQeyAfJg594RAoYC5jcdnplDQ1tgMQLARzLrUc+cb53S8wGd9D0Vmsf\n" + + "SxOaFIqII6hR8INMqzW/Rn453HWkrugp++85j09VZw==\n" + + "-----END CERTIFICATE-----\n" + + "-----BEGIN CERTIFICATE-----\n" + + "MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0\n" + + "IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz\n" + + "BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y\n" + + "aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG\n" + + "9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy\n" + + "NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y\n" + + "azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs\n" + + "YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw\n" + + "Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl\n" + + "cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY\n" + + "dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9\n" + + "WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS\n" + + "v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v\n" + + "UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu\n" + + "IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC\n" + + "W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd\n" + + "-----END CERTIFICATE-----\n"; + @Override public String[] getUpgradableVersionRange() { return new String[] { "2.2.13", "2.2.14"}; @@ -47,6 +186,35 @@ public class Upgrade2213to2214 implements DbUpgrade { return true; } + private void upgradeCerts(Connection conn) { + PreparedStatement pstmt; + try { + pstmt = conn.prepareStatement("select md5(`cloud`.`keystore`.key) from `cloud`.`keystore` where name = 'CPVMCertificate'"); + ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + String privateKeyMd5 = rs.getString(1); + if (privateKeyMd5.equalsIgnoreCase("b2d3089241ed0ea0336efeb125dbb610")) { + s_logger.debug("Need to upgrade cloudstack provided certificate"); + pstmt = conn.prepareStatement("update `cloud`.`keystore` set `cloud`.`keystore`.key = ?, certificate = ? where name = 'CPVMCertificate'"); + pstmt.setString(1, ConsoleProxyManagerImpl.keyContent); + pstmt.setString(2, ConsoleProxyManagerImpl.certContent); + pstmt.executeUpdate(); + + pstmt = conn.prepareStatement("insert into `cloud`.`keystore` (name, certificate, seq, domain_suffix) VALUES (?,?,?,?)"); + pstmt.setString(1, "root"); + pstmt.setString(2, ConsoleProxyManagerImpl.rootCa); + pstmt.setInt(3, 0); + pstmt.setString(4, "realhostip.com"); + pstmt.executeUpdate(); + } + } + rs.close(); + pstmt.close(); + } catch (SQLException e) { + s_logger.debug("Failed to upgrade keystore: " + e.toString()); + } + + } @Override public File[] getPrepareScripts() { String script = Script.findScript("", "db/schema-2213to2214.sql"); @@ -54,12 +222,14 @@ public class Upgrade2213to2214 implements DbUpgrade { throw new CloudRuntimeException("Unable to find db/schema-2213to2214.sql"); } + return new File[] { new File(script) }; } @Override public void performDataMigration(Connection conn) { fixIndexes(conn); + upgradeCerts(conn); } @Override diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 5f526b5e650..e4238e60a94 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -1619,8 +1619,9 @@ CREATE TABLE `cloud`.`keystore` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', `name` varchar(64) NOT NULL COMMENT 'unique name for the certifiation', `certificate` text NOT NULL COMMENT 'the actual certificate being stored in the db', - `key` text NOT NULL COMMENT 'private key associated wih the certificate', + `key` text COMMENT 'private key associated wih the certificate', `domain_suffix` varchar(256) NOT NULL COMMENT 'DNS domain suffix associated with the certificate', + `seq` int, PRIMARY KEY (`id`), UNIQUE(name) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/db/schema-2213to2214.sql b/setup/db/db/schema-2213to2214.sql index 1bbf44a5075..9fe9c2d596b 100644 --- a/setup/db/db/schema-2213to2214.sql +++ b/setup/db/db/schema-2213to2214.sql @@ -61,4 +61,6 @@ ALTER TABLE `cloud`.`vm_instance` MODIFY `limit_cpu_use` tinyint(1) unsigned NOT UPDATE `cloud`.`configuration` SET `value`='false' WHERE `name`='agent.lb.enabled'; -ALTER TABLE `cloud_usage`.`user_statistics` MODIFY `device_type` varchar(32) NOT NULL; +ALTER TABLE `cloud_usage`.`user_statistics` MODIFY `device_type` varchar(32) NOT NULL; +ALTER TABLE `cloud`.`keystore` ADD seq int; +ALTER TABLE `cloud`.`keystore` MODIFY `cloud`.`keystore`.`key` text; diff --git a/utils/src/com/cloud/utils/security/CertificateHelper.java b/utils/src/com/cloud/utils/security/CertificateHelper.java index 8ba7c99154c..3d3deff0b55 100644 --- a/utils/src/com/cloud/utils/security/CertificateHelper.java +++ b/utils/src/com/cloud/utils/security/CertificateHelper.java @@ -3,6 +3,7 @@ package com.cloud.utils.security; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.security.Key; import java.security.KeyFactory; @@ -14,9 +15,12 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.List; import org.apache.commons.codec.binary.Base64; +import com.cloud.utils.Ternary; + public class CertificateHelper { public static byte[] buildAndSaveKeystore(String alias, String cert, String privateKey, String storePassword) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, InvalidKeySpecException, IOException { @@ -28,6 +32,32 @@ public class CertificateHelper { return os.toByteArray(); } + public static byte[] buildAndSaveKeystore(List> certs, String storePassword) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, InvalidKeySpecException { + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, storePassword != null ? storePassword.toCharArray() : null); + + //name,cert,key + for (Ternary cert : certs) { + if (cert.third() == null) { + Certificate c = buildCertificate(cert.second()); + ks.setCertificateEntry(cert.first(), c); + } else { + Certificate[] c = new Certificate[certs.size()]; + int i = certs.size(); + for (Ternary ct : certs) { + c[i - 1] = buildCertificate(ct.second()); + i--; + } + ks.setKeyEntry(cert.first(), buildPrivateKey(cert.third()), storePassword != null ? storePassword.toCharArray() : null, c ); + } + } + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ks.store(os, storePassword != null ? storePassword.toCharArray() : null); + os.close(); + return os.toByteArray(); + } + public static KeyStore loadKeystore(byte[] ksData, String storePassword) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { assert(ksData != null); KeyStore ks = KeyStore.getInstance("JKS");