2021-02-12 11:03:08 +00:00
|
|
|
package scep
|
|
|
|
|
|
|
|
import (
|
2021-02-26 11:32:43 +00:00
|
|
|
"context"
|
2023-05-26 21:52:24 +00:00
|
|
|
"crypto"
|
2021-02-12 11:03:08 +00:00
|
|
|
"crypto/x509"
|
2022-03-24 15:08:23 +00:00
|
|
|
"errors"
|
|
|
|
"fmt"
|
2021-02-12 11:03:08 +00:00
|
|
|
|
2021-03-26 21:04:18 +00:00
|
|
|
microx509util "github.com/micromdm/scep/v2/cryptoutil/x509util"
|
|
|
|
microscep "github.com/micromdm/scep/v2/scep"
|
2021-02-25 23:55:37 +00:00
|
|
|
"go.mozilla.org/pkcs7"
|
2021-02-25 23:32:21 +00:00
|
|
|
|
|
|
|
"go.step.sm/crypto/x509util"
|
2021-02-12 11:03:08 +00:00
|
|
|
|
2022-03-24 15:08:23 +00:00
|
|
|
"github.com/smallstep/certificates/authority/provisioner"
|
|
|
|
)
|
2021-02-12 11:03:08 +00:00
|
|
|
|
|
|
|
// Authority is the layer that handles all SCEP interactions.
|
|
|
|
type Authority struct {
|
2023-06-01 10:10:54 +00:00
|
|
|
service *Service // TODO: refactor, so that this is not required
|
2023-05-26 21:52:24 +00:00
|
|
|
signAuth SignAuthority
|
2021-02-12 11:03:08 +00:00
|
|
|
}
|
|
|
|
|
2022-04-28 01:02:37 +00:00
|
|
|
type authorityKey struct{}
|
|
|
|
|
|
|
|
// NewContext adds the given authority to the context.
|
|
|
|
func NewContext(ctx context.Context, a *Authority) context.Context {
|
|
|
|
return context.WithValue(ctx, authorityKey{}, a)
|
|
|
|
}
|
|
|
|
|
|
|
|
// FromContext returns the current authority from the given context.
|
|
|
|
func FromContext(ctx context.Context) (a *Authority, ok bool) {
|
|
|
|
a, ok = ctx.Value(authorityKey{}).(*Authority)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// MustFromContext returns the current authority from the given context. It will
|
|
|
|
// panic if the authority is not in the context.
|
|
|
|
func MustFromContext(ctx context.Context) *Authority {
|
|
|
|
if a, ok := FromContext(ctx); !ok {
|
|
|
|
panic("scep authority is not in the context")
|
|
|
|
} else {
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-12 11:03:08 +00:00
|
|
|
// AuthorityOptions required to create a new SCEP Authority.
|
|
|
|
type AuthorityOptions struct {
|
2023-06-01 10:10:54 +00:00
|
|
|
// Service provides the roots, intermediates, the signer and the (default)
|
|
|
|
// decrypter to the SCEP Authority.
|
2021-03-12 15:58:52 +00:00
|
|
|
Service *Service
|
2021-02-12 11:03:08 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
// SignAuthority is the interface for a signing authority
|
2021-02-12 11:03:08 +00:00
|
|
|
type SignAuthority interface {
|
|
|
|
Sign(cr *x509.CertificateRequest, opts provisioner.SignOptions, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
|
2022-01-21 15:07:31 +00:00
|
|
|
LoadProvisionerByName(string) (provisioner.Interface, error)
|
2021-02-12 11:03:08 +00:00
|
|
|
}
|
|
|
|
|
2021-02-12 16:02:39 +00:00
|
|
|
// New returns a new Authority that implements the SCEP interface.
|
|
|
|
func New(signAuth SignAuthority, ops AuthorityOptions) (*Authority, error) {
|
2021-03-12 15:58:52 +00:00
|
|
|
authority := &Authority{
|
|
|
|
signAuth: signAuth,
|
2023-05-26 21:52:24 +00:00
|
|
|
service: ops.Service,
|
2021-03-12 15:58:52 +00:00
|
|
|
}
|
|
|
|
return authority, nil
|
2021-02-12 16:02:39 +00:00
|
|
|
}
|
|
|
|
|
2023-06-01 10:10:54 +00:00
|
|
|
func (a *Authority) Validate() error {
|
|
|
|
// if a default decrypter is set, the Authority is able
|
|
|
|
// to decrypt SCEP requests. No need to verify the provisioners.
|
|
|
|
if a.service.defaultDecrypter != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, name := range []string{"scepca"} { // TODO: correct names; provided through options
|
|
|
|
p, err := a.LoadProvisionerByName(name)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Println("prov load fail: %w", err)
|
|
|
|
}
|
|
|
|
if scepProv, ok := p.(*provisioner.SCEP); ok {
|
|
|
|
if cert, decrypter := scepProv.GetDecrypter(); cert == nil || decrypter == nil {
|
|
|
|
fmt.Println(fmt.Sprintf("SCEP provisioner %q doesn't have valid decrypter", scepProv.GetName()))
|
|
|
|
// TODO: return error
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-03-06 23:50:00 +00:00
|
|
|
var (
|
|
|
|
// TODO: check the default capabilities; https://tools.ietf.org/html/rfc8894#section-3.5.2
|
|
|
|
defaultCapabilities = []string{
|
2022-01-14 09:48:23 +00:00
|
|
|
"Renewal", // NOTE: removing this will result in macOS SCEP client stating the server doesn't support renewal, but it uses PKCSreq to do so.
|
2021-03-06 23:50:00 +00:00
|
|
|
"SHA-1",
|
|
|
|
"SHA-256",
|
|
|
|
"AES",
|
|
|
|
"DES3",
|
|
|
|
"SCEPStandard",
|
|
|
|
"POSTPKIOperation",
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2022-01-21 15:07:31 +00:00
|
|
|
// LoadProvisionerByName calls out to the SignAuthority interface to load a
|
|
|
|
// provisioner by name.
|
|
|
|
func (a *Authority) LoadProvisionerByName(name string) (provisioner.Interface, error) {
|
|
|
|
return a.signAuth.LoadProvisionerByName(name)
|
|
|
|
}
|
|
|
|
|
2023-06-01 10:10:54 +00:00
|
|
|
// GetCACertificates returns the certificate (chain) for the CA.
|
|
|
|
//
|
|
|
|
// This methods returns the "SCEP Server (RA)" certificate, the issuing CA up to and excl. the root.
|
|
|
|
// Some clients do need the root certificate however; also see: https://github.com/openxpki/openxpki/issues/73
|
|
|
|
//
|
|
|
|
// In case a provisioner specific decrypter is available, this is used as the "SCEP Server (RA)" certificate
|
|
|
|
// instead of the CA intermediate directly. This uses a distinct instance of a KMS for doing the SCEp key
|
|
|
|
// operations, so that RSA can be used for just SCEP.
|
|
|
|
//
|
|
|
|
// Using an RA does not seem to exist in https://tools.ietf.org/html/rfc8894, but is mentioned in
|
|
|
|
// https://tools.ietf.org/id/draft-nourse-scep-21.html.
|
|
|
|
func (a *Authority) GetCACertificates(ctx context.Context) (certs []*x509.Certificate, err error) {
|
2023-05-01 20:09:42 +00:00
|
|
|
p, err := provisionerFromContext(ctx)
|
2022-01-14 09:48:23 +00:00
|
|
|
if err != nil {
|
2023-06-01 10:10:54 +00:00
|
|
|
return
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
|
|
|
|
2023-06-01 10:10:54 +00:00
|
|
|
// if a provisioner specific RSA decrypter is available, it is returned as
|
|
|
|
// the first certificate.
|
2023-05-26 21:52:24 +00:00
|
|
|
if decrypterCertificate, _ := p.GetDecrypter(); decrypterCertificate != nil {
|
|
|
|
certs = append(certs, decrypterCertificate)
|
|
|
|
}
|
2022-01-14 09:48:23 +00:00
|
|
|
|
2023-06-01 10:10:54 +00:00
|
|
|
// TODO: ensure logic, so that signer is first intermediate and that
|
|
|
|
// there are no doubles certificates.
|
|
|
|
//certs = append(certs, a.service.signerCertificate)
|
|
|
|
certs = append(certs, a.service.intermediates...)
|
|
|
|
|
|
|
|
// the CA roots are added for completeness. Clients are responsible
|
|
|
|
// to select the right cert(s) to store and use.
|
|
|
|
if p.ShouldIncludeRootInChain() {
|
|
|
|
certs = append(certs, a.service.roots...)
|
2022-01-14 09:48:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return certs, nil
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// DecryptPKIEnvelope decrypts an enveloped message
|
2023-05-26 21:52:24 +00:00
|
|
|
func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error {
|
2021-03-06 22:24:49 +00:00
|
|
|
p7c, err := pkcs7.Parse(msg.P7.Content)
|
2021-02-25 23:32:21 +00:00
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return fmt.Errorf("error parsing pkcs7 content: %w", err)
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
|
|
|
|
2023-06-01 10:10:54 +00:00
|
|
|
fmt.Println(fmt.Sprintf("%#+v", a.service.signerCertificate))
|
2023-05-26 21:52:24 +00:00
|
|
|
fmt.Println(fmt.Sprintf("%#+v", a.service.defaultDecrypter))
|
|
|
|
|
|
|
|
cert, pkey, err := a.selectDecrypter(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed selecting decrypter: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt.Println(fmt.Sprintf("%#+v", cert))
|
|
|
|
fmt.Println(fmt.Sprintf("%#+v", pkey))
|
|
|
|
|
|
|
|
envelope, err := p7c.Decrypt(cert, pkey)
|
2021-02-25 23:32:21 +00:00
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return fmt.Errorf("error decrypting encrypted pkcs7 content: %w", err)
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
msg.pkiEnvelope = envelope
|
|
|
|
|
|
|
|
switch msg.MessageType {
|
|
|
|
case microscep.CertRep:
|
|
|
|
certs, err := microscep.CACerts(msg.pkiEnvelope)
|
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return fmt.Errorf("error extracting CA certs from pkcs7 degenerate data: %w", err)
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
2021-03-21 15:42:41 +00:00
|
|
|
msg.CertRepMessage.Certificate = certs[0]
|
2021-02-25 23:32:21 +00:00
|
|
|
return nil
|
|
|
|
case microscep.PKCSReq, microscep.UpdateReq, microscep.RenewalReq:
|
|
|
|
csr, err := x509.ParseCertificateRequest(msg.pkiEnvelope)
|
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return fmt.Errorf("parse CSR from pkiEnvelope: %w", err)
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
2023-05-26 21:52:24 +00:00
|
|
|
if err := csr.CheckSignature(); err != nil {
|
|
|
|
return fmt.Errorf("invalid CSR signature; %w", err)
|
|
|
|
}
|
2021-02-25 23:32:21 +00:00
|
|
|
// check for challengePassword
|
|
|
|
cp, err := microx509util.ParseChallengePassword(msg.pkiEnvelope)
|
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return fmt.Errorf("parse challenge password in pkiEnvelope: %w", err)
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
|
|
|
msg.CSRReqMessage = µscep.CSRReqMessage{
|
|
|
|
RawDecrypted: msg.pkiEnvelope,
|
|
|
|
CSR: csr,
|
|
|
|
ChallengePassword: cp,
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
case microscep.GetCRL, microscep.GetCert, microscep.CertPoll:
|
2022-03-24 15:08:23 +00:00
|
|
|
return errors.New("not implemented")
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-05-26 21:52:24 +00:00
|
|
|
func (a *Authority) selectDecrypter(ctx context.Context) (cert *x509.Certificate, pkey crypto.PrivateKey, err error) {
|
|
|
|
p, err := provisionerFromContext(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// return provisioner specific decrypter, if available
|
|
|
|
if cert, pkey = p.GetDecrypter(); cert != nil && pkey != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// fallback to the CA wide decrypter
|
2023-06-01 10:10:54 +00:00
|
|
|
cert = a.service.signerCertificate
|
2023-05-26 21:52:24 +00:00
|
|
|
pkey = a.service.defaultDecrypter
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-26 11:32:43 +00:00
|
|
|
// SignCSR creates an x509.Certificate based on a CSR template and Cert Authority credentials
|
2021-02-25 23:32:21 +00:00
|
|
|
// returns a new PKIMessage with CertRep data
|
2021-02-26 17:07:50 +00:00
|
|
|
func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage) (*PKIMessage, error) {
|
2021-02-26 13:00:47 +00:00
|
|
|
// TODO: intermediate storage of the request? In SCEP it's possible to request a csr/certificate
|
|
|
|
// to be signed, which can be performed asynchronously / out-of-band. In that case a client can
|
|
|
|
// poll for the status. It seems to be similar as what can happen in ACME, so might want to model
|
|
|
|
// the implementation after the one in the ACME authority. Requires storage, etc.
|
|
|
|
|
2023-05-01 20:09:42 +00:00
|
|
|
p, err := provisionerFromContext(ctx)
|
2021-02-26 11:32:43 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-02-25 23:32:21 +00:00
|
|
|
|
|
|
|
// check if CSRReqMessage has already been decrypted
|
|
|
|
if msg.CSRReqMessage.CSR == nil {
|
2021-02-26 11:32:43 +00:00
|
|
|
if err := a.DecryptPKIEnvelope(ctx, msg); err != nil {
|
2021-02-25 23:32:21 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2021-02-26 17:07:50 +00:00
|
|
|
csr = msg.CSRReqMessage.CSR
|
2021-02-25 23:32:21 +00:00
|
|
|
}
|
2021-02-12 16:02:39 +00:00
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
// Template data
|
2021-03-26 15:11:35 +00:00
|
|
|
sans := []string{}
|
|
|
|
sans = append(sans, csr.DNSNames...)
|
|
|
|
sans = append(sans, csr.EmailAddresses...)
|
|
|
|
for _, v := range csr.IPAddresses {
|
|
|
|
sans = append(sans, v.String())
|
|
|
|
}
|
|
|
|
for _, v := range csr.URIs {
|
|
|
|
sans = append(sans, v.String())
|
|
|
|
}
|
|
|
|
if len(sans) == 0 {
|
|
|
|
sans = append(sans, csr.Subject.CommonName)
|
|
|
|
}
|
|
|
|
data := x509util.CreateTemplateData(csr.Subject.CommonName, sans)
|
|
|
|
data.SetCertificateRequest(csr)
|
|
|
|
data.SetSubject(x509util.Subject{
|
|
|
|
Country: csr.Subject.Country,
|
|
|
|
Organization: csr.Subject.Organization,
|
|
|
|
OrganizationalUnit: csr.Subject.OrganizationalUnit,
|
|
|
|
Locality: csr.Subject.Locality,
|
|
|
|
Province: csr.Subject.Province,
|
|
|
|
StreetAddress: csr.Subject.StreetAddress,
|
|
|
|
PostalCode: csr.Subject.PostalCode,
|
|
|
|
SerialNumber: csr.Subject.SerialNumber,
|
|
|
|
CommonName: csr.Subject.CommonName,
|
|
|
|
})
|
2021-02-25 23:32:21 +00:00
|
|
|
|
2021-02-26 13:00:47 +00:00
|
|
|
// Get authorizations from the SCEP provisioner.
|
|
|
|
ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod)
|
|
|
|
signOps, err := p.AuthorizeSign(ctx, "")
|
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return nil, fmt.Errorf("error retrieving authorization options from SCEP provisioner: %w", err)
|
2021-02-26 13:00:47 +00:00
|
|
|
}
|
2022-09-30 00:16:26 +00:00
|
|
|
// Unlike most of the provisioners, scep's AuthorizeSign method doesn't
|
|
|
|
// define the templates, and the template data used in WebHooks is not
|
|
|
|
// available.
|
|
|
|
for _, signOp := range signOps {
|
|
|
|
if wc, ok := signOp.(*provisioner.WebhookController); ok {
|
|
|
|
wc.TemplateData = data
|
|
|
|
}
|
|
|
|
}
|
2021-02-26 13:00:47 +00:00
|
|
|
|
2022-01-27 20:06:55 +00:00
|
|
|
opts := provisioner.SignOptions{}
|
2021-02-26 11:32:43 +00:00
|
|
|
templateOptions, err := provisioner.TemplateOptions(p.GetOptions(), data)
|
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return nil, fmt.Errorf("error creating template options from SCEP provisioner: %w", err)
|
2021-02-26 11:32:43 +00:00
|
|
|
}
|
|
|
|
signOps = append(signOps, templateOptions)
|
2021-02-25 23:32:21 +00:00
|
|
|
|
2021-02-26 13:00:47 +00:00
|
|
|
certChain, err := a.signAuth.Sign(csr, opts, signOps...)
|
2021-02-12 16:02:39 +00:00
|
|
|
if err != nil {
|
2022-03-24 15:08:23 +00:00
|
|
|
return nil, fmt.Errorf("error generating certificate for order: %w", err)
|
2021-02-12 16:02:39 +00:00
|
|
|
}
|
|
|
|
|
2021-03-21 15:42:41 +00:00
|
|
|
// take the issued certificate (only); https://tools.ietf.org/html/rfc8894#section-3.3.2
|
2021-02-26 13:00:47 +00:00
|
|
|
cert := certChain[0]
|
2021-02-25 23:32:21 +00:00
|
|
|
|
2021-03-21 15:42:41 +00:00
|
|
|
// and create a degenerate cert structure
|
|
|
|
deg, err := microscep.DegenerateCertificates([]*x509.Certificate{cert})
|
2021-02-25 23:32:21 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2021-02-12 16:02:39 +00:00
|
|
|
}
|
|
|
|
|
2022-01-14 09:48:23 +00:00
|
|
|
// apparently the pkcs7 library uses a global default setting for the content encryption
|
|
|
|
// algorithm to use when en- or decrypting data. We need to restore the current setting after
|
|
|
|
// the cryptographic operation, so that other usages of the library are not influenced by
|
2022-01-18 14:54:18 +00:00
|
|
|
// this call to Encrypt(). We are not required to use the same algorithm the SCEP client uses.
|
2022-01-14 09:48:23 +00:00
|
|
|
encryptionAlgorithmToRestore := pkcs7.ContentEncryptionAlgorithm
|
|
|
|
pkcs7.ContentEncryptionAlgorithm = p.GetContentEncryptionAlgorithm()
|
2021-03-06 22:24:49 +00:00
|
|
|
e7, err := pkcs7.Encrypt(deg, msg.P7.Certificates)
|
2021-02-12 16:02:39 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-01-14 09:48:23 +00:00
|
|
|
pkcs7.ContentEncryptionAlgorithm = encryptionAlgorithmToRestore
|
2021-02-12 16:02:39 +00:00
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
// PKIMessageAttributes to be signed
|
|
|
|
config := pkcs7.SignerInfoConfig{
|
|
|
|
ExtraSignedAttributes: []pkcs7.Attribute{
|
|
|
|
{
|
|
|
|
Type: oidSCEPtransactionID,
|
|
|
|
Value: msg.TransactionID,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: oidSCEPpkiStatus,
|
|
|
|
Value: microscep.SUCCESS,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: oidSCEPmessageType,
|
|
|
|
Value: microscep.CertRep,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: oidSCEPrecipientNonce,
|
|
|
|
Value: msg.SenderNonce,
|
|
|
|
},
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPsenderNonce,
|
|
|
|
Value: msg.SenderNonce,
|
|
|
|
},
|
2021-02-25 23:32:21 +00:00
|
|
|
},
|
|
|
|
}
|
2021-02-12 16:02:39 +00:00
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
signedData, err := pkcs7.NewSignedData(e7)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-02-12 11:03:08 +00:00
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
// add the certificate into the signed data type
|
|
|
|
// this cert must be added before the signedData because the recipient will expect it
|
|
|
|
// as the first certificate in the array
|
|
|
|
signedData.AddCertificate(cert)
|
2021-02-12 16:02:39 +00:00
|
|
|
|
2023-05-26 21:52:24 +00:00
|
|
|
authCert := a.service.signerCertificate
|
|
|
|
signer := a.service.signer
|
2021-02-25 23:32:21 +00:00
|
|
|
|
|
|
|
// sign the attributes
|
2023-05-26 21:52:24 +00:00
|
|
|
if err := signedData.AddSigner(authCert, signer, config); err != nil {
|
2021-02-25 23:32:21 +00:00
|
|
|
return nil, err
|
2021-02-12 16:02:39 +00:00
|
|
|
}
|
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
certRepBytes, err := signedData.Finish()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-02-12 16:02:39 +00:00
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
cr := &CertRepMessage{
|
|
|
|
PKIStatus: microscep.SUCCESS,
|
|
|
|
RecipientNonce: microscep.RecipientNonce(msg.SenderNonce),
|
|
|
|
Certificate: cert,
|
|
|
|
degenerate: deg,
|
|
|
|
}
|
2021-02-12 11:03:08 +00:00
|
|
|
|
2021-03-10 20:13:05 +00:00
|
|
|
// create a CertRep message from the original
|
|
|
|
crepMsg := &PKIMessage{
|
|
|
|
Raw: certRepBytes,
|
|
|
|
TransactionID: msg.TransactionID,
|
|
|
|
MessageType: microscep.CertRep,
|
|
|
|
CertRepMessage: cr,
|
|
|
|
}
|
|
|
|
|
|
|
|
return crepMsg, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// CreateFailureResponse creates an appropriately signed reply for PKI operations
|
2023-05-10 06:47:28 +00:00
|
|
|
func (a *Authority) CreateFailureResponse(_ context.Context, _ *x509.CertificateRequest, msg *PKIMessage, info FailInfoName, infoText string) (*PKIMessage, error) {
|
2021-03-10 20:13:05 +00:00
|
|
|
config := pkcs7.SignerInfoConfig{
|
|
|
|
ExtraSignedAttributes: []pkcs7.Attribute{
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPtransactionID,
|
|
|
|
Value: msg.TransactionID,
|
|
|
|
},
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPpkiStatus,
|
|
|
|
Value: microscep.FAILURE,
|
|
|
|
},
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPfailInfo,
|
|
|
|
Value: info,
|
|
|
|
},
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPfailInfoText,
|
|
|
|
Value: infoText,
|
|
|
|
},
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPmessageType,
|
|
|
|
Value: microscep.CertRep,
|
|
|
|
},
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPsenderNonce,
|
|
|
|
Value: msg.SenderNonce,
|
|
|
|
},
|
2021-03-10 21:20:02 +00:00
|
|
|
{
|
2021-03-10 20:13:05 +00:00
|
|
|
Type: oidSCEPrecipientNonce,
|
|
|
|
Value: msg.SenderNonce,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
signedData, err := pkcs7.NewSignedData(nil)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// sign the attributes
|
2023-05-26 21:52:24 +00:00
|
|
|
if err := signedData.AddSigner(a.service.signerCertificate, a.service.signer, config); err != nil {
|
2021-03-10 20:13:05 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
certRepBytes, err := signedData.Finish()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
cr := &CertRepMessage{
|
|
|
|
PKIStatus: microscep.FAILURE,
|
2021-05-06 22:23:09 +00:00
|
|
|
FailInfo: microscep.FailInfo(info),
|
2021-03-10 20:13:05 +00:00
|
|
|
RecipientNonce: microscep.RecipientNonce(msg.SenderNonce),
|
|
|
|
}
|
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
// create a CertRep message from the original
|
|
|
|
crepMsg := &PKIMessage{
|
|
|
|
Raw: certRepBytes,
|
|
|
|
TransactionID: msg.TransactionID,
|
|
|
|
MessageType: microscep.CertRep,
|
|
|
|
CertRepMessage: cr,
|
2021-02-12 16:02:39 +00:00
|
|
|
}
|
2021-02-12 11:03:08 +00:00
|
|
|
|
2021-02-25 23:32:21 +00:00
|
|
|
return crepMsg, nil
|
|
|
|
}
|
|
|
|
|
2021-03-06 23:50:00 +00:00
|
|
|
// GetCACaps returns the CA capabilities
|
|
|
|
func (a *Authority) GetCACaps(ctx context.Context) []string {
|
2023-05-01 20:09:42 +00:00
|
|
|
p, err := provisionerFromContext(ctx)
|
2021-03-06 23:50:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return defaultCapabilities
|
|
|
|
}
|
|
|
|
|
|
|
|
caps := p.GetCapabilities()
|
|
|
|
if len(caps) == 0 {
|
|
|
|
return defaultCapabilities
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: validate the caps? Ensure they are the right format according to RFC?
|
|
|
|
// TODO: ensure that the capabilities are actually "enforced"/"verified" in code too:
|
|
|
|
// check that only parts of the spec are used in the implementation belonging to the capabilities.
|
|
|
|
// For example for renewals, which we could disable in the provisioner, should then also
|
|
|
|
// not be reported in cacaps operation.
|
|
|
|
|
|
|
|
return caps
|
|
|
|
}
|
2023-05-01 20:09:42 +00:00
|
|
|
|
|
|
|
func (a *Authority) ValidateChallenge(ctx context.Context, challenge, transactionID string) error {
|
|
|
|
p, err := provisionerFromContext(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return p.ValidateChallenge(ctx, challenge, transactionID)
|
|
|
|
}
|