Optional operations¶
The handler checks whether the CA implements these interfaces and serves the matching operation only when it does.
| Interface | Operation | Without the interface |
|---|---|---|
CertificateGetter |
GetCert, a PKIOperation | FAILURE with badRequest |
CRLGetter |
GetCRL, a PKIOperation | FAILURE with badRequest |
NextCAGetter |
GetNextCACert and the GetNextCACert capability | HTTP 501 |
ChainGetter |
GetCACertChain | HTTP 501 |
A CA that implements RefusalRecorder is told about the GetCert and GetCRL requests refused this way.
GetCert¶
GetCert fetches a certificate by its issuer and serial number. ca.lookup stands for the
certificate store of your CA.
// GetCert returns the certificate with the issuer and serial number the request names.
func (ca *myCA) GetCert(_ context.Context, req *scepserver.Request) ([]*x509.Certificate, error) {
id := req.Message.CertificateID
cert, ok := ca.lookup(id.SerialNumber)
if !ok || !bytes.Equal(id.Issuer, ca.cert.RawSubject) {
return nil, &scepserver.Failure{Info: scep.BadCertID, Err: errors.New("unknown certificate")}
}
return []*x509.Certificate{cert}, nil
}
Message.CertificateID holds the DER encoded issuer name and the serial number. Return the
certificate first, optionally followed by its chain. The answer is encrypted for the certificate
that signed the request, which is usually one the CA issued earlier. The handler does not check it,
so decide in GetCert whether that signer may read the certificate.
GetCRL¶
GetCRL names a certificate the same way and asks for the CRL that covers it. Return the DER encoded CRL. The handler sends it in a SUCCESS answer.
// GetCRL returns the current CRL of the CA.
func (ca *myCA) GetCRL(context.Context, *scepserver.Request) ([]byte, error) {
return ca.currentCRL()
}
GetNextCACert¶
Before a CA certificate expires, a CA can announce the certificate that replaces it. Clients fetch it with GetNextCACert and switch to it after the rollover.
// NextCACertificates announces the next CA certificate, signed by the current CA.
func (ca *myCA) NextCACertificates(_ context.Context, name string) ([]*x509.Certificate, *scepserver.Responder, error) {
if ca.next == nil {
return nil, nil, scepserver.ErrNotFound
}
return []*x509.Certificate{ca.next}, &scepserver.Responder{SignerCertificate: ca.cert, SignerKey: ca.key}, nil
}
The handler signs the certificates with the current responder, which clients already trust from
GetCACert. The signature digest is Options.Digest. SHA-256 when it is zero. Return
scepserver.ErrNotFound while no rollover is planned, which the handler answers with HTTP 404. A
nil responder without an error is answered with HTTP 500.
When the CA implements NextCAGetter, the default capabilities list GetNextCACert.
GetCACertChain¶
RFC 8894 does not define GetCACertChain, but some CAs serve it and their clients still send it. It returns the CA certificate followed by the certificates that issued it, up to the root.
// CACertificateChain returns the issuing CA certificate followed by its root.
func (ca *myCA) CACertificateChain(context.Context, string) ([]*x509.Certificate, error) {
return []*x509.Certificate{ca.cert, ca.root}, nil
}
name is the message parameter, as for CACertificates. Return scepserver.ErrNotFound for a
name you do not serve, which gives HTTP 404.
Answer formats¶
| Operation | Body | Content type |
|---|---|---|
| GetCACert with one certificate | The DER certificate | application/x-x509-ca-cert |
| GetCACert with several certificates | A certificate-only SignedData | application/x-x509-ca-ra-cert |
| GetCACertChain | A certificate-only SignedData, also for one certificate | application/x-x509-ca-ra-cert |
| GetNextCACert | A SignedData that the current responder signs and that carries only the next certificates | application/x-x509-next-ca-cert |
| GetCACaps | One capability per line, each ending with a line feed | text/plain; charset=utf-8 |
| PKIOperation | The CertRep pkiMessage | application/x-pki-message |