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
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
@ -13,7 +14,7 @@ type SCEP struct {
|
|||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
|
||||
// ForceCN bool `json:"forceCN,omitempty"`
|
||||
ForceCN bool `json:"forceCN,omitempty"`
|
||||
Options *Options `json:"options,omitempty"`
|
||||
Claims *Claims `json:"claims,omitempty"`
|
||||
claimer *Claimer
|
||||
|
@ -75,6 +76,21 @@ func (s *SCEP) Init(config Config) (err error) {
|
|||
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
|
||||
var (
|
||||
_ Interface = (*SCEP)(nil)
|
||||
|
|
|
@ -6,8 +6,6 @@ import (
|
|||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
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
|
||||
|
||||
GetCACertificates() ([]*x509.Certificate, error)
|
||||
//GetSigningKey() (*rsa.PrivateKey, error)
|
||||
|
||||
DecryptPKIEnvelope(ctx context.Context, msg *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:
|
||||
csr, err := x509.ParseCertificateRequest(msg.pkiEnvelope)
|
||||
if err != nil {
|
||||
return fmt.Errorf("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 fmt.Errorf("scep: parse challenge password in pkiEnvelope")
|
||||
return fmt.Errorf("scep: parse challenge password in pkiEnvelope: %w", err)
|
||||
}
|
||||
msg.CSRReqMessage = µscep.CSRReqMessage{
|
||||
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 (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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -245,32 +246,32 @@ func (a *Authority) SignCSR(ctx context.Context, msg *PKIMessage, template *x509
|
|||
data := x509util.NewTemplateData()
|
||||
data.SetCommonName(csr.Subject.CommonName)
|
||||
data.SetSANs(csr.DNSNames)
|
||||
data.SetCertificateRequest(csr)
|
||||
|
||||
// TODO: proper options
|
||||
opts := provisioner.SignOptions{}
|
||||
signOps := []provisioner.SignOption{}
|
||||
// Get authorizations from the SCEP provisioner.
|
||||
ctx = provisioner.NewContextWithMethod(ctx, provisioner.SignMethod)
|
||||
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)
|
||||
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)
|
||||
|
||||
// // Create and store a new certificate.
|
||||
// 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...)
|
||||
certChain, err := a.signAuth.Sign(csr, opts, signOps...)
|
||||
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)
|
||||
|
@ -278,9 +279,6 @@ func (a *Authority) SignCSR(ctx context.Context, msg *PKIMessage, template *x509
|
|||
// fmt.Println(cert.Issuer)
|
||||
// fmt.Println(cert.Subject)
|
||||
|
||||
serial := big.NewInt(int64(rand.Int63())) // TODO: serial logic?
|
||||
cert.SerialNumber = serial
|
||||
|
||||
// create a degenerate cert structure
|
||||
deg, err := DegenerateCertificates([]*x509.Certificate{cert})
|
||||
if err != nil {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package scep
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/smallstep/certificates/authority/provisioner"
|
||||
|
@ -9,7 +10,7 @@ import (
|
|||
// Provisioner is an interface that implements a subset of the provisioner.Interface --
|
||||
// only those methods required by the SCEP api/authority.
|
||||
type Provisioner interface {
|
||||
// AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error)
|
||||
AuthorizeSign(ctx context.Context, token string) ([]provisioner.SignOption, error)
|
||||
GetName() string
|
||||
DefaultTLSCertDuration() time.Duration
|
||||
GetOptions() *provisioner.Options
|
||||
|
|
Loading…
Reference in a new issue