scep: remove Interface and the dependency to pkg/errors (#872)

* scep: documented the package

* scep/api: removed some top level constants

* scep: removed dependency to pkg/errors

* scep/api: documented the package
This commit is contained in:
Panagiotis Siatras 2022-03-24 17:08:23 +02:00 committed by Mariano Cano
parent bca74cb6a7
commit a852223717
3 changed files with 35 additions and 54 deletions

View file

@ -1,3 +1,4 @@
// Package api implements a SCEP HTTP server.
package api
import (
@ -31,12 +32,6 @@ const (
const maxPayloadSize = 2 << 20
const (
certChainHeader = "application/x-x509-ca-ra-cert"
leafHeader = "application/x-x509-ca-cert"
pkiOperationHeader = "application/x-pki-message"
)
// request is a SCEP server request.
type request struct {
Operation string
@ -54,17 +49,19 @@ type response struct {
// handler is the SCEP request handler.
type handler struct {
Auth scep.Interface
auth *scep.Authority
}
// New returns a new SCEP API router.
func New(scepAuth scep.Interface) api.RouterHandler {
return &handler{scepAuth}
func New(auth *scep.Authority) api.RouterHandler {
return &handler{
auth: auth,
}
}
// Route traffic and implement the Router interface.
func (h *handler) Route(r api.Router) {
getLink := h.Auth.GetLinkExplicit
getLink := h.auth.GetLinkExplicit
r.MethodFunc(http.MethodGet, getLink("{provisionerName}/*", false, nil), h.lookupProvisioner(h.Get))
r.MethodFunc(http.MethodGet, getLink("{provisionerName}", false, nil), h.lookupProvisioner(h.Get))
r.MethodFunc(http.MethodPost, getLink("{provisionerName}/*", false, nil), h.lookupProvisioner(h.Post))
@ -192,7 +189,7 @@ func (h *handler) lookupProvisioner(next http.HandlerFunc) http.HandlerFunc {
return
}
p, err := h.Auth.LoadProvisionerByName(provisionerName)
p, err := h.auth.LoadProvisionerByName(provisionerName)
if err != nil {
fail(w, err)
return
@ -213,7 +210,7 @@ func (h *handler) lookupProvisioner(next http.HandlerFunc) http.HandlerFunc {
// GetCACert returns the CA certificates in a SCEP response
func (h *handler) GetCACert(ctx context.Context) (response, error) {
certs, err := h.Auth.GetCACertificates(ctx)
certs, err := h.auth.GetCACertificates(ctx)
if err != nil {
return response{}, err
}
@ -246,7 +243,7 @@ func (h *handler) GetCACert(ctx context.Context) (response, error) {
// GetCACaps returns the CA capabilities in a SCEP response
func (h *handler) GetCACaps(ctx context.Context) (response, error) {
caps := h.Auth.GetCACaps(ctx)
caps := h.auth.GetCACaps(ctx)
res := response{
Operation: opnGetCACaps,
@ -283,7 +280,7 @@ func (h *handler) PKIOperation(ctx context.Context, req request) (response, erro
P7: p7,
}
if err := h.Auth.DecryptPKIEnvelope(ctx, msg); err != nil {
if err := h.auth.DecryptPKIEnvelope(ctx, msg); err != nil {
return response{}, err
}
@ -296,7 +293,7 @@ func (h *handler) PKIOperation(ctx context.Context, req request) (response, erro
// a certificate exists; then it will use RenewalReq. Adding the challenge check here may be a small breaking change for clients.
// We'll have to see how it works out.
if msg.MessageType == microscep.PKCSReq || msg.MessageType == microscep.RenewalReq {
challengeMatches, err := h.Auth.MatchChallengePassword(ctx, msg.CSRReqMessage.ChallengePassword)
challengeMatches, err := h.auth.MatchChallengePassword(ctx, msg.CSRReqMessage.ChallengePassword)
if err != nil {
return h.createFailureResponse(ctx, csr, msg, microscep.BadRequest, errors.New("error when checking password"))
}
@ -314,7 +311,7 @@ func (h *handler) PKIOperation(ctx context.Context, req request) (response, erro
// Authentication by the (self-signed) certificate with an optional challenge is required; supporting renewals incl. verification
// of the client cert is not.
certRep, err := h.Auth.SignCSR(ctx, csr, msg)
certRep, err := h.auth.SignCSR(ctx, csr, msg)
if err != nil {
return h.createFailureResponse(ctx, csr, msg, microscep.BadRequest, fmt.Errorf("error when signing new certificate: %w", err))
}
@ -354,7 +351,7 @@ func fail(w http.ResponseWriter, err error) {
}
func (h *handler) createFailureResponse(ctx context.Context, csr *x509.CertificateRequest, msg *scep.PKIMessage, info microscep.FailInfo, failError error) (response, error) {
certRepMsg, err := h.Auth.CreateFailureResponse(ctx, csr, msg, scep.FailInfoName(info), failError.Error())
certRepMsg, err := h.auth.CreateFailureResponse(ctx, csr, msg, scep.FailInfoName(info), failError.Error())
if err != nil {
return response{}, err
}
@ -367,14 +364,14 @@ func (h *handler) createFailureResponse(ctx context.Context, csr *x509.Certifica
func contentHeader(r response) string {
switch r.Operation {
case opnGetCACert:
if r.CACertNum > 1 {
return certChainHeader
}
return leafHeader
case opnPKIOperation:
return pkiOperationHeader
default:
return "text/plain"
case opnGetCACert:
if r.CACertNum > 1 {
return "application/x-x509-ca-ra-cert"
}
return "application/x-x509-ca-cert"
case opnPKIOperation:
return "application/x-pki-message"
}
}

View file

@ -4,33 +4,19 @@ import (
"context"
"crypto/subtle"
"crypto/x509"
"errors"
"fmt"
"net/url"
"github.com/smallstep/certificates/authority/provisioner"
microx509util "github.com/micromdm/scep/v2/cryptoutil/x509util"
microscep "github.com/micromdm/scep/v2/scep"
"github.com/pkg/errors"
"go.mozilla.org/pkcs7"
"go.step.sm/crypto/x509util"
"github.com/smallstep/certificates/authority/provisioner"
)
// Interface is the SCEP authority interface.
type Interface interface {
LoadProvisionerByName(string) (provisioner.Interface, error)
GetLinkExplicit(provName string, absoluteLink bool, baseURL *url.URL, inputs ...string) string
GetCACertificates(ctx context.Context) ([]*x509.Certificate, error)
DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error
SignCSR(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage) (*PKIMessage, error)
CreateFailureResponse(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage, info FailInfoName, infoText string) (*PKIMessage, error)
MatchChallengePassword(ctx context.Context, password string) (bool, error)
GetCACaps(ctx context.Context) []string
}
// Authority is the layer that handles all SCEP interactions.
type Authority struct {
prefix string
@ -180,12 +166,12 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
p7c, err := pkcs7.Parse(msg.P7.Content)
if err != nil {
return errors.Wrap(err, "error parsing pkcs7 content")
return fmt.Errorf("error parsing pkcs7 content: %w", err)
}
envelope, err := p7c.Decrypt(a.intermediateCertificate, a.service.decrypter)
if err != nil {
return errors.Wrap(err, "error decrypting encrypted pkcs7 content")
return fmt.Errorf("error decrypting encrypted pkcs7 content: %w", err)
}
msg.pkiEnvelope = envelope
@ -194,19 +180,19 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
case microscep.CertRep:
certs, err := microscep.CACerts(msg.pkiEnvelope)
if err != nil {
return errors.Wrap(err, "error extracting CA certs from pkcs7 degenerate data")
return fmt.Errorf("error extracting CA certs from pkcs7 degenerate data: %w", err)
}
msg.CertRepMessage.Certificate = certs[0]
return nil
case microscep.PKCSReq, microscep.UpdateReq, microscep.RenewalReq:
csr, err := x509.ParseCertificateRequest(msg.pkiEnvelope)
if err != nil {
return errors.Wrap(err, "parse CSR from pkiEnvelope")
return fmt.Errorf("parse CSR from pkiEnvelope: %w", err)
}
// check for challengePassword
cp, err := microx509util.ParseChallengePassword(msg.pkiEnvelope)
if err != nil {
return errors.Wrap(err, "parse challenge password in pkiEnvelope")
return fmt.Errorf("parse challenge password in pkiEnvelope: %w", err)
}
msg.CSRReqMessage = &microscep.CSRReqMessage{
RawDecrypted: msg.pkiEnvelope,
@ -215,7 +201,7 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
}
return nil
case microscep.GetCRL, microscep.GetCert, microscep.CertPoll:
return errors.Errorf("not implemented")
return errors.New("not implemented")
}
return nil
@ -274,19 +260,19 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m
ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod)
signOps, err := p.AuthorizeSign(ctx, "")
if err != nil {
return nil, errors.Wrap(err, "error retrieving authorization options from SCEP provisioner")
return nil, fmt.Errorf("error retrieving authorization options from SCEP provisioner: %w", err)
}
opts := provisioner.SignOptions{}
templateOptions, err := provisioner.TemplateOptions(p.GetOptions(), data)
if err != nil {
return nil, errors.Wrap(err, "error creating template options from SCEP provisioner")
return nil, fmt.Errorf("error creating template options from SCEP provisioner: %w", err)
}
signOps = append(signOps, templateOptions)
certChain, err := a.signAuth.Sign(csr, opts, signOps...)
if err != nil {
return nil, errors.Wrap(err, "error generating certificate for order")
return nil, fmt.Errorf("error generating certificate for order: %w", err)
}
// take the issued certificate (only); https://tools.ietf.org/html/rfc8894#section-3.3.2

View file

@ -1,3 +1,4 @@
// Package scep implements Simple Certificate Enrollment Protocol related functionality.
package scep
import (
@ -5,9 +6,6 @@ import (
"encoding/asn1"
microscep "github.com/micromdm/scep/v2/scep"
//"github.com/smallstep/certificates/scep/pkcs7"
"go.mozilla.org/pkcs7"
)