forked from TrueCloudLab/certificates
Add AuthorizeSign method to SCEP authority
This commit is contained in:
parent
812e1c7218
commit
da65f46d0f
3 changed files with 42 additions and 27 deletions
|
@ -1,6 +1,7 @@
|
||||||
package provisioner
|
package provisioner
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
@ -13,7 +14,7 @@ type SCEP struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|
||||||
// ForceCN bool `json:"forceCN,omitempty"`
|
ForceCN bool `json:"forceCN,omitempty"`
|
||||||
Options *Options `json:"options,omitempty"`
|
Options *Options `json:"options,omitempty"`
|
||||||
Claims *Claims `json:"claims,omitempty"`
|
Claims *Claims `json:"claims,omitempty"`
|
||||||
claimer *Claimer
|
claimer *Claimer
|
||||||
|
@ -75,6 +76,21 @@ func (s *SCEP) Init(config Config) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthorizeSign does not do any validation, because all validation is handled
|
||||||
|
// in the SCEP protocol. This method returns a list of modifiers / constraints
|
||||||
|
// on the resulting certificate.
|
||||||
|
func (s *SCEP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) {
|
||||||
|
return []SignOption{
|
||||||
|
// modifiers / withOptions
|
||||||
|
newProvisionerExtensionOption(TypeSCEP, s.Name, ""),
|
||||||
|
newForceCNOption(s.ForceCN),
|
||||||
|
profileDefaultDuration(s.claimer.DefaultTLSCertDuration()),
|
||||||
|
// validators
|
||||||
|
defaultPublicKeyValidator{},
|
||||||
|
newValidityValidator(s.claimer.MinTLSCertDuration(), s.claimer.MaxTLSCertDuration()),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Interface guards
|
// Interface guards
|
||||||
var (
|
var (
|
||||||
_ Interface = (*SCEP)(nil)
|
_ Interface = (*SCEP)(nil)
|
||||||
|
|
|
@ -6,8 +6,6 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
database "github.com/smallstep/certificates/db"
|
database "github.com/smallstep/certificates/db"
|
||||||
|
@ -53,8 +51,6 @@ type Interface interface {
|
||||||
// GetLinkExplicit(linkType Link, provName string, absoluteLink bool, baseURL *url.URL, inputs ...string) string
|
// GetLinkExplicit(linkType Link, provName string, absoluteLink bool, baseURL *url.URL, inputs ...string) string
|
||||||
|
|
||||||
GetCACertificates() ([]*x509.Certificate, error)
|
GetCACertificates() ([]*x509.Certificate, error)
|
||||||
//GetSigningKey() (*rsa.PrivateKey, error)
|
|
||||||
|
|
||||||
DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error
|
DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) error
|
||||||
SignCSR(ctx context.Context, msg *PKIMessage, template *x509.Certificate) (*PKIMessage, error)
|
SignCSR(ctx context.Context, msg *PKIMessage, template *x509.Certificate) (*PKIMessage, error)
|
||||||
}
|
}
|
||||||
|
@ -201,12 +197,12 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
||||||
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 fmt.Errorf("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 fmt.Errorf("scep: parse challenge password in pkiEnvelope")
|
return fmt.Errorf("scep: parse challenge password in pkiEnvelope: %w", err)
|
||||||
}
|
}
|
||||||
msg.CSRReqMessage = µscep.CSRReqMessage{
|
msg.CSRReqMessage = µscep.CSRReqMessage{
|
||||||
RawDecrypted: msg.pkiEnvelope,
|
RawDecrypted: msg.pkiEnvelope,
|
||||||
|
@ -227,6 +223,11 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
||||||
//func (msg *PKIMessage) SignCSR(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, template *x509.Certificate) (*PKIMessage, error) {
|
//func (msg *PKIMessage) SignCSR(crtAuth *x509.Certificate, keyAuth *rsa.PrivateKey, template *x509.Certificate) (*PKIMessage, error) {
|
||||||
func (a *Authority) SignCSR(ctx context.Context, msg *PKIMessage, template *x509.Certificate) (*PKIMessage, error) {
|
func (a *Authority) SignCSR(ctx context.Context, msg *PKIMessage, template *x509.Certificate) (*PKIMessage, error) {
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
|
||||||
p, err := ProvisionerFromContext(ctx)
|
p, err := ProvisionerFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -245,32 +246,32 @@ func (a *Authority) SignCSR(ctx context.Context, msg *PKIMessage, template *x509
|
||||||
data := x509util.NewTemplateData()
|
data := x509util.NewTemplateData()
|
||||||
data.SetCommonName(csr.Subject.CommonName)
|
data.SetCommonName(csr.Subject.CommonName)
|
||||||
data.SetSANs(csr.DNSNames)
|
data.SetSANs(csr.DNSNames)
|
||||||
|
data.SetCertificateRequest(csr)
|
||||||
|
|
||||||
// TODO: proper options
|
// Get authorizations from the SCEP provisioner.
|
||||||
opts := provisioner.SignOptions{}
|
ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod)
|
||||||
signOps := []provisioner.SignOption{}
|
signOps, err := p.AuthorizeSign(ctx, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error retrieving authorization options from SCEP provisioner: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := provisioner.SignOptions{
|
||||||
|
// NotBefore: provisioner.NewTimeDuration(o.NotBefore),
|
||||||
|
// NotAfter: provisioner.NewTimeDuration(o.NotAfter),
|
||||||
|
}
|
||||||
|
|
||||||
templateOptions, err := provisioner.TemplateOptions(p.GetOptions(), data)
|
templateOptions, err := provisioner.TemplateOptions(p.GetOptions(), data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("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)
|
||||||
|
|
||||||
// // Create and store a new certificate.
|
certChain, err := a.signAuth.Sign(csr, opts, signOps...)
|
||||||
// certChain, err := auth.Sign(csr, provisioner.SignOptions{
|
|
||||||
// NotBefore: provisioner.NewTimeDuration(o.NotBefore),
|
|
||||||
// NotAfter: provisioner.NewTimeDuration(o.NotAfter),
|
|
||||||
// }, signOps...)
|
|
||||||
// if err != nil {
|
|
||||||
// return nil, ServerInternalErr(errors.Wrapf(err, "error generating certificate for order %s", o.ID))
|
|
||||||
// }
|
|
||||||
|
|
||||||
certs, err := a.signAuth.Sign(csr, opts, signOps...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("error generating certificate for order %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cert := certs[0]
|
cert := certChain[0]
|
||||||
|
|
||||||
// fmt.Println("CERT")
|
// fmt.Println("CERT")
|
||||||
// fmt.Println(cert)
|
// fmt.Println(cert)
|
||||||
|
@ -278,9 +279,6 @@ func (a *Authority) SignCSR(ctx context.Context, msg *PKIMessage, template *x509
|
||||||
// fmt.Println(cert.Issuer)
|
// fmt.Println(cert.Issuer)
|
||||||
// fmt.Println(cert.Subject)
|
// fmt.Println(cert.Subject)
|
||||||
|
|
||||||
serial := big.NewInt(int64(rand.Int63())) // TODO: serial logic?
|
|
||||||
cert.SerialNumber = serial
|
|
||||||
|
|
||||||
// create a degenerate cert structure
|
// create a degenerate cert structure
|
||||||
deg, err := DegenerateCertificates([]*x509.Certificate{cert})
|
deg, err := DegenerateCertificates([]*x509.Certificate{cert})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package scep
|
package scep
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/provisioner"
|
"github.com/smallstep/certificates/authority/provisioner"
|
||||||
|
@ -9,7 +10,7 @@ import (
|
||||||
// Provisioner is an interface that implements a subset of the provisioner.Interface --
|
// Provisioner is an interface that implements a subset of the provisioner.Interface --
|
||||||
// only those methods required by the SCEP api/authority.
|
// only those methods required by the SCEP api/authority.
|
||||||
type Provisioner interface {
|
type Provisioner interface {
|
||||||
// AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error)
|
AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error)
|
||||||
GetName() string
|
GetName() string
|
||||||
DefaultTLSCertDuration() time.Duration
|
DefaultTLSCertDuration() time.Duration
|
||||||
GetOptions() *provisioner.Options
|
GetOptions() *provisioner.Options
|
||||||
|
|
Loading…
Reference in a new issue