mirror of https://github.com/apache/cloudstack.git
FR12: Have basic constraint in CA certificate (#52)
* FR12: Have basic constraint in CA certificate - Refactors certificate generation to use V3 - Removes use of V1 based certificate generator - Puts basic constraint and keyusage extentions in certificate generator when caCert is not provided, i.e. for building CA certificate - For normal certificate generation, skips putting basic constraint instead puts authority key identifier (the ca cert) - Fixes tests to use the V3 certificate generator Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com> * FR12: backup and restore cpvm/ssvm keystore during reboot This is backported from: https://github.com/apache/cloudstack/pull/2278 Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
parent
5cd57a5011
commit
1f52cd4245
|
|
@ -35,7 +35,6 @@ import java.security.SecureRandom;
|
|||
import java.security.Security;
|
||||
import java.security.SignatureException;
|
||||
import java.security.UnrecoverableKeyException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateExpiredException;
|
||||
import java.security.cert.CertificateNotYetValidException;
|
||||
|
|
@ -139,11 +138,12 @@ public final class RootCAProvider extends AdapterBase implements CAProvider, Con
|
|||
final String subject = "CN=" + domainNames.get(0);
|
||||
|
||||
final KeyPair keyPair = CertUtils.generateRandomKeyPair(CAManager.CertKeySize.value());
|
||||
final X509Certificate clientCertificate = CertUtils.generateV3Certificate(
|
||||
final X509Certificate clientCertificate = CertUtils.generateCertificate(
|
||||
caCertificate,
|
||||
caKeyPair.getPrivate(),
|
||||
caKeyPair,
|
||||
keyPair.getPublic(),
|
||||
subject,
|
||||
caCertificate.getIssuerDN().getName(),
|
||||
CAManager.CertSignatureAlgorithm.value(),
|
||||
validityDays,
|
||||
domainNames,
|
||||
|
|
@ -167,10 +167,11 @@ public final class RootCAProvider extends AdapterBase implements CAProvider, Con
|
|||
|
||||
final PKCS10CertificationRequest request = new PKCS10CertificationRequest(pemObject.getContent());
|
||||
|
||||
final X509Certificate clientCertificate = CertUtils.generateV3Certificate(
|
||||
caCertificate, caKeyPair.getPrivate(),
|
||||
final X509Certificate clientCertificate = CertUtils.generateCertificate(
|
||||
caCertificate, caKeyPair,
|
||||
request.getPublicKey(),
|
||||
request.getCertificationRequestInfo().getSubject().toString(),
|
||||
caCertificate.getIssuerDN().getName(),
|
||||
CAManager.CertSignatureAlgorithm.value(),
|
||||
validityDays,
|
||||
domainNames,
|
||||
|
|
@ -461,16 +462,18 @@ public final class RootCAProvider extends AdapterBase implements CAProvider, Con
|
|||
}
|
||||
try {
|
||||
LOG.debug("Generating root CA certificate");
|
||||
final X509Certificate rootCaCertificate = CertUtils.generateV1Certificate(
|
||||
final X509Certificate rootCaCertificate = CertUtils.generateCertificate(
|
||||
null,
|
||||
caKeyPair,
|
||||
caKeyPair.getPublic(),
|
||||
rootCAIssuerDN.value(),
|
||||
rootCAIssuerDN.value(),
|
||||
caValidityYears,
|
||||
CAManager.CertSignatureAlgorithm.value());
|
||||
CAManager.CertSignatureAlgorithm.value(),
|
||||
caValidityYears * 365, null, null);
|
||||
if (!configDao.update(rootCACertificate.key(), rootCACertificate.category(), CertUtils.x509CertificateToPem(rootCaCertificate))) {
|
||||
LOG.error("Failed to update RootCA public/x509 certificate");
|
||||
}
|
||||
} catch (final NoSuchAlgorithmException | NoSuchProviderException | CertificateEncodingException | SignatureException | InvalidKeyException | IOException e) {
|
||||
} catch (final NoSuchAlgorithmException | NoSuchProviderException | CertificateException | SignatureException | InvalidKeyException | IOException e) {
|
||||
LOG.error("Failed to generate RootCA certificate from private/public keys due to exception:", e);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@ public class RootCACustomTrustManagerTest {
|
|||
certMap.clear();
|
||||
caKeypair = CertUtils.generateRandomKeyPair(1024);
|
||||
clientKeypair = CertUtils.generateRandomKeyPair(1024);
|
||||
caCertificate = CertUtils.generateV1Certificate(caKeypair, "CN=ca", "CN=ca", 1,
|
||||
"SHA256withRSA");
|
||||
expiredClientCertificate = CertUtils.generateV3Certificate(caCertificate, caKeypair.getPrivate(), clientKeypair.getPublic(),
|
||||
"CN=cloudstack.apache.org", "SHA256withRSA", 0, Collections.singletonList("cloudstack.apache.org"), Collections.singletonList(clientIp));
|
||||
caCertificate = CertUtils.generateCertificate(null, caKeypair, caKeypair.getPublic(), "CN=ca", "CN=ca",
|
||||
"SHA256withRSA", 1, null, null);
|
||||
expiredClientCertificate = CertUtils.generateCertificate(caCertificate, caKeypair, clientKeypair.getPublic(),
|
||||
"CN=cloudstack.apache.org", caCertificate.getIssuerDN().getName(), "SHA256withRSA", 0, Collections.singletonList("cloudstack.apache.org"), Collections.singletonList(clientIp));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ public class RootCAProviderTest {
|
|||
@Before
|
||||
public void setUp() throws Exception {
|
||||
caKeyPair = CertUtils.generateRandomKeyPair(1024);
|
||||
caCertificate = CertUtils.generateV1Certificate(caKeyPair, "CN=ca", "CN=ca", 1, "SHA256withRSA");
|
||||
caCertificate = CertUtils.generateCertificate(null, caKeyPair, caKeyPair.getPublic(), "CN=ca", "CN=ca", "SHA256withRSA", 1, null, null);
|
||||
|
||||
provider = new RootCAProvider();
|
||||
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ public class CABackgroundTaskTest {
|
|||
host.setManagementServerId(ManagementServerNode.getManagementServerId());
|
||||
task = new CAManagerImpl.CABackgroundTask(caManager, hostDao);
|
||||
final KeyPair keypair = CertUtils.generateRandomKeyPair(1024);
|
||||
expiredCertificate = CertUtils.generateV1Certificate(keypair, "CN=ca", "CN=ca", 0,
|
||||
"SHA256withRSA");
|
||||
expiredCertificate = CertUtils.generateCertificate(null, keypair, keypair.getPublic(), "CN=ca", "CN=ca",
|
||||
"SHA256withRSA", 0, null, null);
|
||||
|
||||
Mockito.when(hostDao.findByIp(Mockito.anyString())).thenReturn(host);
|
||||
Mockito.when(caManager.getActiveCertificatesMap()).thenReturn(certMap);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ package org.apache.cloudstack.ca;
|
|||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPair;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Collections;
|
||||
|
||||
|
|
@ -108,7 +109,8 @@ public class CAManagerImplTest {
|
|||
public void testProvisionCertificate() throws Exception {
|
||||
final Host host = Mockito.mock(Host.class);
|
||||
Mockito.when(host.getPrivateIpAddress()).thenReturn("1.2.3.4");
|
||||
final X509Certificate certificate = CertUtils.generateV1Certificate(CertUtils.generateRandomKeyPair(1024), "CN=ca", "CN=ca", 1, "SHA256withRSA");
|
||||
final KeyPair keyPair = CertUtils.generateRandomKeyPair(1024);
|
||||
final X509Certificate certificate = CertUtils.generateCertificate(null, keyPair, keyPair.getPublic(), "CN=ca", "CN=ca", "SHA256withRSA", 1, null, null);
|
||||
Mockito.when(caProvider.issueCertificate(Mockito.anyString(), Mockito.anyList(), Mockito.anyList(), Mockito.anyInt())).thenReturn(new Certificate(certificate, null, Collections.singletonList(certificate)));
|
||||
Mockito.when(agentManager.send(Mockito.anyLong(), Mockito.any(SetupKeyStoreCommand.class))).thenReturn(new SetupKeystoreAnswer("someCsr"));
|
||||
Mockito.when(agentManager.reconnect(Mockito.anyLong())).thenReturn(true);
|
||||
|
|
|
|||
|
|
@ -21,10 +21,21 @@ logfile="/var/log/patchsystemvm.log"
|
|||
# To use existing console proxy .zip-based package file
|
||||
patch_console_proxy() {
|
||||
local patchfile=$1
|
||||
local backupfolder="/tmp/.conf.backup"
|
||||
if [ -f /usr/local/cloud/systemvm/conf/cloud.jks ]; then
|
||||
rm -fr $backupfolder
|
||||
mkdir -p $backupfolder
|
||||
cp -r /usr/local/cloud/systemvm/conf/* $backupfolder/
|
||||
fi
|
||||
rm /usr/local/cloud/systemvm -rf
|
||||
mkdir -p /usr/local/cloud/systemvm
|
||||
echo "All" | unzip $patchfile -d /usr/local/cloud/systemvm >$logfile 2>&1
|
||||
find /usr/local/cloud/systemvm/ -name \*.sh | xargs chmod 555
|
||||
if [ -f $backupfolder/cloud.jks ]; then
|
||||
cp -r $backupfolder/* /usr/local/cloud/systemvm/conf/
|
||||
echo "Restored keystore file and certs using backup" >> $logfile
|
||||
fi
|
||||
rm -fr $backupfolder
|
||||
return 0
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import java.security.PublicKey;
|
|||
import java.security.SecureRandom;
|
||||
import java.security.Security;
|
||||
import java.security.SignatureException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
|
|
@ -48,13 +47,14 @@ import javax.security.auth.x500.X500Principal;
|
|||
import org.apache.log4j.Logger;
|
||||
import org.bouncycastle.asn1.ASN1Encodable;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.x509.BasicConstraints;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.asn1.x509.KeyUsage;
|
||||
import org.bouncycastle.asn1.x509.X509Extensions;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.openssl.PEMReader;
|
||||
import org.bouncycastle.openssl.PEMWriter;
|
||||
import org.bouncycastle.util.io.pem.PemObject;
|
||||
import org.bouncycastle.x509.X509V1CertificateGenerator;
|
||||
import org.bouncycastle.x509.X509V3CertificateGenerator;
|
||||
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
|
||||
import org.bouncycastle.x509.extension.SubjectKeyIdentifierStructure;
|
||||
|
|
@ -145,47 +145,56 @@ public class CertUtils {
|
|||
return new BigInteger(64, new SecureRandom());
|
||||
}
|
||||
|
||||
public static X509Certificate generateV1Certificate(final KeyPair keyPair,
|
||||
final String subjectDN,
|
||||
final String issuerDN,
|
||||
final int validityYears,
|
||||
final String signatureAlgorithm) throws NoSuchAlgorithmException, NoSuchProviderException, CertificateEncodingException, SignatureException, InvalidKeyException {
|
||||
final DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
final X500Principal subjectDn = new X500Principal(subjectDN);
|
||||
final X500Principal issuerDn = new X500Principal(issuerDN);
|
||||
final X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
|
||||
certGen.setSerialNumber(generateRandomBigInt());
|
||||
certGen.setSubjectDN(subjectDn);
|
||||
certGen.setIssuerDN(issuerDn);
|
||||
certGen.setNotBefore(now.minusDays(1).toDate());
|
||||
certGen.setNotAfter(now.plusYears(validityYears).toDate());
|
||||
certGen.setPublicKey(keyPair.getPublic());
|
||||
certGen.setSignatureAlgorithm(signatureAlgorithm);
|
||||
return certGen.generate(keyPair.getPrivate(), "BC");
|
||||
}
|
||||
|
||||
public static X509Certificate generateV3Certificate(final X509Certificate caCert,
|
||||
final PrivateKey caPrivateKey,
|
||||
final PublicKey clientPublicKey,
|
||||
final String subjectDN,
|
||||
final String signatureAlgorithm,
|
||||
final int validityDays,
|
||||
final List<String> dnsNames,
|
||||
final List<String> publicIPAddresses) throws IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException, InvalidKeyException, SignatureException {
|
||||
/**
|
||||
* Generates a X509 V3 Certificate based on provided arguments
|
||||
* @param caCert when caCert is not provided self-signed root CA certificate is generated with basic constraints
|
||||
* @param caKeyPair the ca KeyPair that contains public and private keys
|
||||
* @param clientPublicKey the client public key, for CA self-signing this will be CA public key
|
||||
* @param subjectDN
|
||||
* @param issuerDN
|
||||
* @param signatureAlgorithm
|
||||
* @param validityDays
|
||||
* @param dnsNames
|
||||
* @param publicIPAddresses
|
||||
* @return returns a X509Certificate
|
||||
* @throws IOException
|
||||
* @throws NoSuchAlgorithmException
|
||||
* @throws CertificateException
|
||||
* @throws NoSuchProviderException
|
||||
* @throws InvalidKeyException
|
||||
* @throws SignatureException
|
||||
*/
|
||||
public static X509Certificate generateCertificate(final X509Certificate caCert,
|
||||
final KeyPair caKeyPair,
|
||||
final PublicKey clientPublicKey,
|
||||
final String subjectDN,
|
||||
final String issuerDN,
|
||||
final String signatureAlgorithm,
|
||||
final int validityDays,
|
||||
final List<String> dnsNames,
|
||||
final List<String> publicIPAddresses) throws IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException, InvalidKeyException, SignatureException {
|
||||
final DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
final BigInteger serial = generateRandomBigInt();
|
||||
final X500Principal subject = new X500Principal(subjectDN);
|
||||
final X500Principal issuer = new X500Principal(issuerDN);
|
||||
|
||||
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();;
|
||||
certGen.setSerialNumber(serial);
|
||||
certGen.setIssuerDN(caCert.getSubjectX500Principal());
|
||||
certGen.setSubjectDN(subject);
|
||||
certGen.setIssuerDN(issuer);
|
||||
certGen.setNotBefore(now.minusHours(12).toDate());
|
||||
certGen.setNotAfter(now.plusDays(validityDays).toDate());
|
||||
certGen.setPublicKey(clientPublicKey);
|
||||
certGen.setSignatureAlgorithm(signatureAlgorithm);
|
||||
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
|
||||
new AuthorityKeyIdentifierStructure(caCert));
|
||||
if (caCert == null) {
|
||||
certGen.addExtension(X509Extensions.BasicConstraints, true,
|
||||
new BasicConstraints(true, 0));
|
||||
certGen.addExtension(X509Extensions.KeyUsage, true,
|
||||
new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));
|
||||
} else {
|
||||
certGen.addExtension(X509Extensions.AuthorityKeyIdentifier, false,
|
||||
new AuthorityKeyIdentifierStructure(caCert));
|
||||
}
|
||||
certGen.addExtension(X509Extensions.SubjectKeyIdentifier, false,
|
||||
new SubjectKeyIdentifierStructure(clientPublicKey));
|
||||
|
||||
|
|
@ -212,8 +221,8 @@ public class CertUtils {
|
|||
certGen.addExtension(X509Extensions.SubjectAlternativeName, false,
|
||||
subjectAlternativeNamesExtension);
|
||||
}
|
||||
final X509Certificate certificate = certGen.generate(caPrivateKey, "BC");
|
||||
certificate.verify(caCert.getPublicKey());
|
||||
final X509Certificate certificate = certGen.generate(caKeyPair.getPrivate(), "BC");
|
||||
certificate.verify(caKeyPair.getPublic());
|
||||
return certificate;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class CertUtilsTest {
|
|||
@Before
|
||||
public void setUp() throws Exception {
|
||||
caKeyPair = CertUtils.generateRandomKeyPair(1024);
|
||||
caCertificate = CertUtils.generateV1Certificate(caKeyPair, "CN=test", "CN=test", 1, "SHA256WithRSAEncryption");
|
||||
caCertificate = CertUtils.generateCertificate(null, caKeyPair, caKeyPair.getPublic(), "CN=test", "CN=test", "SHA256WithRSAEncryption", 365, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -93,8 +93,8 @@ public class CertUtilsTest {
|
|||
final List<String> domainNames = Arrays.asList("domain1.com", "www.2.domain2.com", "3.domain3.com");
|
||||
final List<String> addressList = Arrays.asList("1.2.3.4", "192.168.1.1", "2a02:120b:2c16:f6d0:d9df:8ebc:e44a:f181");
|
||||
|
||||
final X509Certificate clientCert = CertUtils.generateV3Certificate(caCertificate, caKeyPair.getPrivate(), clientKeyPair.getPublic(),
|
||||
"CN=domain.example", "SHA256WithRSAEncryption", 10, domainNames, addressList);
|
||||
final X509Certificate clientCert = CertUtils.generateCertificate(caCertificate, caKeyPair, clientKeyPair.getPublic(),
|
||||
"CN=domain.example", caCertificate.getIssuerDN().getName(), "SHA256WithRSAEncryption", 10, domainNames, addressList);
|
||||
|
||||
clientCert.verify(caKeyPair.getPublic());
|
||||
Assert.assertEquals(clientCert.getIssuerDN(), caCertificate.getIssuerDN());
|
||||
|
|
|
|||
Loading…
Reference in New Issue