Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve interoperability between self-signer in dev environments with openssl generated certs #2495

Merged
merged 1 commit into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x500.X500NameBuilder;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -42,15 +46,6 @@
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x500.style.IETFUtils;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.ExtensionsGenerator;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.pkcs.Attribute;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
Expand Down Expand Up @@ -1368,13 +1363,33 @@ public static String extractX509CertPublicKey(X509Certificate x509Cert) {
return convertToPEMFormat(publicKey);
}

public static X500Name utf8DEREncodedIssuer(final String issuer) {

X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE);
X500Name x500Name = new X500Name(issuer);
RDN[] rdns = x500Name.getRDNs();

// for compatibility with openssl generated certificates
// we're going to make sure all the RDNs in the issuer
// field are encoded as UTF8Strings except for C field
// which is encoded as a PrintableString

for (int i = rdns.length - 1; i >= 0; i--) {
ASN1ObjectIdentifier asn1ObjectIdentifier = rdns[i].getFirst().getType();
ASN1Encodable value = (asn1ObjectIdentifier == BCStyle.C) ?
new DERPrintableString(IETFUtils.valueToString(rdns[i].getFirst().getValue())) :
new DERUTF8String(IETFUtils.valueToString(rdns[i].getFirst().getValue()));
builder.addRDN(asn1ObjectIdentifier, value);
}
return builder.build();
}

public static X509Certificate generateX509Certificate(PKCS10CertificationRequest certReq,
PrivateKey caPrivateKey, X509Certificate caCertificate, int validityTimeout,
boolean basicConstraints) {

return generateX509Certificate(certReq, caPrivateKey,
X500Name.getInstance(caCertificate.getSubjectX500Principal().getEncoded()),
validityTimeout, basicConstraints);
X500Name issuer = utf8DEREncodedIssuer(caCertificate.getSubjectX500Principal().getName());
return generateX509Certificate(certReq, caPrivateKey, issuer, validityTimeout, basicConstraints);
}

