forked from TrueCloudLab/certificates
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:
parent
b98f86a515
commit
e27124b037
3 changed files with 35 additions and 54 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
// Package api implements a SCEP HTTP server.
|
||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -31,12 +32,6 @@ const (
|
||||||
|
|
||||||
const maxPayloadSize = 2 << 20
|
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.
|
// request is a SCEP server request.
|
||||||
type request struct {
|
type request struct {
|
||||||
Operation string
|
Operation string
|
||||||
|
@ -54,17 +49,19 @@ type response struct {
|
||||||
|
|
||||||
// handler is the SCEP request handler.
|
// handler is the SCEP request handler.
|
||||||
type handler struct {
|
type handler struct {
|
||||||
Auth scep.Interface
|
auth *scep.Authority
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a new SCEP API router.
|
// New returns a new SCEP API router.
|
||||||
func New(scepAuth scep.Interface) api.RouterHandler {
|
func New(auth *scep.Authority) api.RouterHandler {
|
||||||
return &handler{scepAuth}
|
return &handler{
|
||||||
|
auth: auth,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Route traffic and implement the Router interface.
|
// Route traffic and implement the Router interface.
|
||||||
func (h *handler) Route(r api.Router) {
|
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.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))
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := h.Auth.LoadProvisionerByName(provisionerName)
|
p, err := h.auth.LoadProvisionerByName(provisionerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fail(w, err)
|
fail(w, err)
|
||||||
return
|
return
|
||||||
|
@ -213,7 +210,7 @@ func (h *handler) lookupProvisioner(next http.HandlerFunc) http.HandlerFunc {
|
||||||
// GetCACert returns the CA certificates in a SCEP response
|
// GetCACert returns the CA certificates in a SCEP response
|
||||||
func (h *handler) GetCACert(ctx context.Context) (response, error) {
|
func (h *handler) GetCACert(ctx context.Context) (response, error) {
|
||||||
|
|
||||||
certs, err := h.Auth.GetCACertificates(ctx)
|
certs, err := h.auth.GetCACertificates(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response{}, err
|
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
|
// GetCACaps returns the CA capabilities in a SCEP response
|
||||||
func (h *handler) GetCACaps(ctx context.Context) (response, error) {
|
func (h *handler) GetCACaps(ctx context.Context) (response, error) {
|
||||||
|
|
||||||
caps := h.Auth.GetCACaps(ctx)
|
caps := h.auth.GetCACaps(ctx)
|
||||||
|
|
||||||
res := response{
|
res := response{
|
||||||
Operation: opnGetCACaps,
|
Operation: opnGetCACaps,
|
||||||
|
@ -283,7 +280,7 @@ func (h *handler) PKIOperation(ctx context.Context, req request) (response, erro
|
||||||
P7: p7,
|
P7: p7,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.Auth.DecryptPKIEnvelope(ctx, msg); err != nil {
|
if err := h.auth.DecryptPKIEnvelope(ctx, msg); err != nil {
|
||||||
return response{}, err
|
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.
|
// 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.
|
// We'll have to see how it works out.
|
||||||
if msg.MessageType == microscep.PKCSReq || msg.MessageType == microscep.RenewalReq {
|
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 {
|
if err != nil {
|
||||||
return h.createFailureResponse(ctx, csr, msg, microscep.BadRequest, errors.New("error when checking password"))
|
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
|
// Authentication by the (self-signed) certificate with an optional challenge is required; supporting renewals incl. verification
|
||||||
// of the client cert is not.
|
// 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 {
|
if err != nil {
|
||||||
return h.createFailureResponse(ctx, csr, msg, microscep.BadRequest, fmt.Errorf("error when signing new certificate: %w", err))
|
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) {
|
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 {
|
if err != nil {
|
||||||
return response{}, err
|
return response{}, err
|
||||||
}
|
}
|
||||||
|
@ -367,14 +364,14 @@ func (h *handler) createFailureResponse(ctx context.Context, csr *x509.Certifica
|
||||||
|
|
||||||
func contentHeader(r response) string {
|
func contentHeader(r response) string {
|
||||||
switch r.Operation {
|
switch r.Operation {
|
||||||
case opnGetCACert:
|
|
||||||
if r.CACertNum > 1 {
|
|
||||||
return certChainHeader
|
|
||||||
}
|
|
||||||
return leafHeader
|
|
||||||
case opnPKIOperation:
|
|
||||||
return pkiOperationHeader
|
|
||||||
default:
|
default:
|
||||||
return "text/plain"
|
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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,33 +4,19 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
|
||||||
|
|
||||||
microx509util "github.com/micromdm/scep/v2/cryptoutil/x509util"
|
microx509util "github.com/micromdm/scep/v2/cryptoutil/x509util"
|
||||||
microscep "github.com/micromdm/scep/v2/scep"
|
microscep "github.com/micromdm/scep/v2/scep"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
|
|
||||||
"go.mozilla.org/pkcs7"
|
"go.mozilla.org/pkcs7"
|
||||||
|
|
||||||
"go.step.sm/crypto/x509util"
|
"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.
|
// Authority is the layer that handles all SCEP interactions.
|
||||||
type Authority struct {
|
type Authority struct {
|
||||||
prefix string
|
prefix string
|
||||||
|
@ -180,12 +166,12 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
||||||
|
|
||||||
p7c, err := pkcs7.Parse(msg.P7.Content)
|
p7c, err := pkcs7.Parse(msg.P7.Content)
|
||||||
if err != nil {
|
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)
|
envelope, err := p7c.Decrypt(a.intermediateCertificate, a.service.decrypter)
|
||||||
if err != nil {
|
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
|
msg.pkiEnvelope = envelope
|
||||||
|
@ -194,19 +180,19 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
||||||
case microscep.CertRep:
|
case microscep.CertRep:
|
||||||
certs, err := microscep.CACerts(msg.pkiEnvelope)
|
certs, err := microscep.CACerts(msg.pkiEnvelope)
|
||||||
if err != nil {
|
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]
|
msg.CertRepMessage.Certificate = certs[0]
|
||||||
return nil
|
return nil
|
||||||
case microscep.PKCSReq, microscep.UpdateReq, microscep.RenewalReq:
|
case microscep.PKCSReq, microscep.UpdateReq, microscep.RenewalReq:
|
||||||
csr, err := x509.ParseCertificateRequest(msg.pkiEnvelope)
|
csr, err := x509.ParseCertificateRequest(msg.pkiEnvelope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "parse CSR from pkiEnvelope")
|
return fmt.Errorf("parse CSR from pkiEnvelope: %w", err)
|
||||||
}
|
}
|
||||||
// check for challengePassword
|
// check for challengePassword
|
||||||
cp, err := microx509util.ParseChallengePassword(msg.pkiEnvelope)
|
cp, err := microx509util.ParseChallengePassword(msg.pkiEnvelope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "parse challenge password in pkiEnvelope")
|
return fmt.Errorf("parse challenge password in pkiEnvelope: %w", err)
|
||||||
}
|
}
|
||||||
msg.CSRReqMessage = µscep.CSRReqMessage{
|
msg.CSRReqMessage = µscep.CSRReqMessage{
|
||||||
RawDecrypted: msg.pkiEnvelope,
|
RawDecrypted: msg.pkiEnvelope,
|
||||||
|
@ -215,7 +201,7 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
case microscep.GetCRL, microscep.GetCert, microscep.CertPoll:
|
case microscep.GetCRL, microscep.GetCert, microscep.CertPoll:
|
||||||
return errors.Errorf("not implemented")
|
return errors.New("not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -274,19 +260,19 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m
|
||||||
ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod)
|
ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod)
|
||||||
signOps, err := p.AuthorizeSign(ctx, "")
|
signOps, err := p.AuthorizeSign(ctx, "")
|
||||||
if err != nil {
|
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{}
|
opts := provisioner.SignOptions{}
|
||||||
templateOptions, err := provisioner.TemplateOptions(p.GetOptions(), data)
|
templateOptions, err := provisioner.TemplateOptions(p.GetOptions(), data)
|
||||||
if err != nil {
|
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)
|
signOps = append(signOps, templateOptions)
|
||||||
|
|
||||||
certChain, err := a.signAuth.Sign(csr, opts, signOps...)
|
certChain, err := a.signAuth.Sign(csr, opts, signOps...)
|
||||||
if err != nil {
|
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
|
// take the issued certificate (only); https://tools.ietf.org/html/rfc8894#section-3.3.2
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
// Package scep implements Simple Certificate Enrollment Protocol related functionality.
|
||||||
package scep
|
package scep
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -5,9 +6,6 @@ import (
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
|
|
||||||
microscep "github.com/micromdm/scep/v2/scep"
|
microscep "github.com/micromdm/scep/v2/scep"
|
||||||
|
|
||||||
//"github.com/smallstep/certificates/scep/pkcs7"
|
|
||||||
|
|
||||||
"go.mozilla.org/pkcs7"
|
"go.mozilla.org/pkcs7"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue