x509pkimtlsaws-acm

ACM PCA Issue certificate for client authentication and signing data


I'm trying to implement MTLS client authentication using AWS ACM Private CA to issue X.509 client certificates. The certificate and the correlating private key is supposed to be stored in a password protected PKCS#12 file. The private key will also be used by the client to sign data.

If I request a new certificate using aws-acm-sdk:

RequestCertificateResult response = acm.requestCertificate(new RequestCertificateRequest()
                .withCertificateAuthorityArn(CA_ARN)
                .withIdempotencyToken("1234")
                .withDomainName("localhost.com"));
        
return response.getCertificateArn();

And then export the it using the arn, I get a certificate, certificateChain and a privateKey as strings.

ExportCertificateResult response = acm.exportCertificate(new ExportCertificateRequest()
                .withCertificateArn(certificateArn)
                .withPassphrase(ByteBuffer.wrap(password.getBytes())));

String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
String privateKey = response.getPrivateKey();

But I'm not able to add any type of identifier that let's me tie the certificate to a user during authentication (I'm using Java and Spring security x509 authentication, which extracts e.g. the subject CN (Common Name) from the certificate which then can be used to identify a user). If I want to add custom attributes to the certificate, I need to issue a certificate through the aws-acm-pca-sdk:

IssueCertificateRequest request = new IssueCertificateRequest()
                .withCertificateAuthorityArn(CA_ARN)
                .withCsr(stringToByteBuffer(getCSR()))
                .withTemplateArn("arn:aws:acm-pca:::template/EndEntityClientAuthCertificate_APIPassthrough/V1")
                .withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA)
                .withValidity(new Validity()
                        .withValue(365L)
                        .withType(ValidityPeriodType.DAYS))
                .withIdempotencyToken(userId)
                .withApiPassthrough(new ApiPassthrough()
                        .withSubject(new ASN1Subject()
                                .withCustomAttributes(List.of(
                                        new CustomAttribute()
                                                .withObjectIdentifier("1.3.6.1.4.1") // CustomOID
                                                .withValue("userId")))));

return acmPca.issueCertificate(request).getCertificateArn();

But if I use the sdk to get the certificate, it doesn't contain any private key.

GetCertificateResult response = acmPca.getCertificate(new GetCertificateRequest()
                .withCertificateAuthorityArn(CA_ARN)
                .withCertificateArn(certificateArn));
        
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();

So, when I read documentation I found that I need to import it to ACM in order to export it and get the private key. But in order to import it to ACM I also need to provide the private key..

But as I understand it, the private key should be used when issuing the certificate in the first place? Should I create a new public/private key pair using KMS or what am I supposed to do?

Im confused.. Please help!


Solution

  • I had misinterpreted the responsibility of the PCA.

    The PCA is only responsible for issuing certificates, not keys or even CSR (Certificate Signing Requests). I assumed that the CSR were created by PCA, so the getCSR() method actually fetched the CA's CSR from PCA, while the actual CSR should be generated internally using a private key which has been generated either programmatically or using KMS.