forked from TrueCloudLab/certificates
Add support for multiple SCEP provisioners
Similarly to how ACME suppors multiple provisioners, it's now possible to load the right provisioner based on the URL.
This commit is contained in:
parent
a191319da9
commit
5df60c5a9b
4 changed files with 78 additions and 26 deletions
2
ca/ca.go
2
ca/ca.go
|
@ -212,7 +212,7 @@ func (ca *CA) Init(config *config.Config) (*CA, error) {
|
|||
})
|
||||
}
|
||||
|
||||
// helpful routine for logging all routes //
|
||||
// helpful routine for logging all routes
|
||||
//dumpRoutes(mux)
|
||||
|
||||
// Add monitoring if configured
|
||||
|
|
|
@ -9,8 +9,10 @@ import (
|
|||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/smallstep/certificates/api"
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
"github.com/smallstep/certificates/scep"
|
||||
|
@ -76,14 +78,10 @@ func New(scepAuth scep.Interface) api.RouterHandler {
|
|||
|
||||
// Route traffic and implement the Router interface.
|
||||
func (h *Handler) Route(r api.Router) {
|
||||
//getLink := h.Auth.GetLinkExplicit
|
||||
//fmt.Println(getLink)
|
||||
getLink := h.Auth.GetLinkExplicit
|
||||
|
||||
//r.MethodFunc("GET", "/bla", h.baseURLFromRequest(h.lookupProvisioner(nil)))
|
||||
//r.MethodFunc("GET", getLink(acme.NewNonceLink, "{provisionerID}", false, nil), h.baseURLFromRequest(h.lookupProvisioner(h.addNonce(h.GetNonce))))
|
||||
|
||||
r.MethodFunc(http.MethodGet, "/", h.lookupProvisioner(h.Get))
|
||||
r.MethodFunc(http.MethodPost, "/", h.lookupProvisioner(h.Post))
|
||||
r.MethodFunc(http.MethodGet, getLink("{provisionerID}", false, nil), h.lookupProvisioner(h.Get))
|
||||
r.MethodFunc(http.MethodPost, getLink("{provisionerID}", false, nil), h.lookupProvisioner(h.Post))
|
||||
|
||||
}
|
||||
|
||||
|
@ -202,16 +200,12 @@ func decodeSCEPRequest(r *http.Request) (SCEPRequest, error) {
|
|||
func (h *Handler) lookupProvisioner(next nextHTTP) nextHTTP {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// name := chi.URLParam(r, "provisionerID")
|
||||
// provisionerID, err := url.PathUnescape(name)
|
||||
// if err != nil {
|
||||
// api.WriteError(w, fmt.Errorf("error url unescaping provisioner id '%s'", name))
|
||||
// return
|
||||
// }
|
||||
|
||||
// TODO: make this configurable; and we might want to look at being able to provide multiple,
|
||||
// like the ACME one? The below assumes a SCEP provider (scep/) called "scep1" exists.
|
||||
provisionerID := "scep1"
|
||||
name := chi.URLParam(r, "provisionerID")
|
||||
provisionerID, err := url.PathUnescape(name)
|
||||
if err != nil {
|
||||
api.WriteError(w, fmt.Errorf("error url unescaping provisioner id '%s'", name))
|
||||
return
|
||||
}
|
||||
|
||||
p, err := h.Auth.LoadProvisionerByID("scep/" + provisionerID)
|
||||
if err != nil {
|
||||
|
@ -275,6 +269,8 @@ func (h *Handler) PKIOperation(ctx context.Context, request SCEPRequest) (SCEPRe
|
|||
|
||||
response := SCEPResponse{Operation: opnPKIOperation}
|
||||
|
||||
fmt.Println("BEFORE PARSING")
|
||||
|
||||
microMsg, err := microscep.ParsePKIMessage(request.Message)
|
||||
if err != nil {
|
||||
return SCEPResponse{}, err
|
||||
|
@ -287,7 +283,12 @@ func (h *Handler) PKIOperation(ctx context.Context, request SCEPRequest) (SCEPRe
|
|||
Raw: microMsg.Raw,
|
||||
}
|
||||
|
||||
fmt.Println("len raw:", len(microMsg.Raw))
|
||||
|
||||
fmt.Println("AFTER PARSING")
|
||||
|
||||
if err := h.Auth.DecryptPKIEnvelope(ctx, msg); err != nil {
|
||||
fmt.Println("ERROR IN DECRYPTPKIENVELOPE")
|
||||
return SCEPResponse{}, err
|
||||
}
|
||||
|
||||
|
@ -311,6 +312,8 @@ func (h *Handler) PKIOperation(ctx context.Context, request SCEPRequest) (SCEPRe
|
|||
response.Data = certRep.Raw
|
||||
response.Certificate = certRep.Certificate
|
||||
|
||||
fmt.Println("HERE!!!")
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
|
@ -336,8 +339,8 @@ func writeSCEPResponse(w http.ResponseWriter, response SCEPResponse) {
|
|||
|
||||
func writeError(w http.ResponseWriter, err error) {
|
||||
scepError := &scep.Error{
|
||||
Err: fmt.Errorf("post request failed: %w", err),
|
||||
Status: http.StatusInternalServerError, // TODO: make this a param?
|
||||
Message: err.Error(),
|
||||
Status: http.StatusInternalServerError, // TODO: make this a param?
|
||||
}
|
||||
api.WriteError(w, scepError)
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
database "github.com/smallstep/certificates/db"
|
||||
|
@ -55,6 +56,8 @@ type Interface interface {
|
|||
GetCACertificates() ([]*x509.Certificate, error)
|
||||
DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error
|
||||
SignCSR(ctx context.Context, csr *x509.CertificateRequest, msg *PKIMessage) (*PKIMessage, error)
|
||||
|
||||
GetLinkExplicit(provName string, absoluteLink bool, baseURL *url.URL, inputs ...string) string
|
||||
}
|
||||
|
||||
// Authority is the layer that handles all SCEP interactions.
|
||||
|
@ -130,6 +133,44 @@ func (a *Authority) LoadProvisionerByID(id string) (provisioner.Interface, error
|
|||
return a.signAuth.LoadProvisionerByID(id)
|
||||
}
|
||||
|
||||
// GetLinkExplicit returns the requested link from the directory.
|
||||
func (a *Authority) GetLinkExplicit(provName string, abs bool, baseURL *url.URL, inputs ...string) string {
|
||||
// TODO: taken from ACME; move it to directory (if we need a directory in SCEP)?
|
||||
return a.getLinkExplicit(provName, abs, baseURL, inputs...)
|
||||
}
|
||||
|
||||
// getLinkExplicit returns an absolute or partial path to the given resource and a base
|
||||
// URL dynamically obtained from the request for which the link is being calculated.
|
||||
func (a *Authority) getLinkExplicit(provisionerName string, abs bool, baseURL *url.URL, inputs ...string) string {
|
||||
|
||||
// TODO: do we need to provide a way to provide a different suffix/base?
|
||||
// Like "/cgi-bin/pkiclient.exe"? Or would it be enough to have that as the name?
|
||||
link := fmt.Sprintf("/%s", provisionerName)
|
||||
|
||||
if abs {
|
||||
// Copy the baseURL value from the pointer. https://github.com/golang/go/issues/38351
|
||||
u := url.URL{}
|
||||
if baseURL != nil {
|
||||
u = *baseURL
|
||||
}
|
||||
|
||||
// If no Scheme is set, then default to https.
|
||||
if u.Scheme == "" {
|
||||
u.Scheme = "https"
|
||||
}
|
||||
|
||||
// If no Host is set, then use the default (first DNS attr in the ca.json).
|
||||
if u.Host == "" {
|
||||
u.Host = a.dns
|
||||
}
|
||||
|
||||
u.Path = a.prefix + link
|
||||
return u.String()
|
||||
}
|
||||
|
||||
return link
|
||||
}
|
||||
|
||||
// GetCACertificates returns the certificate (chain) for the CA
|
||||
func (a *Authority) GetCACertificates() ([]*x509.Certificate, error) {
|
||||
|
||||
|
@ -164,6 +205,8 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
|||
return err
|
||||
}
|
||||
|
||||
fmt.Println("len content:", len(p7.Content))
|
||||
|
||||
var tID microscep.TransactionID
|
||||
if err := p7.UnmarshalSignedAttribute(oidSCEPtransactionID, &tID); err != nil {
|
||||
return err
|
||||
|
@ -176,11 +219,17 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
|||
|
||||
msg.p7 = p7
|
||||
|
||||
//p7c, err := pkcs7.Parse(p7.Content)
|
||||
p7c, err := pkcs7.Parse(p7.Content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(tID)
|
||||
fmt.Println(msgType)
|
||||
|
||||
fmt.Println("len p7c content:", len(p7c.Content))
|
||||
|
||||
envelope, err := p7c.Decrypt(a.intermediateCertificate, a.service.Decrypter)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -308,7 +357,7 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m
|
|||
// fmt.Println(string(cert.SubjectKeyId))
|
||||
|
||||
// create a degenerate cert structure
|
||||
deg, err := DegenerateCertificates([]*x509.Certificate{cert})
|
||||
deg, err := degenerateCertificates([]*x509.Certificate{cert})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -380,8 +429,8 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m
|
|||
return crepMsg, nil
|
||||
}
|
||||
|
||||
// DegenerateCertificates creates degenerate certificates pkcs#7 type
|
||||
func DegenerateCertificates(certs []*x509.Certificate) ([]byte, error) {
|
||||
// degenerateCertificates creates degenerate certificates pkcs#7 type
|
||||
func degenerateCertificates(certs []*x509.Certificate) ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
for _, cert := range certs {
|
||||
buf.Write(cert.Raw)
|
||||
|
|
|
@ -4,8 +4,8 @@ package scep
|
|||
type Error struct {
|
||||
// Type ProbType
|
||||
// Detail string
|
||||
Err error
|
||||
Status int
|
||||
Message string `json:"message"`
|
||||
Status int `json:"-"`
|
||||
// Sub []*Error
|
||||
// Identifier *Identifier
|
||||
}
|
||||
|
@ -15,5 +15,5 @@ func (e *Error) Error() string {
|
|||
// if e.Err == nil {
|
||||
// return e.Detail
|
||||
// }
|
||||
return e.Err.Error()
|
||||
return e.Message
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue