Skip to content

Commit

Permalink
Add rudimentary (and incomplete) support for SCEP
Browse files Browse the repository at this point in the history
  • Loading branch information
hslatman committed Feb 12, 2021
1 parent fc93d60 commit ffdd58e
Show file tree
Hide file tree
Showing 10 changed files with 668 additions and 3 deletions.
10 changes: 7 additions & 3 deletions authority/authority.go
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,13 @@ func (a *Authority) init() error {
audiences := a.config.getAudiences()
a.provisioners = provisioner.NewCollection(audiences)
config := provisioner.Config{
Claims: claimer.Claims(),
Audiences: audiences,
DB: a.db,
// TODO: this probably shouldn't happen like this; via SignAuth instead?
IntermediateCert: a.config.IntermediateCert,
SigningKey: a.config.IntermediateKey,
CACertificates: a.rootX509Certs,
Claims: claimer.Claims(),
Audiences: audiences,
DB: a.db,
SSHKeys: &provisioner.SSHKeys{
UserKeys: sshKeys.UserKeys,
HostKeys: sshKeys.HostKeys,
Expand Down
10 changes: 10 additions & 0 deletions authority/provisioner/provisioner.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ const (
TypeK8sSA Type = 8
// TypeSSHPOP is used to indicate the SSHPOP provisioners.
TypeSSHPOP Type = 9
// TypeSCEP is used to indicate the SCEP provisioners
TypeSCEP Type = 10
)

// String returns the string representation of the type.
Expand All @@ -164,6 +166,8 @@ func (t Type) String() string {
return "K8sSA"
case TypeSSHPOP:
return "SSHPOP"
case TypeSCEP:
return "SCEP"
default:
return ""
}
Expand All @@ -178,6 +182,10 @@ type SSHKeys struct {
// Config defines the default parameters used in the initialization of
// provisioners.
type Config struct {
// TODO: these probably shouldn't be here but passed via SignAuth
IntermediateCert string
SigningKey string
CACertificates []*x509.Certificate
// Claims are the default claims.
Claims Claims
// Audiences are the audiences used in the default provisioner, (JWK).
Expand Down Expand Up @@ -232,6 +240,8 @@ func (l *List) UnmarshalJSON(data []byte) error {
p = &K8sSA{}
case "sshpop":
p = &SSHPOP{}
case "scep":
p = &SCEP{}
default:
// Skip unsupported provisioners. A client using this method may be
// compiled with a version of smallstep/certificates that does not
Expand Down
116 changes: 116 additions & 0 deletions authority/provisioner/scep.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package provisioner

import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"fmt"
"io/ioutil"

"github.com/pkg/errors"
)

// SCEP is the SCEP provisioner type, an entity that can authorize the
// SCEP provisioning flow
type SCEP struct {
*base
Type string `json:"type"`
Name string `json:"name"`
// ForceCN bool `json:"forceCN,omitempty"`
// Claims *Claims `json:"claims,omitempty"`
// Options *Options `json:"options,omitempty"`
// claimer *Claimer

IntermediateCert string
SigningKey string
CACertificates []*x509.Certificate
}

// GetID returns the provisioner unique identifier.
func (s SCEP) GetID() string {
return "scep/" + s.Name
}

// GetName returns the name of the provisioner.
func (s *SCEP) GetName() string {
return s.Name
}

// GetType returns the type of provisioner.
func (s *SCEP) GetType() Type {
return TypeSCEP
}

// GetEncryptedKey returns the base provisioner encrypted key if it's defined.
func (s *SCEP) GetEncryptedKey() (string, string, bool) {
return "", "", false
}

// GetTokenID returns the identifier of the token.
func (s *SCEP) GetTokenID(ott string) (string, error) {
return "", errors.New("scep provisioner does not implement GetTokenID")
}

// GetCACertificates returns the CA certificate chain
// TODO: this should come from the authority instead?
func (s *SCEP) GetCACertificates() []*x509.Certificate {

pemtxt, _ := ioutil.ReadFile(s.IntermediateCert) // TODO: move reading key to init? That's probably safer.
block, _ := pem.Decode([]byte(pemtxt))
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
fmt.Println(err)
}

// TODO: return chain? I'm not sure if the client understands it correctly
return []*x509.Certificate{cert}
}

func (s *SCEP) GetSigningKey() *rsa.PrivateKey {

keyBytes, err := ioutil.ReadFile(s.SigningKey)
if err != nil {
return nil
}

block, _ := pem.Decode([]byte(keyBytes))
if block == nil {
return nil
}

key, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
fmt.Println(err)
return nil
}

return key
}

// Init initializes and validates the fields of a JWK type.
func (s *SCEP) Init(config Config) (err error) {

switch {
case s.Type == "":
return errors.New("provisioner type cannot be empty")
case s.Name == "":
return errors.New("provisioner name cannot be empty")
}

// // Update claims with global ones
// if p.claimer, err = NewClaimer(p.Claims, config.Claims); err != nil {
// return err
// }

s.IntermediateCert = config.IntermediateCert
s.SigningKey = config.SigningKey
s.CACertificates = config.CACertificates

return err
}

// Interface guards
var (
_ Interface = (*SCEP)(nil)
//_ scep.Provisioner = (*SCEP)(nil)
)
22 changes: 22 additions & 0 deletions ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/smallstep/certificates/db"
"github.com/smallstep/certificates/logging"
"github.com/smallstep/certificates/monitoring"
"github.com/smallstep/certificates/scep"
"github.com/smallstep/certificates/server"
"github.com/smallstep/nosql"
)
Expand Down Expand Up @@ -143,6 +144,27 @@ func (ca *CA) Init(config *authority.Config) (*CA, error) {
acmeRouterHandler.Route(r)
})

// TODO: THIS SHOULDN'T HAPPEN (or should become configurable)
// Current SCEP client I'm testing with doesn't seem to easily trust untrusted certs.
tlsConfig = nil

scepPrefix := "scep"
scepAuthority, err := scep.New(auth, scep.AuthorityOptions{
//Certificates: certificates,
//AuthConfig: *config.AuthorityConfig,
//Backdate: *config.AuthorityConfig.Backdate,
DB: auth.GetDatabase().(nosql.DB),
DNS: dns,
Prefix: scepPrefix,
})
if err != nil {
return nil, errors.Wrap(err, "error creating SCEP authority")
}
scepRouterHandler := scep.NewAPI(scepAuthority)
mux.Route("/"+scepPrefix, func(r chi.Router) {
scepRouterHandler.Route(r)
})

/*
// helpful routine for logging all routes //
walkFunc := func(method string, route string, handler http.Handler, middlewares ...func(http.Handler) http.Handler) error {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ require (
github.com/google/uuid v1.1.2
github.com/googleapis/gax-go/v2 v2.0.5
github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect
github.com/micromdm/scep v1.0.0
github.com/newrelic/go-agent v2.15.0+incompatible
github.com/pkg/errors v0.9.1
github.com/rs/xid v1.2.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/micromdm/scep v1.0.0 h1:ai//kcZnxZPq1YE/MatiE2bIRD94KOAwZRpN1fhVQXY=
github.com/micromdm/scep v1.0.0/go.mod h1:CID2SixSr5FvoauZdAFUSpQkn5MAuSy9oyURMGOJbag=
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
Expand Down

0 comments on commit ffdd58e

Please sign in to comment.