使用自定义扩展创建证书 - AWS Private Certificate Authority

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

使用自定义扩展创建证书

CustomExtension 对象允许管理员在私有证书中设置自定义 X.509 扩展。必须使用其中一个 ApiPassthrough 模板创建自定义证书。有关模板的更多信息,请参阅模板种类。有关使用自定义扩展的更多信息,请参阅 颁发私有终端实体证书

激活带有 NameConstraints 扩展的从属 CA

package com.amazonaws.samples; 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.auth.AWSStaticCredentialsProvider; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; import java.util.Objects; import com.amazonaws.services.acmpca.AWSACMPCA; import com.amazonaws.services.acmpca.AWSACMPCAClientBuilder; import com.amazonaws.services.acmpca.model.IssueCertificateRequest; import com.amazonaws.services.acmpca.model.IssueCertificateResult; import com.amazonaws.services.acmpca.model.KeyAlgorithm; import com.amazonaws.services.acmpca.model.SigningAlgorithm; import com.amazonaws.services.acmpca.model.Validity; import com.amazonaws.waiters.Waiter; import com.amazonaws.waiters.WaiterParameters; import com.amazonaws.waiters.WaiterTimedOutException; import com.amazonaws.waiters.WaiterUnrecoverableException; import com.amazonaws.AmazonClientException; import com.amazonaws.services.acmpca.model.LimitExceededException; import com.amazonaws.services.acmpca.model.ResourceNotFoundException; import com.amazonaws.services.acmpca.model.RevocationConfiguration; import com.amazonaws.services.acmpca.model.InvalidStateException; import com.amazonaws.services.acmpca.model.InvalidArnException; import com.amazonaws.services.acmpca.model.InvalidPolicyException; import com.amazonaws.services.acmpca.model.ASN1Subject; import com.amazonaws.services.acmpca.model.AWSACMPCAException; 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.CertificateMismatchException; import com.amazonaws.services.acmpca.model.ConcurrentModificationException; import com.amazonaws.services.acmpca.model.CreateCertificateAuthorityRequest; import com.amazonaws.services.acmpca.model.CreateCertificateAuthorityResult; import com.amazonaws.services.acmpca.model.CrlConfiguration; import com.amazonaws.services.acmpca.model.CustomExtension; import com.amazonaws.services.acmpca.model.Extensions; import com.amazonaws.services.acmpca.model.GetCertificateAuthorityCertificateRequest; import com.amazonaws.services.acmpca.model.GetCertificateAuthorityCertificateResult; 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.InvalidArgsException; import com.amazonaws.services.acmpca.model.MalformedCSRException; import com.amazonaws.services.acmpca.model.MalformedCertificateException; import com.amazonaws.services.acmpca.model.RequestFailedException; import com.amazonaws.services.acmpca.model.RequestInProgressException; import org.bouncycastle.asn1.x509.GeneralName; import org.bouncycastle.asn1.x509.GeneralSubtree; import org.bouncycastle.asn1.x509.NameConstraints; import lombok.SneakyThrows; public class SubordinateCAActivationWithNameConstraints { public static void main(String[] args) throws Exception { // Place your own Root CA ARN here. String rootCAArn = "arn:aws:acm-pca:region:123456789012:certificate-authority/12345678-1234-1234-1234-123456789012"; // Define the endpoint region for your sample. String endpointRegion = "us-west-2"; // Substitute your region here, e.g. "us-west-2" // Define a CA subject. ASN1Subject subject = new ASN1Subject(); subject.setOrganization("Example Organization"); subject.setOrganizationalUnit("Example"); subject.setCountry("US"); subject.setState("Virginia"); subject.setLocality("Arlington"); subject.setCommonName("SubordinateCA"); // Define the CA configuration. CertificateAuthorityConfiguration configCA = new CertificateAuthorityConfiguration(); configCA.withKeyAlgorithm(KeyAlgorithm.RSA_2048); configCA.withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA); configCA.withSubject(subject); // Define a certificate revocation list configuration. CrlConfiguration crlConfigure = new CrlConfiguration(); crlConfigure.withEnabled(true); crlConfigure.withExpirationInDays(365); crlConfigure.withCustomCname(null); crlConfigure.withS3BucketName("your-bucket-name"); // Define a certificate authority type CertificateAuthorityType caType = CertificateAuthorityType.SUBORDINATE; // ** Execute core code samples for Subordinate CA activation in sequence ** AWSACMPCA client = ClientBuilder(endpointRegion); String rootCertificate = GetCertificateAuthorityCertificate(rootCAArn, client); String subordinateCAArn = CreateCertificateAuthority(configCA, crlConfigure, caType, client); String csr = GetCertificateAuthorityCsr(subordinateCAArn, client); String subordinateCertificateArn = IssueCertificate(rootCAArn, csr, client); String subordinateCertificate = GetCertificate(subordinateCertificateArn, rootCAArn, client); ImportCertificateAuthorityCertificate(subordinateCertificate, rootCertificate, subordinateCAArn, 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 GetCertificateAuthorityCertificate(String rootCAArn, AWSACMPCA client) { // ** GetCertificateAuthorityCertificate ** // Create a request object and set the certificate authority ARN, GetCertificateAuthorityCertificateRequest getCACertificateRequest = new GetCertificateAuthorityCertificateRequest(); getCACertificateRequest.withCertificateAuthorityArn(rootCAArn); // Create a result object. GetCertificateAuthorityCertificateResult getCACertificateResult = null; try { getCACertificateResult = client.getCertificateAuthorityCertificate(getCACertificateRequest); } catch (ResourceNotFoundException ex) { throw ex; } catch (InvalidStateException ex) { throw ex; } catch (InvalidArnException ex) { throw ex; } // Retrieve and display the certificate information. String rootCertificate = getCACertificateResult.getCertificate(); System.out.println("Root CA Certificate / Certificate Chain:"); System.out.println(rootCertificate); return rootCertificate; } private static String CreateCertificateAuthority(CertificateAuthorityConfiguration configCA, CrlConfiguration crlConfigure, CertificateAuthorityType caType, AWSACMPCA client) { RevocationConfiguration revokeConfig = new RevocationConfiguration(); revokeConfig.setCrlConfiguration(crlConfigure); // Create the request object. CreateCertificateAuthorityRequest createCARequest = new CreateCertificateAuthorityRequest(); createCARequest.withCertificateAuthorityConfiguration(configCA); createCARequest.withRevocationConfiguration(revokeConfig); createCARequest.withIdempotencyToken("1234"); 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 subordinateCAArn = createCAResult.getCertificateAuthorityArn(); System.out.println("Subordinate CA Arn: " + subordinateCAArn); return subordinateCAArn; } private static String GetCertificateAuthorityCsr(String subordinateCAArn, AWSACMPCA client) { // Create the CSR request object and set the CA ARN. GetCertificateAuthorityCsrRequest csrRequest = new GetCertificateAuthorityCsrRequest(); csrRequest.withCertificateAuthorityArn(subordinateCAArn); // 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("Subordinate CSR:"); System.out.println(csr); return csr; } private static String IssueCertificate(String rootCAArn, String csr, AWSACMPCA client) { // Create a certificate request: IssueCertificateRequest issueRequest = new IssueCertificateRequest(); // Set the issuing CA ARN. issueRequest.withCertificateAuthorityArn(rootCAArn); // Set the template ARN. issueRequest.withTemplateArn("arn:aws:acm-pca:::template/SubordinateCACertificate_PathLen0_APIPassthrough/V1"); ByteBuffer csrByteBuffer = stringToByteBuffer(csr); issueRequest.setCsr(csrByteBuffer); // Set the signing algorithm. issueRequest.withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA); // Set the validity period for the certificate to be issued. Validity validity = new Validity(); validity.withValue(100L); validity.withType("DAYS"); issueRequest.withValidity(validity); // Set the idempotency token. issueRequest.setIdempotencyToken("1234"); // Generate Base64 encoded Nameconstraints extension value String base64EncodedExtValue = getNameConstraintExtensionValue(); // Generate custom extension CustomExtension customExtension = new CustomExtension(); customExtension.setCritical(true); customExtension.setObjectIdentifier("2.5.29.30"); // NameConstraints 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 subordinateCertificateArn = issueResult.getCertificateArn(); System.out.println("Subordinate Certificate Arn: " + subordinateCertificateArn); return subordinateCertificateArn; } @SneakyThrows private static String getNameConstraintExtensionValue() { // Generate Base64 encoded Nameconstraints extension value GeneralSubtree dnsPrivate = new GeneralSubtree(new GeneralName(GeneralName.dNSName, ".private")); GeneralSubtree dnsLocal = new GeneralSubtree(new GeneralName(GeneralName.dNSName, ".local")); GeneralSubtree dnsCorp = new GeneralSubtree(new GeneralName(GeneralName.dNSName, ".corp")); GeneralSubtree dnsSecretCorp = new GeneralSubtree(new GeneralName(GeneralName.dNSName, ".secret.corp")); GeneralSubtree dnsExample = new GeneralSubtree(new GeneralName(GeneralName.dNSName, ".example.com")); GeneralSubtree[] permittedSubTree = new GeneralSubtree[] { dnsPrivate, dnsLocal, dnsCorp }; GeneralSubtree[] excludedSubTree = new GeneralSubtree[] { dnsSecretCorp, dnsExample }; NameConstraints nameConstraints = new NameConstraints(permittedSubTree, excludedSubTree); return new String(Base64.getEncoder().encode(nameConstraints.getEncoded())); } private static String GetCertificate(String subordinateCertificateArn, String rootCAArn, AWSACMPCA client) { // Create a request object. GetCertificateRequest certificateRequest = new GetCertificateRequest(); // Set the certificate ARN. certificateRequest.withCertificateArn(subordinateCertificateArn); // 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 subordinateCertificate = certificateResult.getCertificate(); System.out.println("Subordinate CA Certificate:"); System.out.println(subordinateCertificate); return subordinateCertificate; } private static void ImportCertificateAuthorityCertificate(String subordinateCertificate, String rootCertificate, String subordinateCAArn, AWSACMPCA client) { // Create the request object and set the signed certificate, chain and CA ARN. ImportCertificateAuthorityCertificateRequest importRequest = new ImportCertificateAuthorityCertificateRequest(); ByteBuffer certByteBuffer = stringToByteBuffer(subordinateCertificate); importRequest.setCertificate(certByteBuffer); ByteBuffer rootCACertByteBuffer = stringToByteBuffer(rootCertificate); importRequest.setCertificateChain(rootCACertByteBuffer); // Set the certificate authority ARN. importRequest.withCertificateAuthorityArn(subordinateCAArn); // 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("Subordinate CA certificate successfully imported."); System.out.println("Subordinate 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); } }

颁发带有 QC 声明扩展的证书

package com.amazonaws.samples; 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.auth.AWSStaticCredentialsProvider; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; import java.util.Objects; import com.amazonaws.services.acmpca.AWSACMPCA; import com.amazonaws.services.acmpca.AWSACMPCAClientBuilder; import com.amazonaws.services.acmpca.model.ApiPassthrough; import com.amazonaws.services.acmpca.model.CustomExtension; import com.amazonaws.services.acmpca.model.Extensions; 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.LimitExceededException; import com.amazonaws.services.acmpca.model.ResourceNotFoundException; import com.amazonaws.services.acmpca.model.InvalidStateException; import com.amazonaws.services.acmpca.model.InvalidArnException; import com.amazonaws.services.acmpca.model.InvalidArgsException; import com.amazonaws.services.acmpca.model.MalformedCSRException; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERUTF8String; import org.bouncycastle.asn1.x509.qualified.ETSIQCObjectIdentifiers; import org.bouncycastle.asn1.x509.qualified.QCStatement; import lombok.SneakyThrows; public class IssueCertificateWithQCStatement { private static ByteBuffer stringToByteBuffer(final String string) { if (Objects.isNull(string)) { return null; } byte[] bytes = string.getBytes(StandardCharsets.UTF_8); return ByteBuffer.wrap(bytes); } @SneakyThrows private static String generateQCStatementBase64ExtValue() { DERSequence qcTypeSeq = new DERSequence(ETSIQCObjectIdentifiers.id_etsi_qct_web); QCStatement qcType = new QCStatement(ETSIQCObjectIdentifiers.id_etsi_qcs_QcType, qcTypeSeq); ASN1EncodableVector pspAIVector = new ASN1EncodableVector(2); pspAIVector.add(new ASN1ObjectIdentifier("0.4.0.19495.1.3")); pspAIVector.add(new DERUTF8String("PSP_AI")); DERSequence pspAISeq = new DERSequence(pspAIVector); ASN1EncodableVector pspASVector = new ASN1EncodableVector(2); pspASVector.add(new ASN1ObjectIdentifier("0.4.0.19495.1.1")); pspASVector.add(new DERUTF8String("PSP_AS")); DERSequence pspASSeq = new DERSequence(pspASVector); ASN1EncodableVector pspPIVector = new ASN1EncodableVector(2); pspPIVector.add(new ASN1ObjectIdentifier("0.4.0.19495.1.2")); pspPIVector.add(new DERUTF8String("PSP_PI")); DERSequence pspPISeq = new DERSequence(pspPIVector); ASN1EncodableVector pspICVector = new ASN1EncodableVector(2); pspICVector.add(new ASN1ObjectIdentifier("0.4.0.19495.1.4")); pspICVector.add(new DERUTF8String("PSP_IC")); DERSequence pspICSeq = new DERSequence(pspICVector); ASN1EncodableVector pspSeqVector = new ASN1EncodableVector(4); pspSeqVector.add(pspPISeq); pspSeqVector.add(pspICSeq); pspSeqVector.add(pspASSeq); pspSeqVector.add(pspAISeq); DERSequence pspSeq = new DERSequence(pspSeqVector); ASN1EncodableVector pspVector = new ASN1EncodableVector(3); pspVector.add(pspSeq); pspVector.add(new DERUTF8String("Your Financial Authority")); pspVector.add(new DERUTF8String("AB-CD")); DERSequence psp = new DERSequence(pspVector); QCStatement qcPSP = new QCStatement(new ASN1ObjectIdentifier("0.4.0.19495.2"), psp); DERSequence qcSeq = new DERSequence(new QCStatement[] { qcType, qcPSP }); byte[] qcExtValueInBytes = qcSeq.getEncoded(); return Base64.getEncoder().encodeToString(qcExtValueInBytes); } public static void main(String[] args) throws Exception { // 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 your credentials from disk", e); } // Define the endpoint for your sample. String endpointRegion = "us-west-2"; // Substitute your region here, e.g. "us-west-2" 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(); // Create a certificate request: IssueCertificateRequest req = new IssueCertificateRequest(); // Set the CA ARN. req.withCertificateAuthorityArn("arn:aws:acm-pca:region:account:" + "certificate-authority/12345678-1234-1234-1234-123456789012"); // Specify the certificate signing request (CSR) for the certificate to be signed and issued. String strCSR = "-----BEGIN CERTIFICATE REQUEST-----\n" + "base64-encoded CSR\n" + "-----END CERTIFICATE REQUEST-----\n"; ByteBuffer csrByteBuffer = stringToByteBuffer(strCSR); req.setCsr(csrByteBuffer); // Specify the template for the issued certificate. req.withTemplateArn("arn:aws:acm-pca:::template/EndEntityCertificate_APIPassthrough/V1"); // Set the signing algorithm. req.withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA); // Set the validity period for the certificate to be issued. Validity validity = new Validity(); validity.withValue(30L); validity.withType("DAYS"); req.withValidity(validity); // Set the idempotency token. req.setIdempotencyToken("1234"); // Generate Base64 encoded extension value for QC Statement String base64EncodedExtValue = generateQCStatementBase64ExtValue(); // Generate custom extension CustomExtension customExtension = new CustomExtension(); customExtension.setObjectIdentifier("1.3.6.1.5.5.7.1.3"); // QC Statement 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); req.setApiPassthrough(apiPassthrough); // Issue the certificate. IssueCertificateResult result = null; try { result = client.issueCertificate(req); } 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 arn = result.getCertificateArn(); System.out.println(arn); } }