This Java sample shows how to use the RootCACertificate_APIPassthrough/V1 definition template to create and install a
Matter
The example calls the following AWS Private CA API actions:
If you encounter problems, see Troubleshoot AWS Private CA Matter-compliant certificate errors in the Troubleshooting section.
package com.amazonaws.samples.matter;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.samples.GetCertificateAuthorityCertificate;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.services.acmpca.AWSACMPCA;
import com.amazonaws.services.acmpca.AWSACMPCAClientBuilder;
import com.amazonaws.services.acmpca.model.ASN1Subject;
import com.amazonaws.services.acmpca.model.ApiPassthrough;
import com.amazonaws.services.acmpca.model.CertificateAuthorityConfiguration;
import com.amazonaws.services.acmpca.model.CertificateAuthorityType;
import com.amazonaws.services.acmpca.model.CreateCertificateAuthorityResult;
import com.amazonaws.services.acmpca.model.CreateCertificateAuthorityRequest;
import com.amazonaws.services.acmpca.model.CrlConfiguration;
import com.amazonaws.services.acmpca.model.CustomAttribute;
import com.amazonaws.services.acmpca.model.CustomExtension;
import com.amazonaws.services.acmpca.model.Extensions;
import com.amazonaws.services.acmpca.model.KeyAlgorithm;
import com.amazonaws.services.acmpca.model.SigningAlgorithm;
import com.amazonaws.services.acmpca.model.Tag;
import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
import com.amazonaws.services.acmpca.model.GetCertificateAuthorityCsrRequest;
import com.amazonaws.services.acmpca.model.GetCertificateAuthorityCsrResult;
import com.amazonaws.services.acmpca.model.GetCertificateRequest;
import com.amazonaws.services.acmpca.model.GetCertificateResult;
import com.amazonaws.services.acmpca.model.ImportCertificateAuthorityCertificateRequest;
import com.amazonaws.services.acmpca.model.IssueCertificateRequest;
import com.amazonaws.services.acmpca.model.IssueCertificateResult;
import com.amazonaws.services.acmpca.model.SigningAlgorithm;
import com.amazonaws.services.acmpca.model.Validity;
import com.amazonaws.AmazonClientException;
import com.amazonaws.services.acmpca.model.CertificateMismatchException;
import com.amazonaws.services.acmpca.model.ConcurrentModificationException;
import com.amazonaws.services.acmpca.model.LimitExceededException;
import com.amazonaws.services.acmpca.model.InvalidArgsException;
import com.amazonaws.services.acmpca.model.InvalidArnException;
import com.amazonaws.services.acmpca.model.InvalidPolicyException;
import com.amazonaws.services.acmpca.model.InvalidStateException;
import com.amazonaws.services.acmpca.model.MalformedCertificateException;
import com.amazonaws.services.acmpca.model.MalformedCSRException;
import com.amazonaws.services.acmpca.model.RequestFailedException;
import com.amazonaws.services.acmpca.model.RequestInProgressException;
import com.amazonaws.services.acmpca.model.ResourceNotFoundException;
import com.amazonaws.services.acmpca.model.RevocationConfiguration;
import com.amazonaws.services.acmpca.model.AWSACMPCAException;
import com.amazonaws.waiters.Waiter;
import com.amazonaws.waiters.WaiterParameters;
import com.amazonaws.waiters.WaiterTimedOutException;
import com.amazonaws.waiters.WaiterUnrecoverableException;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.pkcs.PKCS10CertificationRequest;
import org.bouncycastle.util.io.pem.PemReader;
import lombok.SneakyThrows;
public class RootCAActivation {
public static void main(String[] args) throws Exception {
// Define the endpoint region for your sample.
String endpointRegion = "region"; // Substitute your region here, e.g. "ap-southeast-2"
// Define custom attributes
List<CustomAttribute> customAttributes = Arrays.asList(
new CustomAttribute()
.withObjectIdentifier("1.3.6.1.4.1.37244.1.4")
.withValue("CACACACA00000001")
);
// Define a CA subject.
ASN1Subject subject = new ASN1Subject();
subject.setCustomAttributes(customAttributes);
// Define the CA configuration.
CertificateAuthorityConfiguration configCA = new CertificateAuthorityConfiguration();
configCA.withKeyAlgorithm(KeyAlgorithm.EC_prime256v1);
configCA.withSigningAlgorithm(SigningAlgorithm.SHA256WITHECDSA);
configCA.withSubject(subject);
// Define a certificate authority type
CertificateAuthorityType CAtype = CertificateAuthorityType.ROOT;
// ** Execute core code samples for Root CA activation in sequence **
AWSACMPCA client = ClientBuilder(endpointRegion);
String rootCAArn = CreateCertificateAuthority(configCA, CAtype, client);
String csr = GetCertificateAuthorityCsr(rootCAArn, client);
String rootCertificateArn = IssueCertificate(rootCAArn, csr, client);
String rootCertificate = GetCertificate(rootCertificateArn, rootCAArn, client);
ImportCertificateAuthorityCertificate(rootCertificate, rootCAArn, client);
}
private static AWSACMPCA ClientBuilder(String endpointRegion) {
// Retrieve your credentials from the C:\Users\name\.aws\credentials file
// in Windows or the .aws/credentials file in Linux.
AWSCredentials credentials = null;
try {
credentials = new ProfileCredentialsProvider("default").getCredentials();
} catch (Exception e) {
throw new AmazonClientException(
"Cannot load the credentials from the credential profiles file. " +
"Please make sure that your credentials file is at the correct " +
"location (C:\\Users\\joneps\\.aws\\credentials), and is in valid format.",
e);
}
String endpointProtocol = "https://acm-pca." + endpointRegion + ".amazonaws.com/";
EndpointConfiguration endpoint =
new AwsClientBuilder.EndpointConfiguration(endpointProtocol, endpointRegion);
// Create a client that you can use to make requests.
AWSACMPCA client = AWSACMPCAClientBuilder.standard()
.withEndpointConfiguration(endpoint)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.build();
return client;
}
private static String CreateCertificateAuthority(CertificateAuthorityConfiguration configCA, CertificateAuthorityType CAtype, AWSACMPCA client) {
// Create the request object.
CreateCertificateAuthorityRequest createCARequest = new CreateCertificateAuthorityRequest();
createCARequest.withCertificateAuthorityConfiguration(configCA);
createCARequest.withIdempotencyToken("123987");
createCARequest.withCertificateAuthorityType(CAtype);
// Create the private CA.
CreateCertificateAuthorityResult createCAResult = null;
try {
createCAResult = client.createCertificateAuthority(createCARequest);
} catch (InvalidArgsException ex) {
throw ex;
} catch (InvalidPolicyException ex) {
throw ex;
} catch (LimitExceededException ex) {
throw ex;
}
// Retrieve the ARN of the private CA.
String rootCAArn = createCAResult.getCertificateAuthorityArn();
System.out.println("Root CA Arn: " + rootCAArn);
return rootCAArn;
}
private static String GetCertificateAuthorityCsr(String rootCAArn, AWSACMPCA client) {
// Create the CSR request object and set the CA ARN.
GetCertificateAuthorityCsrRequest csrRequest = new GetCertificateAuthorityCsrRequest();
csrRequest.withCertificateAuthorityArn(rootCAArn);
// Create waiter to wait on successful creation of the CSR file.
Waiter<GetCertificateAuthorityCsrRequest> getCSRWaiter = client.waiters().certificateAuthorityCSRCreated();
try {
getCSRWaiter.run(new WaiterParameters<>(csrRequest));
} catch (WaiterUnrecoverableException e) {
//Explicit short circuit when the recourse transitions into
//an undesired state.
} catch (WaiterTimedOutException e) {
//Failed to transition into desired state even after polling.
} catch (AWSACMPCAException e) {
//Unexpected service exception.
}
// Retrieve the CSR.
GetCertificateAuthorityCsrResult csrResult = null;
try {
csrResult = client.getCertificateAuthorityCsr(csrRequest);
} catch (RequestInProgressException ex) {
throw ex;
} catch (ResourceNotFoundException ex) {
throw ex;
} catch (InvalidArnException ex) {
throw ex;
} catch (RequestFailedException ex) {
throw ex;
}
// Retrieve and display the CSR;
String csr = csrResult.getCsr();
System.out.println(csr);
return csr;
}
@SneakyThrows
private static String generateAuthorityKeyIdentifier(final String csrPEM) {
PKCS10CertificationRequest csr = getPKCS10CertificationRequest(csrPEM);
SubjectPublicKeyInfo spki = csr.getSubjectPublicKeyInfo();
JcaX509ExtensionUtils extensionUtils = new JcaX509ExtensionUtils();
byte[] akiBytes = extensionUtils.createAuthorityKeyIdentifier(spki).getEncoded();
return Base64.getEncoder().encodeToString(akiBytes);
}
@SneakyThrows
private static PKCS10CertificationRequest getPKCS10CertificationRequest(final String csrPEM) {
ByteArrayInputStream bais = new ByteArrayInputStream(csrPEM.getBytes());
PemReader pemReader = new PemReader(new InputStreamReader(bais));
PEMParser parser = new PEMParser(pemReader);
Object o = parser.readObject();
if (o instanceof PKCS10CertificationRequest) {
return (PKCS10CertificationRequest) o;
}
return null;
}
private static String IssueCertificate(String rootCAArn, String csr, AWSACMPCA client) {
// Create a certificate request:
IssueCertificateRequest issueRequest = new IssueCertificateRequest();
// Set the CA ARN.
issueRequest.withCertificateAuthorityArn(rootCAArn);
// Set the template ARN.
issueRequest.withTemplateArn("arn:aws:acm-pca:::template/RootCACertificate_APIPassthrough/V1");
ByteBuffer csrByteBuffer = stringToByteBuffer(csr);
issueRequest.setCsr(csrByteBuffer);
// Set the signing algorithm.
issueRequest.withSigningAlgorithm(SigningAlgorithm.SHA256WITHECDSA);
// Set the validity period for the certificate to be issued.
Validity validity = new Validity();
validity.withValue(3650L);
validity.withType("DAYS");
issueRequest.withValidity(validity);
// Set the idempotency token.
issueRequest.setIdempotencyToken("1234");
// Generate Base64 encoded extension value for AuthorityKeyIdentifier
String base64EncodedExtValue = generateAuthorityKeyIdentifier(csr);
// Generate custom extension
CustomExtension customExtension = new CustomExtension();
customExtension.setObjectIdentifier("2.5.29.35"); // AuthorityKeyIdentifier Extension OID
customExtension.setValue(base64EncodedExtValue);
// Add custom extension to api-passthrough
ApiPassthrough apiPassthrough = new ApiPassthrough();
Extensions extensions = new Extensions();
extensions.setCustomExtensions(Arrays.asList(customExtension));
apiPassthrough.setExtensions(extensions);
issueRequest.setApiPassthrough(apiPassthrough);
// Issue the certificate.
IssueCertificateResult issueResult = null;
try {
issueResult = client.issueCertificate(issueRequest);
} catch (LimitExceededException ex) {
throw ex;
} catch (ResourceNotFoundException ex) {
throw ex;
} catch (InvalidStateException ex) {
throw ex;
} catch (InvalidArnException ex) {
throw ex;
} catch (InvalidArgsException ex) {
throw ex;
} catch (MalformedCSRException ex) {
throw ex;
}
// Retrieve and display the certificate ARN.
String rootCertificateArn = issueResult.getCertificateArn();
System.out.println("Root Certificate Arn: " + rootCertificateArn);
return rootCertificateArn;
}
private static String GetCertificate(String rootCertificateArn, String rootCAArn, AWSACMPCA client) {
// Create a request object.
GetCertificateRequest certificateRequest = new GetCertificateRequest();
// Set the certificate ARN.
certificateRequest.withCertificateArn(rootCertificateArn);
// Set the certificate authority ARN.
certificateRequest.withCertificateAuthorityArn(rootCAArn);
// Create waiter to wait on successful creation of the certificate file.
Waiter<GetCertificateRequest> getCertificateWaiter = client.waiters().certificateIssued();
try {
getCertificateWaiter.run(new WaiterParameters<>(certificateRequest));
} catch (WaiterUnrecoverableException e) {
//Explicit short circuit when the recourse transitions into
//an undesired state.
} catch (WaiterTimedOutException e) {
//Failed to transition into desired state even after polling.
} catch (AWSACMPCAException e) {
//Unexpected service exception.
}
// Retrieve the certificate and certificate chain.
GetCertificateResult certificateResult = null;
try {
certificateResult = client.getCertificate(certificateRequest);
} catch (RequestInProgressException ex) {
throw ex;
} catch (RequestFailedException ex) {
throw ex;
} catch (ResourceNotFoundException ex) {
throw ex;
} catch (InvalidArnException ex) {
throw ex;
} catch (InvalidStateException ex) {
throw ex;
}
// Get the certificate and certificate chain and display the result.
String rootCertificate = certificateResult.getCertificate();
System.out.println(rootCertificate);
return rootCertificate;
}
private static void ImportCertificateAuthorityCertificate(String rootCertificate, String rootCAArn, AWSACMPCA client) {
// Create the request object and set the signed certificate, chain and CA ARN.
ImportCertificateAuthorityCertificateRequest importRequest =
new ImportCertificateAuthorityCertificateRequest();
ByteBuffer certByteBuffer = stringToByteBuffer(rootCertificate);
importRequest.setCertificate(certByteBuffer);
importRequest.setCertificateChain(null);
// Set the certificate authority ARN.
importRequest.withCertificateAuthorityArn(rootCAArn);
// Import the certificate.
try {
client.importCertificateAuthorityCertificate(importRequest);
} catch (CertificateMismatchException ex) {
throw ex;
} catch (MalformedCertificateException ex) {
throw ex;
} catch (InvalidArnException ex) {
throw ex;
} catch (ResourceNotFoundException ex) {
throw ex;
} catch (RequestInProgressException ex) {
throw ex;
} catch (ConcurrentModificationException ex) {
throw ex;
} catch (RequestFailedException ex) {
throw ex;
}
System.out.println("Root CA certificate successfully imported.");
System.out.println("Root CA activated successfully.");
}
private static ByteBuffer stringToByteBuffer(final String string) {
if (Objects.isNull(string)) {
return null;
}
byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
return ByteBuffer.wrap(bytes);
}
}