Adding utility methods for generating x509 certificates for testing purposes.
Adding jacoco test coverage report plugin. Adding and improving tests for X509SvidValidator and CertificateUtils. Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
This commit is contained in:
parent
ef4dbf86c5
commit
ef2cdafab9
23
build.gradle
23
build.gradle
|
|
@ -3,6 +3,7 @@ subprojects {
|
|||
version '0.6.0'
|
||||
|
||||
apply plugin: 'java-library'
|
||||
apply plugin: 'jacoco'
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
|
|
@ -13,6 +14,28 @@ subprojects {
|
|||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
finalizedBy jacocoTestReport
|
||||
|
||||
}
|
||||
|
||||
jacocoTestReport {
|
||||
dependsOn test // tests are required to run before generating the report
|
||||
reports {
|
||||
xml.enabled false
|
||||
csv.enabled false
|
||||
html.destination file("${buildDir}/jacocoHtml")
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
classDirectories.setFrom(files(classDirectories.files.collect {
|
||||
fileTree(dir: it, exclude: ['**/internal/**', '**/exception/**'])
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.5"
|
||||
reportsDir = file("$buildDir/customJacocoReportDir")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
|
|||
|
|
@ -56,5 +56,8 @@ dependencies {
|
|||
|
||||
// library for processing JWT tokens and JOSE JWK bundles
|
||||
implementation group: 'com.nimbusds', name: 'nimbus-jose-jwt', version: '5.7'
|
||||
|
||||
// using bouncy castle for generating x509 certs for testing purposes
|
||||
testImplementation group: 'org.bouncycastle', name: 'bcpkix-jdk15on', version: '1.65'
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import java.util.List;
|
|||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Collections.EMPTY_LIST;
|
||||
import static org.apache.commons.lang3.StringUtils.startsWith;
|
||||
|
||||
/**
|
||||
|
|
@ -209,6 +210,9 @@ public class CertificateUtils {
|
|||
}
|
||||
|
||||
private static List<String> getSpiffeIds(X509Certificate certificate) throws CertificateParsingException {
|
||||
if (certificate.getSubjectAlternativeNames() == null) {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
return certificate.getSubjectAlternativeNames()
|
||||
.stream()
|
||||
.map(san -> (String) san.get(SAN_VALUE_INDEX))
|
||||
|
|
|
|||
|
|
@ -3,19 +3,26 @@ package spiffe.internal;
|
|||
import lombok.val;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import spiffe.spiffeid.SpiffeId;
|
||||
import spiffe.spiffeid.TrustDomain;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertPathValidatorException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static spiffe.utils.X509CertificateTestUtils.createCertificate;
|
||||
import static spiffe.utils.X509CertificateTestUtils.createRootCA;
|
||||
|
||||
public class CertificateUtilsTest {
|
||||
|
||||
|
|
@ -24,7 +31,7 @@ public class CertificateUtilsTest {
|
|||
val path = Paths.get(toUri("testdata/internal/cert.pem"));
|
||||
val certBytes = Files.readAllBytes(path);
|
||||
|
||||
List<X509Certificate> x509CertificateList = null;
|
||||
List<X509Certificate> x509CertificateList;
|
||||
SpiffeId spiffeId = null;
|
||||
try {
|
||||
x509CertificateList = CertificateUtils.generateCertificates(certBytes);
|
||||
|
|
@ -55,7 +62,59 @@ public class CertificateUtilsTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGeneratePrivateKey() throws URISyntaxException, IOException {
|
||||
val keyPath = Paths.get(toUri("testdata/internal/privateKeyRsa.pem"));
|
||||
val keyBytes = Files.readAllBytes(keyPath);
|
||||
|
||||
try {
|
||||
PrivateKey privateKey = CertificateUtils.generatePrivateKey(keyBytes);
|
||||
assertNotNull(privateKey);
|
||||
assertEquals("RSA", privateKey.getAlgorithm());
|
||||
} catch (InvalidKeySpecException | InvalidKeyException | NoSuchAlgorithmException e) {
|
||||
fail("Should have generated key", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSpiffeId() throws Exception {
|
||||
val rootCa = createRootCA("C = US, O = SPIFFE", "spiffe://domain.test" );
|
||||
val leaf = createCertificate("C = US, O = SPIRE", "C = US, O = SPIRE", "spiffe://domain.test/workload", rootCa, false);
|
||||
SpiffeId spiffeId = CertificateUtils.getSpiffeId(leaf.getCertificate());
|
||||
assertEquals(SpiffeId.parse("spiffe://domain.test/workload"), spiffeId);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetSpiffeId_certNotContainSpiffeId_throwsCertificateException() throws Exception {
|
||||
val rootCa = createRootCA("C = US, O = SPIFFE", "spiffe://domain.test" );
|
||||
val leaf = createCertificate("C = US, O = SPIRE", "C = US, O = SPIRE", "", rootCa, false);
|
||||
try {
|
||||
CertificateUtils.getSpiffeId(leaf.getCertificate());
|
||||
fail("exception is expected");
|
||||
} catch (CertificateException e) {
|
||||
assertEquals("Certificate does not contain SPIFFE ID in the URI SAN", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetTrustDomain() throws Exception {
|
||||
val rootCa = createRootCA("C = US, O = SPIFFE", "spiffe://domain.test" );
|
||||
val intermediate = createCertificate("C = US, O = SPIRE", "C = US, O = SPIRE", "spiffe://domain.test/host", rootCa, true);
|
||||
val leaf = createCertificate("C = US, O = SPIRE", "C = US, O = SPIRE", "spiffe://domain.test/workload", intermediate, false);
|
||||
|
||||
val chain = Arrays.asList(leaf.getCertificate(), intermediate.getCertificate());
|
||||
|
||||
try {
|
||||
TrustDomain trustDomain = CertificateUtils.getTrustDomain(chain);
|
||||
assertNotNull(trustDomain);
|
||||
assertEquals(TrustDomain.of("domain.test"), trustDomain);
|
||||
} catch (CertificateException e) {
|
||||
fail(e);
|
||||
}
|
||||
}
|
||||
|
||||
private URI toUri(String path) throws URISyntaxException {
|
||||
return getClass().getClassLoader().getResource(path).toURI();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,88 +3,79 @@ package spiffe.svid.x509svid;
|
|||
import lombok.val;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import spiffe.bundle.x509bundle.X509Bundle;
|
||||
import spiffe.bundle.x509bundle.X509BundleSource;
|
||||
import spiffe.exception.BundleNotFoundException;
|
||||
import spiffe.internal.CertificateUtils;
|
||||
import spiffe.spiffeid.SpiffeId;
|
||||
import spiffe.spiffeid.TrustDomain;
|
||||
import spiffe.utils.X509CertificateTestUtils.CertAndKeyPair;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Collections.EMPTY_LIST;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static spiffe.utils.X509CertificateTestUtils.createCertificate;
|
||||
import static spiffe.utils.X509CertificateTestUtils.createRootCA;
|
||||
|
||||
public class X509SvidValidatorTest {
|
||||
|
||||
@Mock
|
||||
X509BundleSource bundleSourceMock;
|
||||
List<X509Certificate> chain;
|
||||
CertAndKeyPair rootCa;
|
||||
CertAndKeyPair otherRootCa;
|
||||
CertAndKeyPair leaf;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
void setUp() throws Exception {
|
||||
rootCa = createRootCA("C = US, O = SPIFFE", "spiffe://example.org" );
|
||||
val intermediate1 = createCertificate("C = US, O = SPIRE", "C = US, O = SPIFFE", "spiffe://example.org/host", rootCa, true);
|
||||
val intermediate2 = createCertificate("C = US, O = SPIRE", "C = US, O = SPIRE", "spiffe://example.org/host2", intermediate1, true);
|
||||
leaf = createCertificate("C = US, O = SPIRE", "C = US, O = SPIRE", "spiffe://example.org/test", intermediate2, false);
|
||||
chain = Arrays.asList(leaf.getCertificate(), intermediate2.getCertificate(), intermediate1.getCertificate());
|
||||
otherRootCa = createRootCA("C = US, O = SPIFFE", "spiffe://example.org" );
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyChain_certificateExpired_throwsCertificateException() throws IOException, CertificateException, BundleNotFoundException, URISyntaxException {
|
||||
val certPath = Paths.get(toUri("testdata/x509svid/cert.pem"));
|
||||
val certBytes = Files.readAllBytes(certPath);
|
||||
val chain = CertificateUtils.generateCertificates(certBytes);
|
||||
void testVerifyChain_chainCanBeVerifiedWithAuthorityInBundle() throws Exception {
|
||||
HashSet<X509Certificate> x509Authorities = new HashSet<>();
|
||||
x509Authorities.add(rootCa.getCertificate());
|
||||
x509Authorities.add(otherRootCa.getCertificate());
|
||||
|
||||
val bundlePath = Paths.get(toUri("testdata/x509svid/bundle.pem"));
|
||||
X509Bundle x509Bundle=
|
||||
X509Bundle.load(
|
||||
TrustDomain.of("example.org"),
|
||||
bundlePath
|
||||
);
|
||||
val x509Bundle = new X509Bundle(TrustDomain.of("example.org"), x509Authorities);
|
||||
X509SvidValidator.verifyChain(chain, x509Bundle);
|
||||
}
|
||||
|
||||
when(bundleSourceMock
|
||||
.getX509BundleForTrustDomain(
|
||||
TrustDomain.of("example.org")))
|
||||
.thenReturn(x509Bundle);
|
||||
@Test
|
||||
void testVerifyChain_chainCannotBeVerifiedWithAuthorityInBundle_throwsCertificateException() throws Exception {
|
||||
HashSet<X509Certificate> x509Authorities = new HashSet<>();
|
||||
x509Authorities.add(otherRootCa.getCertificate());
|
||||
|
||||
val x509Bundle = new X509Bundle(TrustDomain.of("example.org"), x509Authorities);
|
||||
try {
|
||||
X509SvidValidator.verifyChain(chain, bundleSourceMock);
|
||||
fail("Verify chain should have thrown validation exception");
|
||||
X509SvidValidator.verifyChain(chain, x509Bundle);
|
||||
fail("exception is expected");
|
||||
} catch (CertificateException e) {
|
||||
assertEquals("Cert chain cannot be verified", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyChain_noBundleForTrustDomain_throwsBundleNotFoundException() throws IOException, CertificateException, BundleNotFoundException, URISyntaxException {
|
||||
val certPath = Paths.get(toUri("testdata/x509svid/cert.pem"));
|
||||
val certBytes = Files.readAllBytes(certPath);
|
||||
val chain = CertificateUtils.generateCertificates(certBytes);
|
||||
void verifyChain_noBundleForTrustDomain_throwsBundleNotFoundException() throws Exception {
|
||||
HashSet<X509Certificate> x509Authorities = new HashSet<>();
|
||||
x509Authorities.add(otherRootCa.getCertificate());
|
||||
|
||||
val bundlePath = Paths.get(toUri("testdata/x509svid/bundle.pem"));
|
||||
X509Bundle x509Bundle=
|
||||
X509Bundle.load(
|
||||
TrustDomain.of("example.org"),
|
||||
bundlePath
|
||||
);
|
||||
|
||||
when(bundleSourceMock
|
||||
.getX509BundleForTrustDomain(
|
||||
TrustDomain.of("example.org")))
|
||||
.thenThrow(new BundleNotFoundException("No bundle found"));
|
||||
val x509Bundle = new X509Bundle(TrustDomain.of("other.org"), x509Authorities);
|
||||
|
||||
try {
|
||||
X509SvidValidator.verifyChain(chain, bundleSourceMock);
|
||||
X509SvidValidator.verifyChain(chain, x509Bundle);
|
||||
fail("Verify chain should have thrown validation exception");
|
||||
} catch (BundleNotFoundException e) {
|
||||
assertEquals("No bundle found", e.getMessage());
|
||||
assertEquals("No X509 bundle found for trust domain example.org", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -93,13 +84,9 @@ public class X509SvidValidatorTest {
|
|||
val spiffeId1 = SpiffeId.parse("spiffe://example.org/test");
|
||||
val spiffeId2 = SpiffeId.parse("spiffe://example.org/test2");
|
||||
|
||||
val certPath = Paths.get(toUri("testdata/x509svid/cert.pem"));
|
||||
val certBytes = Files.readAllBytes(certPath);
|
||||
val x509Certificate = CertificateUtils.generateCertificates(certBytes);
|
||||
|
||||
val spiffeIdList = Arrays.asList(spiffeId1, spiffeId2);
|
||||
|
||||
X509SvidValidator.verifySpiffeId(x509Certificate.get(0), () -> spiffeIdList);
|
||||
X509SvidValidator.verifySpiffeId(leaf.getCertificate(), () -> spiffeIdList);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -108,12 +95,8 @@ public class X509SvidValidatorTest {
|
|||
val spiffeId2 = SpiffeId.parse("spiffe://example.org/other2");
|
||||
List<SpiffeId> spiffeIdList = Arrays.asList(spiffeId1, spiffeId2);
|
||||
|
||||
val certPath = Paths.get(toUri("testdata/x509svid/cert.pem"));
|
||||
val certBytes = Files.readAllBytes(certPath);
|
||||
val x509Certificate = CertificateUtils.generateCertificates(certBytes);
|
||||
|
||||
try {
|
||||
X509SvidValidator.verifySpiffeId(x509Certificate.get(0), () -> spiffeIdList);
|
||||
X509SvidValidator.verifySpiffeId(leaf.getCertificate(), () -> spiffeIdList);
|
||||
fail("Should have thrown CertificateException");
|
||||
} catch (CertificateException e) {
|
||||
assertEquals("SPIFFE ID spiffe://example.org/test in X.509 certificate is not accepted", e.getMessage());
|
||||
|
|
@ -133,10 +116,7 @@ public class X509SvidValidatorTest {
|
|||
@Test
|
||||
void checkSpiffeId_nullAcceptedSpiffeIdsSuppplier_throwsNullPointerException() throws CertificateException, URISyntaxException, IOException {
|
||||
try {
|
||||
val certPath = Paths.get(toUri("testdata/x509svid/cert.pem"));
|
||||
val certBytes = Files.readAllBytes(certPath);
|
||||
val x509Certificate = CertificateUtils.generateCertificates(certBytes);
|
||||
X509SvidValidator.verifySpiffeId(x509Certificate.get(0), null);
|
||||
X509SvidValidator.verifySpiffeId(leaf.getCertificate(), null);
|
||||
fail("should have thrown an exception");
|
||||
} catch (NullPointerException e) {
|
||||
assertEquals("acceptedSpiffedIdsSupplier is marked non-null but is null", e.getMessage());
|
||||
|
|
@ -146,7 +126,7 @@ public class X509SvidValidatorTest {
|
|||
@Test
|
||||
void verifyChain_nullChain_throwsNullPointerException() throws CertificateException, BundleNotFoundException {
|
||||
try {
|
||||
X509SvidValidator.verifyChain(null, bundleSourceMock);
|
||||
X509SvidValidator.verifyChain(null, new X509Bundle(TrustDomain.of("example.org")));
|
||||
fail("should have thrown an exception");
|
||||
} catch (NullPointerException e) {
|
||||
assertEquals("chain is marked non-null but is null", e.getMessage());
|
||||
|
|
@ -156,17 +136,10 @@ public class X509SvidValidatorTest {
|
|||
@Test
|
||||
void verifyChain_nullBundleSource_throwsNullPointerException() throws CertificateException, BundleNotFoundException, URISyntaxException, IOException {
|
||||
try {
|
||||
val certPath = Paths.get(toUri("testdata/x509svid/cert.pem"));
|
||||
val certBytes = Files.readAllBytes(certPath);
|
||||
val chain = CertificateUtils.generateCertificates(certBytes);
|
||||
X509SvidValidator.verifyChain(chain, null);
|
||||
fail("should have thrown an exception");
|
||||
} catch (NullPointerException e) {
|
||||
assertEquals("x509BundleSource is marked non-null but is null", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private URI toUri(String path) throws URISyntaxException {
|
||||
return getClass().getClassLoader().getResource(path).toURI();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
package spiffe.utils;
|
||||
|
||||
import lombok.Value;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.*;
|
||||
import org.bouncycastle.cert.CertIOException;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
|
||||
import org.bouncycastle.operator.ContentSigner;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
|
||||
public class X509CertificateTestUtils {
|
||||
|
||||
/**
|
||||
* Creates a self-signed Root CA certificate
|
||||
*/
|
||||
public static CertAndKeyPair createRootCA(String subject, String spiffeId) throws Exception {
|
||||
KeyPair certKeyPair = generateKeyPair();
|
||||
JcaX509v3CertificateBuilder builder = getCertificateBuilder(certKeyPair, subject, subject);
|
||||
addCAExtensions(builder, certKeyPair, spiffeId);
|
||||
|
||||
// self signed
|
||||
X509Certificate cert = getSignedX509Certificate(certKeyPair.getPrivate(), builder);
|
||||
return new CertAndKeyPair(cert, certKeyPair);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a certificate signed with the private key of the issuer. The generated cert can be an intermediate CA or
|
||||
* a leaf certificate.
|
||||
*/
|
||||
public static CertAndKeyPair createCertificate(String subject, String issuerSubject, String spiffeId, CertAndKeyPair issuer, boolean isCa) throws Exception {
|
||||
KeyPair certKeyPair = generateKeyPair();
|
||||
PrivateKey issuerKey = issuer.keyPair.getPrivate();
|
||||
JcaX509v3CertificateBuilder builder = getCertificateBuilder(certKeyPair, subject, issuerSubject);
|
||||
addCertExtensions(builder, spiffeId, isCa);
|
||||
X509Certificate cert = getSignedX509Certificate(issuerKey, builder);
|
||||
return new CertAndKeyPair(cert, certKeyPair);
|
||||
}
|
||||
|
||||
@Value
|
||||
public final static class CertAndKeyPair {
|
||||
private final KeyPair keyPair;
|
||||
private final X509Certificate certificate;
|
||||
|
||||
public CertAndKeyPair(X509Certificate certificate, KeyPair keyPair) {
|
||||
this.keyPair = keyPair;
|
||||
this.certificate = certificate;
|
||||
}
|
||||
}
|
||||
|
||||
private static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
|
||||
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
return keyGen.generateKeyPair();
|
||||
}
|
||||
|
||||
private static void addCertExtensions(JcaX509v3CertificateBuilder builder, String spiffeId, boolean isCa) throws CertIOException {
|
||||
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(isCa));
|
||||
|
||||
if (isCa) {
|
||||
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.digitalSignature | KeyUsage.cRLSign);
|
||||
builder.addExtension(Extension.keyUsage, true, usage);
|
||||
} else {
|
||||
KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.keyAgreement);
|
||||
builder.addExtension(Extension.keyUsage, true, usage);
|
||||
|
||||
ASN1EncodableVector purposes = new ASN1EncodableVector();
|
||||
purposes.add(KeyPurposeId.id_kp_serverAuth);
|
||||
purposes.add(KeyPurposeId.id_kp_clientAuth);
|
||||
builder.addExtension(Extension.extendedKeyUsage, false, new DERSequence(purposes));
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(spiffeId)) {
|
||||
builder.addExtension(Extension.subjectAlternativeName, false,
|
||||
new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, spiffeId )));
|
||||
}
|
||||
}
|
||||
|
||||
private static void addCAExtensions(JcaX509v3CertificateBuilder builder, KeyPair certKeyPair, String spiffeId) throws CertIOException {
|
||||
builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(true));
|
||||
KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.digitalSignature | KeyUsage.cRLSign);
|
||||
builder.addExtension(Extension.keyUsage, true, usage);
|
||||
|
||||
builder.addExtension(Extension.subjectAlternativeName, true,
|
||||
new GeneralNames(new GeneralName(GeneralName.uniformResourceIdentifier, spiffeId)));
|
||||
|
||||
builder.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(certKeyPair.getPublic().getEncoded()));
|
||||
}
|
||||
|
||||
private static JcaX509v3CertificateBuilder getCertificateBuilder(KeyPair certKeyPair, String subject, String issuerSubject) {
|
||||
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
|
||||
Instant validFrom = Instant.now().minus(5, ChronoUnit.DAYS);
|
||||
Instant validUntil = validFrom.plus(30 , ChronoUnit.DAYS);
|
||||
X500Name name = new X500Name(subject);
|
||||
X500Name issuerName = new X500Name(issuerSubject);
|
||||
return new JcaX509v3CertificateBuilder(
|
||||
issuerName,
|
||||
serialNumber,
|
||||
Date.from(validFrom), Date.from(validUntil),
|
||||
name, certKeyPair.getPublic());
|
||||
}
|
||||
|
||||
private static X509Certificate getSignedX509Certificate(PrivateKey issuerKey, JcaX509v3CertificateBuilder builder) throws OperatorCreationException, CertificateException {
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").build(issuerKey);
|
||||
X509CertificateHolder certHolder = builder.build(signer);
|
||||
return new JcaX509CertificateConverter().getCertificate(certHolder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIB5QIBADANBgkqhkiG9w0BAQEFAASCAc8wggHLAgEAAmEA0EdYWa7LZ/ZA2sKk
|
||||
JsREA2TkXDIq01JIRsVetPFRqRW5GEmkwwk0qThebp/ofZt8oLkMwp06BLaQC3tH
|
||||
QGkK31jh5Djd1NHA8CpU4ByObgGeY75dhwFEzI4YwXM+e0n/AgMBAAECYFD4S4qh
|
||||
/4WtIE1refFwP5iqMnT9M9TvmhWZSVZCsqJvRYQBrUH9ZDGdLmkHVZTvSvKKmkoZ
|
||||
VvXDlpmW4Eaed8xXqsLYplMrVo6WkvdtvlvfIwP69PGFmWwKgFBe2aLHsQIxAOoT
|
||||
dwmlr/dNNu2MjyjcvTK0lCn6vexp6k8MaXTEsTvG0kBmVDZGuSXcKzbBoAZLxQIx
|
||||
AOPJU65HnDpcOM+qLH3jahTnbrg4C0BO0mj1OusLcSUnA6bFP2NkZ9LyWfMerbvG
|
||||
8wIxAI7Iyt8mo50+C5iCGj250OtiPdMRsdLJlPUdRCLHbLljAZPpF8t3/q66i929
|
||||
5MiSZQIwE3wXQmMxw/Q7j9f4slQPsPYTDIMOw1N6wCup/I0gApORxmQ9Bd2C3BKL
|
||||
CzbmmZdtAjEA2v1fSN4DPcQW2bgmoE0GoNEMYGfSza7jBGOiKkqm4p2hAjaur174
|
||||
U2t9BPJHk+Xh
|
||||
-----END PRIVATE KEY-----
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIBzDCCAVGgAwIBAgIBADAKBggqhkjOPQQDAzAeMQswCQYDVQQGEwJVUzEPMA0G
|
||||
A1UEChMGU1BJRkZFMB4XDTIwMDMxNjE4MDQ1N1oXDTIwMDMyMzE4MDUwN1owHjEL
|
||||
MAkGA1UEBhMCVVMxDzANBgNVBAoTBlNQSUZGRTB2MBAGByqGSM49AgEGBSuBBAAi
|
||||
A2IABOStlk5qbbCuuRqKitTqTzQf/UnlljO2bHAekgz+0na4oJhcsOYhRLbKQVcr
|
||||
U5jf7BpcT7nYHyLMv79Cy+Xa1snzMCGhx1obgt8gAXb4b4GwyAiNzaq7ytX4SAZB
|
||||
CUXp36NjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
|
||||
BBYEFCMzt4WGhen9N2N+MwzUkwEtG6YLMB8GA1UdEQQYMBaGFHNwaWZmZTovL2V4
|
||||
YW1wbGUub3JnMAoGCCqGSM49BAMDA2kAMGYCMQDJSIl+8jQek7tHRSfU2vYLQ6sy
|
||||
2t4NJcc5zeSjNxFIajUogl7L8T1QNzrKpXm/ZbQCMQDU54VnA1Awq0Qq2pf4zQ1C
|
||||
KOpj4PguMpUmulRVrzD2KNQz+FUKsHgL/mIZSfN5g1M=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICADCCAYagAwIBAgIQJqqLnXOR3tjUV43PpGW4YDAKBggqhkjOPQQDAzAeMQsw
|
||||
CQYDVQQGEwJVUzEPMA0GA1UEChMGU1BJRkZFMB4XDTIwMDMxODE5MDc1MloXDTIw
|
||||
MDMyMzE4MDUwN1owHTELMAkGA1UEBhMCVVMxDjAMBgNVBAoTBVNQSVJFMFkwEwYH
|
||||
KoZIzj0CAQYIKoZIzj0DAQcDQgAE4/NA2umeK9j1U5+egPqfzomjnpnLz68jNvUN
|
||||
tdA0Lg6E7/nsmvqoNbVVbaD84Jplfg6/6HWSnoO7K7A+oZ1g+qOBpjCBozAOBgNV
|
||||
HQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1Ud
|
||||
EwEB/wQCMAAwHQYDVR0OBBYEFPLf59AkFCva6ehKx8L4i+pjCU1CMB8GA1UdIwQY
|
||||
MBaAFCMzt4WGhen9N2N+MwzUkwEtG6YLMCQGA1UdEQQdMBuGGXNwaWZmZTovL2V4
|
||||
YW1wbGUub3JnL3Rlc3QwCgYIKoZIzj0EAwMDaAAwZQIwRzrN6Rh8X28UYJEuql/1
|
||||
GZEeto7zzj0UtjZFwQy2ODl48nFFRGKUnq8mc4cIMI/kAjEAlixJBUHqb4ty8Ff+
|
||||
d0XHzA5duE1hzFxd2feRppjqiOHKJu7Rh2dzZd3rZhMZWrrd
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -0,0 +1 @@
|
|||
lombok.addLombokGeneratedAnnotation = true
|
||||
Loading…
Reference in New Issue