public static X509Certificate generateX509Certificate(PKCS10CertificationRequest certReq,
Expand All @@ -1396,15 +1411,28 @@ public static X509Certificate generateX509Certificate(PKCS10CertificationRequest
JcaPKCS10CertificationRequest jcaPKCS10CertificationRequest = new JcaPKCS10CertificationRequest(certReq);
PublicKey publicKey = jcaPKCS10CertificationRequest.getPublicKey();

X509v3CertificateBuilder caBuilder = new JcaX509v3CertificateBuilder(
issuer, BigInteger.valueOf(System.currentTimeMillis()),
notBefore, notAfter, certReq.getSubject(), publicKey)
.addExtension(Extension.basicConstraints, false,
SecureRandom random = new SecureRandom();
BigInteger serial = new BigInteger(160, random);

X509v3CertificateBuilder caBuilder = new JcaX509v3CertificateBuilder(issuer, serial,
notBefore, notAfter, certReq.getSubject(), publicKey)
.addExtension(Extension.basicConstraints, basicConstraints,
new BasicConstraints(basicConstraints))
.addExtension(Extension.keyUsage, true,
.addExtension(Extension.extendedKeyUsage, false,
new ExtendedKeyUsage(new KeyPurposeId[]
{ KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth }));

if (basicConstraints) {
caBuilder = caBuilder.addExtension(Extension.keyUsage, false,
new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.keyEncipherment |
X509KeyUsage.keyCertSign | X509KeyUsage.cRLSign));
} else {
final PublicKey caPublicKey = extractPublicKey(caPrivateKey);
caBuilder = caBuilder.addExtension(Extension.keyUsage, false,
new X509KeyUsage(X509KeyUsage.digitalSignature | X509KeyUsage.keyEncipherment))
.addExtension(Extension.extendedKeyUsage, true,
new ExtendedKeyUsage(new KeyPurposeId[]{ KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth }));
.addExtension(Extension.authorityKeyIdentifier, false,
new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(caPublicKey));
}

// see if we have the dns/rfc822/ip address extensions specified in the csr

Expand Down Expand Up @@ -1442,23 +1470,19 @@ public static X509Certificate generateX509Certificate(PKCS10CertificationRequest
JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(BC_PROVIDER);
cert = converter.getCertificate(caBuilder.build(caSigner));
} catch (CertificateException ex) {
LOG.error("generateX509Certificate: Caught CertificateException when generating certificate: "
+ ex.getMessage());
LOG.error("generateX509Certificate: Caught CertificateException when generating certificate", ex);
throw new CryptoException(ex);
} catch (OperatorCreationException ex) {
LOG.error("generateX509Certificate: Caught OperatorCreationException when creating JcaContentSignerBuilder: "
+ ex.getMessage());
LOG.error("generateX509Certificate: Caught OperatorCreationException when creating JcaContentSignerBuilder", ex);
throw new CryptoException(ex);
} catch (InvalidKeyException ex) {
LOG.error("generateX509Certificate: Caught InvalidKeySpecException, invalid key spec is being used: "
+ ex.getMessage());
LOG.error("generateX509Certificate: Caught InvalidKeySpecException, invalid key spec is being used", ex);
throw new CryptoException(ex);
} catch (NoSuchAlgorithmException ex) {
LOG.error("generateX509Certificate: Caught NoSuchAlgorithmException, check to make sure the algorithm is supported by the provider: "
+ ex.getMessage());
LOG.error("generateX509Certificate: Caught NoSuchAlgorithmException, check to make sure the algorithm is supported by the provider", ex) ;
throw new CryptoException(ex);
} catch (Exception ex) {
LOG.error("generateX509Certificate: unable to generate X509 Certificate: {}", ex.getMessage());
LOG.error("generateX509Certificate: unable to generate X509 Certificate", ex);
throw new CryptoException("Unable to generate X509 Certificate");
}
return cert;
Expand Down
8 changes: 8 additions & 0 deletions servers/zts/conf/dev_x509_ext.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
basicConstraints = CA:FALSE
authorityKeyIdentifier=keyid,issuer
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = __athenz_hostname__
17 changes: 17 additions & 0 deletions servers/zts/conf/dev_x509ca_cert.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[req]
default_bits = 1024
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req

[ dn ]
C = US
ST = CA
O = Athenz
OU = Testing Domain
CN = Athenz CA

[ v3_req ]
basicConstraints = critical, CA:TRUE
keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign
15 changes: 15 additions & 0 deletions servers/zts/conf/self_x509_cert.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = dn
x509_extensions = v3_req

[ dn ]
C = US
O = Athenz
CN = Self Signed Athenz CA

[ v3_req ]
basicConstraints = critical, CA:TRUE
keyUsage = critical, digitalSignature, keyEncipherment, keyCertSign
25 changes: 22 additions & 3 deletions servers/zts/scripts/setup_dev_zts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,32 +25,51 @@ cd $ROOT/var/zts_server/keys
openssl genrsa -out zts_private.pem 2048
openssl rsa -in zts_private.pem -pubout > zts_public.pem

# Generate a self-signed CA certificate for the server

echo "Generating a self signed CA certificate for ZTS Server..."

cd ../certs
cp $ROOT/conf/zts_server/dev_x509ca_cert.cnf ./dev_x509ca_cert.cnf
openssl req -x509 -nodes -newkey rsa:2048 -keyout zts_key.pem -out zts_ca_cert.pem -days 3650 -config ./dev_x509ca_cert.cnf

# Generate a self-signed x509 certificate

echo "Generating a self signed certificate for ZTS Server..."
cd ../certs

ZTS_HOSTNAME=$(hostname -f)
sed s/__athenz_hostname__/$ZTS_HOSTNAME/g $ROOT/conf/zts_server/dev_x509_cert.cnf > ./dev_x509_cert.cnf
openssl req -x509 -nodes -newkey rsa:2048 -keyout zts_key.pem -out zts_cert.pem -days 365 -config ./dev_x509_cert.cnf
sed s/__athenz_hostname__/$ZTS_HOSTNAME/g $ROOT/conf/zts_server/dev_x509_ext.cnf > ./dev_x509_ext.cnf
openssl req -key zts_key.pem -new -out zts.csr -config dev_x509_cert.cnf
openssl x509 -req -CA zts_ca_cert.pem -CAkey zts_key.pem -in zts.csr -out zts_cert.pem -days 365 -CAcreateserial -extfile dev_x509_ext.cnf

# Generate a keystore in PKCS#12 format

echo "Generating PKCS12 keystore for ZTS Server..."
rm -rf zts_keystore.pkcs12
openssl pkcs12 -export -out zts_keystore.pkcs12 -in zts_cert.pem -inkey zts_key.pem -noiter -password pass:athenz

# Generate a truststore in JKS format
# Generate a truststore in JKS format for connecting to ZMS Server

echo "Generating JKS truststore for ZTS Server..."
rm -rf zts_truststore.jks
cp $ZMS_CERT $ROOT/var/zts_server/certs/zms_cert.pem
keytool -importcert -noprompt -alias zms -keystore zts_truststore.jks -file zms_cert.pem -storepass athenz

# Generate a truststore in JKS format for ZTS clients using mTLS

echo "Generating JKS truststore for ZTS Server..."
rm -rf zts_client_truststore.jks
cp $ROOT/conf/zts_server/self_x509_cert.cnf ./self_x509_cert.cnf
openssl req -x509 -nodes -key $ROOT/var/zts_server/keys/zts_private.pem -out self_ca_cert.pem -days 3650 -config ./self_x509_cert.cnf
keytool -importcert -noprompt -alias self -keystore zts_client_truststore.jks -file self_ca_cert.pem -storepass athenz

# Register ZTS Server in ZMS Server

echo "Registering ZTS Service in Athenz..."
cd $ROOT
HOST_PLATFORM=$(uname | tr '[:upper:]' '[:lower:]')
$ROOT/bin/$HOST_PLATFORM/zms-cli -c $ROOT/var/zts_server/certs/zms_cert.pem -z https://$ZMS_HOSTNAME:4443/zms/v1 -d sys.auth delete-service zts
$ROOT/bin/$HOST_PLATFORM/zms-cli -c $ROOT/var/zts_server/certs/zms_cert.pem -z https://$ZMS_HOSTNAME:4443/zms/v1 -d sys.auth add-service zts 0 $ROOT/var/zts_server/keys/zts_public.pem

# Generate athenz configuration file
Expand Down
2 changes: 1 addition & 1 deletion servers/zts/scripts/zts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ JAVA_OPTS="${JAVA_OPTS} -Dathenz.prop_file=${ROOT}/conf/zts_server/athenz.proper
JAVA_OPTS="${JAVA_OPTS} -Dathenz.zts.prop_file=${ROOT}/conf/zts_server/zts.properties"
JAVA_OPTS="${JAVA_OPTS} -Dlogback.configurationFile=${ROOT}/conf/zts_server/logback.xml"
JAVA_OPTS="${JAVA_OPTS} -Dathenz.ssl_key_store=${ROOT}/var/zts_server/certs/zts_keystore.pkcs12"
JAVA_OPTS="${JAVA_OPTS} -Dathenz.ssl_trust_store=${ROOT}/var/zts_server/certs/zts_truststore.jks"
JAVA_OPTS="${JAVA_OPTS} -Dathenz.ssl_trust_store=${ROOT}/var/zts_server/certs/zts_client_truststore.jks"
JAVA_OPTS="${JAVA_OPTS} -Dathenz.zts.ssl_key_store=${ROOT}/var/zts_server/certs/zts_keystore.pkcs12"
JAVA_OPTS="${JAVA_OPTS} -Dathenz.zts.ssl_trust_store=${ROOT}/var/zts_server/certs/zts_truststore.jks"
JAVA_OPTS="${JAVA_OPTS} -Djavax.net.ssl.trustStore=${ROOT}/var/zts_server/certs/zts_truststore.jks"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@

public class KeyStoreCertSigner implements CertSigner, AutoCloseable {

private X509Certificate caCertificate;
private PrivateKey caPrivateKey;
private int maxCertExpiryTimeMins;
private final X509Certificate caCertificate;
private final PrivateKey caPrivateKey;
private final int maxCertExpiryTimeMins;

public KeyStoreCertSigner(X509Certificate caCertificate, PrivateKey caPrivateKey, int maxCertExpiryTimeMins) {
this.caCertificate = caCertificate;
Expand All @@ -41,11 +41,12 @@ public String generateX509Certificate(String provider, String certIssuer, String
}

@Override
public String generateX509Certificate(String provider, String certIssuer, String csr, String keyUsage, int certExpiryMins, Priority priority) {
public String generateX509Certificate(String provider, String certIssuer, String csr, String keyUsage,
int certExpiryMins, Priority priority) {

int certExpiryTime = (certExpiryMins == 0) ? this.maxCertExpiryTimeMins : certExpiryMins;

PKCS10CertificationRequest certReq = Crypto.getPKCS10CertRequest(csr);
// keyUsage is ignored
X509Certificate cert = Crypto.generateX509Certificate(certReq, caPrivateKey, caCertificate, certExpiryTime, false);

return Crypto.convertToPEMFormat(cert);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
import org.bouncycastle.pkcs.PKCS10CertificationRequest;

import java.io.IOException;
import javax.security.auth.x500.X500Principal;

public class SelfCertSignerFactory implements CertSignerFactory {

Expand All @@ -47,7 +46,7 @@ public CertSigner create() {
final String pKeyFileName = System.getProperty(ZTSConsts.ZTS_PROP_SELF_SIGNER_PRIVATE_KEY_FNAME);
final String pKeyPassword = System.getProperty(ZTSConsts.ZTS_PROP_SELF_SIGNER_PRIVATE_KEY_PASSWORD);
final String csrDn = System.getProperty(ZTSConsts.ZTS_PROP_SELF_SIGNER_CERT_DN,
"cn=Self Signed Athenz CA,o=Athenz,c=US");
"CN=Self Signed Athenz CA, O=Athenz, C=US");
final int maxCertExpiryTimeMins = Integer.parseInt(System.getProperty(ZTSConsts.ZTS_PROP_CERTSIGN_MAX_EXPIRY_TIME, "43200"));

if (StringUtil.isEmpty(pKeyFileName)) {
Expand All @@ -69,12 +68,11 @@ public CertSigner create() {
}

// generate our self-signed certificate

X500Principal subject = new X500Principal(csrDn);
X500Name issuer = X500Name.getInstance(subject.getEncoded());

X500Name issuer = Crypto.utf8DEREncodedIssuer(csrDn);
PKCS10CertificationRequest certReq = Crypto.getPKCS10CertRequest(csr);
X509Certificate caCertificate = Crypto.generateX509Certificate(certReq,
caPrivateKey, issuer, 30 * 24 * 60, true);
caPrivateKey, issuer, 365 * 24 * 60, true);

return new KeyStoreCertSigner(caCertificate, caPrivateKey, maxCertExpiryTimeMins);
}
Expand Down