NIFI-7783 Add CA Common Name as DNS Subject Alternative Name

This closes #4709

Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
Moncef Abboud 2020-12-04 11:33:56 +01:00 committed by exceptionfactory
parent e0a8b479fd
commit 5fea9179c4
No known key found for this signature in database
GPG Key ID: 29B6A52D2AAE8DBA
2 changed files with 38 additions and 0 deletions

View File

@ -56,6 +56,7 @@ import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.RDN;
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;
@ -63,6 +64,8 @@ import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
@ -469,6 +472,12 @@ public final class CertificateUtils {
// (2) extendedKeyUsage extension
certBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth}));
// (3) subjectAlternativeName extension. Include CN as a SAN entry if it exists.
final String cn = getCommonName(dn);
if (StringUtils.isNotBlank(cn)) {
certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(new GeneralName(GeneralName.dNSName, cn)));
}
// Sign the certificate
X509CertificateHolder certificateHolder = certBuilder.build(sigGen);
return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certificateHolder);
@ -625,6 +634,20 @@ public final class CertificateUtils {
}
}
/**
* Extracts the common name from the given DN.
*
* @param dn the distinguished name to evaluate
* @return the common name if it exists, null otherwise.
*/
public static String getCommonName(final String dn) {
RDN[] rdns = new X500Name(dn).getRDNs(BCStyle.CN);
if (rdns.length == 0) {
return null;
}
return IETFUtils.valueToString(rdns[0].getFirst().getValue());
}
private CertificateUtils() {
}
}

View File

@ -432,6 +432,15 @@ class CertificateUtilsTest extends GroovyTestCase {
assert !dn1MatchesEmpty
}
@Test
void testGetCommonName(){
String dn1 = "CN=testDN,O=testOrg"
String dn2 = "O=testDN,O=testOrg"
assertEquals("testDN", CertificateUtils.getCommonName(dn1))
assertNull(CertificateUtils.getCommonName(dn2))
}
@Test
void testShouldGenerateSelfSignedCert() throws Exception {
String dn = "CN=testDN,O=testOrg"
@ -451,6 +460,12 @@ class CertificateUtilsTest extends GroovyTestCase {
assertEquals(SIGNATURE_ALGORITHM.toUpperCase(), x509Certificate.getSigAlgName().toUpperCase())
assertEquals("RSA", x509Certificate.getPublicKey().getAlgorithm())
assertEquals(1, x509Certificate.getSubjectAlternativeNames().size())
GeneralName gn = x509Certificate.getSubjectAlternativeNames().iterator().next()
assertEquals(GeneralName.dNSName, gn.getTagNo())
assertEquals("testDN", gn.getName().toString())
x509Certificate.checkValidity()
}