From 6ed18b5583a852014d6cc965f28c17a1d049d341 Mon Sep 17 00:00:00 2001 From: Kelven Yang Date: Tue, 19 Apr 2011 16:19:53 -0700 Subject: [PATCH] Add keystore management and related JUNIT test case --- .../src/com/cloud/keystore/KeystoreDao.java | 26 +++ .../com/cloud/keystore/KeystoreDaoImpl.java | 77 +++++++++ .../com/cloud/keystore/KeystoreManager.java | 26 +++ .../cloud/keystore/KeystoreManagerImpl.java | 114 +++++++++++++ server/src/com/cloud/keystore/KeystoreVO.java | 90 ++++++++++ .../test/com/cloud/keystore/KeystoreTest.java | 157 ++++++++++++++++++ setup/db/create-schema.sql | 10 ++ 7 files changed, 500 insertions(+) create mode 100644 server/src/com/cloud/keystore/KeystoreDao.java create mode 100644 server/src/com/cloud/keystore/KeystoreDaoImpl.java create mode 100644 server/src/com/cloud/keystore/KeystoreManager.java create mode 100644 server/src/com/cloud/keystore/KeystoreManagerImpl.java create mode 100644 server/src/com/cloud/keystore/KeystoreVO.java create mode 100644 server/test/com/cloud/keystore/KeystoreTest.java diff --git a/server/src/com/cloud/keystore/KeystoreDao.java b/server/src/com/cloud/keystore/KeystoreDao.java new file mode 100644 index 00000000000..d1b2889eb9e --- /dev/null +++ b/server/src/com/cloud/keystore/KeystoreDao.java @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.keystore; + +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); +} diff --git a/server/src/com/cloud/keystore/KeystoreDaoImpl.java b/server/src/com/cloud/keystore/KeystoreDaoImpl.java new file mode 100644 index 00000000000..d7a15d3de68 --- /dev/null +++ b/server/src/com/cloud/keystore/KeystoreDaoImpl.java @@ -0,0 +1,77 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.keystore; + +import java.sql.PreparedStatement; + +import javax.ejb.Local; + +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; + +@Local(value={KeystoreDao.class}) +public class KeystoreDaoImpl extends GenericDaoBase implements KeystoreDao { + + protected final SearchBuilder FindByNameSearch; + + public KeystoreDaoImpl() { + FindByNameSearch = createSearchBuilder(); + FindByNameSearch.and("name", FindByNameSearch.entity().getName(), Op.EQ); + FindByNameSearch.done(); + } + + @Override + public KeystoreVO findByName(String name) { + assert(name != null); + + SearchCriteria sc = FindByNameSearch.create(); + sc.setParameters("name", name); + return findOneBy(sc); + } + + + @Override + @DB + public void save(String name, String certificate, String key, String domainSuffix) { + Transaction txn = Transaction.currentTxn(); + try { + txn.start(); + + String sql = "INSERT INTO keystore (`name`, `certificate`, `key`, `domain_suffix`) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE `certificate`=?, `key`=?, `domain_suffix`=?"; + PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql); + pstmt.setString(1, name); + pstmt.setString(2, certificate); + pstmt.setString(3, key); + pstmt.setString(4, domainSuffix); + pstmt.setString(5, certificate); + pstmt.setString(6, key); + pstmt.setString(7, domainSuffix); + + pstmt.executeUpdate(); + txn.commit(); + } catch(Exception e) { + txn.rollback(); + throw new CloudRuntimeException("Unable to save certificate under name " + name + " due to exception", e); + } + } +} diff --git a/server/src/com/cloud/keystore/KeystoreManager.java b/server/src/com/cloud/keystore/KeystoreManager.java new file mode 100644 index 00000000000..79e4db49a22 --- /dev/null +++ b/server/src/com/cloud/keystore/KeystoreManager.java @@ -0,0 +1,26 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.keystore; + +import com.cloud.utils.component.Manager; + +public interface KeystoreManager extends Manager { + void saveCertificate(String name, String certificate, String key, String domainSuffix); + byte[] getKeystoreBits(String name, String aliasForCertificateInStore, String storePassword); +} diff --git a/server/src/com/cloud/keystore/KeystoreManagerImpl.java b/server/src/com/cloud/keystore/KeystoreManagerImpl.java new file mode 100644 index 00000000000..cad54c57a4d --- /dev/null +++ b/server/src/com/cloud/keystore/KeystoreManagerImpl.java @@ -0,0 +1,114 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.keystore; + +import java.io.IOException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.spec.InvalidKeySpecException; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.ejb.Local; +import javax.naming.ConfigurationException; + +import org.apache.log4j.Logger; + +import com.cloud.utils.component.Inject; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.security.CertificateHelper; + +@Local(value=KeystoreManager.class) +public class KeystoreManagerImpl implements KeystoreManager { + private static final Logger s_logger = Logger.getLogger(KeystoreManagerImpl.class); + + private String _name; + @Inject private KeystoreDao _ksDao; + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _name = name; + + return true; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } + + @Override + public String getName() { + return _name; + } + + @Override + public void saveCertificate(String name, String certificate, String key, String domainSuffix) { + if(name == null || name.isEmpty() || + certificate == null || certificate.isEmpty() || + key == null || key.isEmpty() || + domainSuffix == null || domainSuffix.isEmpty()) + throw new CloudRuntimeException("invalid parameter in saveCerticate"); + + + _ksDao.save(name, certificate, key, domainSuffix); + } + + @Override + public byte[] getKeystoreBits(String name, String aliasForCertificateInStore, String storePassword) { + assert(name != null); + assert(aliasForCertificateInStore != null); + assert(storePassword != null); + + KeystoreVO ksVo = _ksDao.findByName(name); + if(ksVo == null) + throw new CloudRuntimeException("Unable to find keystore " + name); + + try { + return CertificateHelper.buildAndSaveKeystore(aliasForCertificateInStore, ksVo.getCertificate(), getKeyContent(ksVo.getKey()), storePassword); + } catch(KeyStoreException e) { + s_logger.warn("Unable to build keystore for " + name + " due to KeyStoreException"); + } catch(CertificateException e) { + s_logger.warn("Unable to build keystore for " + name + " due to CertificateException"); + } catch(NoSuchAlgorithmException e) { + s_logger.warn("Unable to build keystore for " + name + " due to NoSuchAlgorithmException"); + } catch(InvalidKeySpecException e) { + s_logger.warn("Unable to build keystore for " + name + " due to InvalidKeySpecException"); + } catch(IOException e) { + s_logger.warn("Unable to build keystore for " + name + " due to IOException"); + } + return null; + } + + private static String getKeyContent(String key) { + Pattern regex = Pattern.compile("(^[\\-]+[^\\-]+[\\-]+[\\n]?)([^\\-]+)([\\-]+[^\\-]+[\\-]+$)"); + Matcher m = regex.matcher(key); + if(m.find()) + return m.group(2); + + return key; + } +} + diff --git a/server/src/com/cloud/keystore/KeystoreVO.java b/server/src/com/cloud/keystore/KeystoreVO.java new file mode 100644 index 00000000000..52e10b85fe1 --- /dev/null +++ b/server/src/com/cloud/keystore/KeystoreVO.java @@ -0,0 +1,90 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +package com.cloud.keystore; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name="keystore") +public class KeystoreVO { + @Id + @GeneratedValue(strategy=GenerationType.IDENTITY) + @Column(name="id") + private Long id; + + @Column(name="name") + private String name; + + @Column(name="certificate",length=65535) + private String certificate; + + @Column(name="key",length=65535) + private String key; + + @Column(name="domain_suffix") + private String domainSuffix; + + public KeystoreVO() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCertificate() { + return certificate; + } + + public void setCertificate(String certificate) { + this.certificate = certificate; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getDomainSuffix() { + return domainSuffix; + } + + public void setDomainSuffix(String domainSuffix) { + this.domainSuffix = domainSuffix; + } +} diff --git a/server/test/com/cloud/keystore/KeystoreTest.java b/server/test/com/cloud/keystore/KeystoreTest.java new file mode 100644 index 00000000000..d33bd906459 --- /dev/null +++ b/server/test/com/cloud/keystore/KeystoreTest.java @@ -0,0 +1,157 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ +package com.cloud.keystore; + +import java.security.KeyStore; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import junit.framework.TestCase; + +import org.apache.log4j.Logger; +import org.junit.After; +import org.junit.Before; + +import com.cloud.configuration.DefaultInterceptorLibrary; +import com.cloud.utils.component.ComponentLocator; +import com.cloud.utils.component.MockComponentLocator; +import com.cloud.utils.security.CertificateHelper; + +public class KeystoreTest extends TestCase { + private final static Logger s_logger = Logger.getLogger(KeystoreTest.class); + + private String keyContent = + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALV5vGlkiWwoZX4hTRplPXP8qtST\n" + + "hwZhko8noeY5vf8ECwmd+vrCTw/JvnOtkx/8oYNbg/SeUt1EfOsk6gqJdBblGFBZRMcUJlIpqE9z\n" + + "uv68U9G8Gfi/qvRSY336hibw0J5bZ4vn1QqmyHDB+Czea9AjFUV7AEVG15+vED7why+/AgMBAAEC\n" + + "gYBmFBPnNKYYMKDmUdUNA+WNWJK/ADzzWe8WlzR6TACTcbLDthl289WFC/YVG42mcHRpbxDKiEQU\n" + + "MnIR0rHTO34Qb/2HcuyweStU2gqR6omxBvMnFpJr90nD1HcOMJzeLHsphau0/EmKKey+gk4PyieD\n" + + "KqTM7LTjjHv8xPM4n+WAAQJBAOMNCeFKlJ4kMokWhU74B5/w/NGyT1BHUN0VmilHSiJC8JqS4BiI\n" + + "ZpAeET3VmilO6QTGh2XVhEDGteu3uZR6ipUCQQDMnRzMgQ/50LFeIQo4IBtwlEouczMlPQF4c21R\n" + + "1d720moxILVPT0NJZTQUDDmmgbL+B7CgtcCR2NlP5sKPZVADAkEAh4Xq1cy8dMBKYcVNgNtPQcqI\n" + + "PWpfKR3ISI5yXB0vRNAL6Vet5zbTcUZhKDVtNSbis3UEsGYH8NorEC2z2cpjGQJANhJi9Ow6c5Mh\n" + + "/DURBUn+1l5pyCKrZnDbvaALSLATLvjmFTuGjoHszy2OeKnOZmEqExWnKKE/VYuPyhy6V7i3TwJA\n" + + "f8skDgtPK0OsBCa6IljPaHoWBjPc4kFkSTSS1d56hUcWSikTmiuKdLyBb85AADSZYsvHWrte4opN\n" + + "dhNukMJuRA==\n"; + + private String certContent = + "-----BEGIN CERTIFICATE-----\n" + + "MIIE3jCCA8agAwIBAgIFAqv56tIwDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYT\n" + + "AlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRowGAYD\n" + + "VQQKExFHb0RhZGR5LmNvbSwgSW5jLjEzMDEGA1UECxMqaHR0cDovL2NlcnRpZmlj\n" + + "YXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5MTAwLgYDVQQDEydHbyBEYWRkeSBT\n" + + "ZWN1cmUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxETAPBgNVBAUTCDA3OTY5Mjg3\n" + + "MB4XDTA5MDIxMTA0NTc1NloXDTEyMDIwNzA1MTEyM1owWTEZMBcGA1UECgwQKi5y\n" + + "ZWFsaG9zdGlwLmNvbTEhMB8GA1UECwwYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVk\n" + + "MRkwFwYDVQQDDBAqLnJlYWxob3N0aXAuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN\n" + + "ADCBiQKBgQC1ebxpZIlsKGV+IU0aZT1z/KrUk4cGYZKPJ6HmOb3/BAsJnfr6wk8P\n" + + "yb5zrZMf/KGDW4P0nlLdRHzrJOoKiXQW5RhQWUTHFCZSKahPc7r+vFPRvBn4v6r0\n" + + "UmN9+oYm8NCeW2eL59UKpshwwfgs3mvQIxVFewBFRtefrxA+8IcvvwIDAQABo4IB\n" + + "vTCCAbkwDwYDVR0TAQH/BAUwAwEBADAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB\n" + + "BQUHAwIwDgYDVR0PAQH/BAQDAgWgMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9j\n" + + "cmwuZ29kYWRkeS5jb20vZ2RzMS0yLmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0B\n" + + "BxcBMDkwNwYIKwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5j\n" + + "b20vcmVwb3NpdG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0\n" + + "cDovL29jc3AuZ29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlm\n" + + "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNy\n" + + "dDAfBgNVHSMEGDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAq\n" + + "LnJlYWxob3N0aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUHxwmdK5w\n" + + "9/YVeZ/3fHyi6nQfzoYwDQYJKoZIhvcNAQEFBQADggEBABv/XinvId6oWXJtmku+\n" + + "7m90JhSVH0ycoIGjgdaIkcExQGP08MCilbUsPcbhLheSFdgn/cR4e1MP083lacoj\n" + + "OGauY7b8f/cuquGkT49Ns14awPlEzRjjycQEjjLxFEuL5CFWa2t2gKRE1dSfhDQ+\n" + + "fJ6GBCs1XgZLuhkKS8fPf+YmG2ZjHzYDjYoSx7paDXgEm+kbYIZdCK51lA0BUAjP\n" + + "9ZMGhsu/PpAbh5U/DtcIqxY0xeqD4TeGsBzXg6uLhv+jKHDtXg5fYPe+z0n5DCEL\n" + + "k0fLF4+i/pt9hVCz0QrZ28RUhXf825+EOL0Gw+Uzt+7RV2cCaJrlu4cDrDom2FRy\n" + + "E8I=\n" + + "-----END CERTIFICATE-----\n"; + + @Override + @Before + public void setUp() { + MockComponentLocator locator = new MockComponentLocator("management-server"); + locator.addDao("keystoreDao", KeystoreDaoImpl.class); + locator.addManager("KeystoreManager", KeystoreManagerImpl.class); + locator.makeActive(new DefaultInterceptorLibrary()); + } + + @Override + @After + public void tearDown() throws Exception { + } + + public void testKeystoreSave() throws Exception { + KeystoreVO ksVo; + + ComponentLocator locator = ComponentLocator.getCurrentLocator(); + + KeystoreDao ksDao = locator.getDao(KeystoreDao.class); + ksDao.save("CPVMCertificate", "CPVMCertificate", "KeyForCertificate", "realhostip.com"); + ksVo = ksDao.findByName("CPVMCertificate"); + assertTrue(ksVo != null); + assertTrue(ksVo.getCertificate().equals("CPVMCertificate")); + assertTrue(ksVo.getKey().equals("KeyForCertificate")); + assertTrue(ksVo.getDomainSuffix().equals("realhostip.com")); + + ksDao.save("CPVMCertificate", "CPVMCertificate Again", "KeyForCertificate Again", "again.realhostip.com"); + + ksVo = ksDao.findByName("CPVMCertificate"); + assertTrue(ksVo != null); + assertTrue(ksVo.getCertificate().equals("CPVMCertificate Again")); + assertTrue(ksVo.getKey().equals("KeyForCertificate Again")); + assertTrue(ksVo.getDomainSuffix().equals("again.realhostip.com")); + + ksDao.expunge(ksVo.getId()); + } + + public void testStripeKey() throws Exception { + Pattern regex = Pattern.compile("(^[\\-]+[^\\-]+[\\-]+[\\n]?)([^\\-]+)([\\-]+[^\\-]+[\\-]+$)"); + Matcher m = regex.matcher("-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAm4bLUORp9oM65GV9XrPrbs+K563DjUR1M8mP1HaE+Y4lX5pk\nvQjC/xoEqSs5pxDDWXAkoexvxij8A4AWcsKU1Q+ep2E+GcytBoz8XINGvgb8cQNn\n/4PlVWKp7j5SDDNCfleYvmiRn8k6P4mxVJOHKzwb/IwQcKghyqAF1w==\n-----END RSA PRIVATE KEY-----"); + if(m.find()) { + String content = m.group(2); + assertTrue(content.startsWith("MIIEpAIBAAKCAQE")); + assertTrue(content.endsWith("KghyqAF1w==\n")); + } else { + assertTrue(false); + } + } + + public void testKeystoreManager() throws Exception { + ComponentLocator locator = ComponentLocator.getCurrentLocator(); + + KeystoreManagerImpl ksMgr = ComponentLocator.inject(KeystoreManagerImpl.class); + assertTrue(ksMgr.configure("TaskManager", new HashMap())); + assertTrue(ksMgr.start()); + + ksMgr.saveCertificate("CPVMCertificate", certContent, keyContent, "realhostip.com"); + + byte[] ksBits = ksMgr.getKeystoreBits("CPVMCertificate", "realhostip", "vmops.com"); + assertTrue(ksBits != null); + + try { + KeyStore ks = CertificateHelper.loadKeystore(ksBits, "vmops.com"); + assertTrue(ks != null); + } catch(Exception e) { + assertTrue(false); + } + + KeystoreDao ksDao = locator.getDao(KeystoreDao.class); + KeystoreVO ksVo = ksDao.findByName("CPVMCertificate"); + ksDao.expunge(ksVo.getId()); + } +} diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index a7f7fbb529d..0c635b3426e 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -1494,4 +1494,14 @@ CREATE TABLE `cloud`.`cmd_exec_log` ( CONSTRAINT `fk_cmd_exec_log_ref__inst_id` FOREIGN KEY (`instance_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +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', + `domain_suffix` varchar(256) NOT NULL COMMENT 'DNS domain suffix associated with the certificate', + PRIMARY KEY (`id`), + UNIQUE(name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + SET foreign_key_checks = 1;