Skip to content

Keys the CA generates

A device that cannot generate a good key pair itself can ask the CA to do it (RFC 9483 section 4.1.6). SendIRWithCentralKeyGeneration, SendCRWithCentralKeyGeneration and SendKURWithCentralKeyGeneration send a request without a public key and return the private key with the certificate:

// nil leaves the key algorithm to the CA.
result, err := c.SendIRWithCentralKeyGeneration(context.Background(), nil, creds,
    client.WithSenderKID([]byte("my-device")),
    client.WithTemplateSubject(pkix.Name{CommonName: "my-device"}),
)
key := result.GeneratedKey.PrivateKey

To ask for a key algorithm, pass its AlgorithmIdentifier. An elliptic curve key names its curve in the parameters:

curve, _ := asn1.Marshal(asn1.ObjectIdentifier{1, 3, 132, 0, 34}) // P-384
algorithm := &pkicmp.AlgorithmIdentifier{
    Algorithm:  asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}, // id-ecPublicKey
    Parameters: curve,
}

The CA decides which algorithms it generates and refuses others, usually with badAlg.

Credentials

The CA encrypts the private key for the requester, so the credentials of the request must be able to decrypt it:

Credentials Encryption
pkicmp.MACCredentials To the shared secret (RFC 5652 section 6.2.4)
pkicmp.SignatureCredentials with an RSA key Key transport to the protection key
pkicmp.SignatureCredentials with an ECDSA key on P-256, P-384 or P-521 Key agreement with the protection key

Other protection keys, such as Ed25519 or ML-DSA, cannot receive the key. The call then fails before it sends anything.

Checks

The client accepts the key only when its signature verifies with the signer certificate in the key package and the key matches the public key of the issued certificate. With WithTrustedCAs the signer certificate must also chain to the trusted CAs and either assert id-kp-cmKGA, be a CA certificate or be the certificate that protected the response. Without trusted CAs the client does not validate the signer, which RFC 9483 section 4.1.6 allows for a MAC-protected exchange.

When a check fails, the client rejects the certificate in its certConf and returns an error. When the certConf itself fails after the checks, the ConfirmationError holds the key in GeneratedKey next to the certificate.

Result

EnrollResult.GeneratedKey holds the key:

Field Content
PrivateKey The parsed key: *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, *mldsa.PrivateKey or a composite ML-DSA key. It is nil for a key type the client cannot parse, such as ML-KEM
PKCS8 The DER PKCS #8 key. A OneAsymmetricKey version 2 from the CA keeps its public key
Signer The certificate of the key generation authority that signed the key

An ML-KEM key is checked against the certificate through the public key that its OneAsymmetricKey carries.

Delayed delivery

The CA may answer with status waiting. The key then arrives with the certificate when the client polls. With WithDeferredPolling, PendingEnrollment.CentralKeyGeneration is true and ResumeEnrollment needs the same credentials to decrypt the key.

Protocol version

These requests are sent as CMP version 3 (cmp2021), because the CA answers with EnvelopedData. The client reads the key package in both forms a CA may send: the AsymmetricKeyPackage of RFC 9810 section 5.2.2 and the id-data that OpenSSL writes, which may hold a PKCS #1 or SEC 1 key. A private key in the deprecated EncryptedValue format is refused.