forked from TrueCloudLab/certificates
Refactor SCEP provisioner and decrypter
This commit is contained in:
parent
0377fe559b
commit
180162bd6a
11 changed files with 234 additions and 250 deletions
|
@ -244,13 +244,16 @@ func (p ProvisionersResponse) MarshalJSON() ([]byte, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println(scepProv.KMS)
|
||||||
|
fmt.Println(fmt.Sprintf("%#+v", scepProv))
|
||||||
|
|
||||||
type old struct {
|
type old struct {
|
||||||
challengePassword string
|
challengePassword string
|
||||||
decrypterCertificate string
|
decrypterCertificate []byte
|
||||||
decrypterKey string
|
decrypterKey string
|
||||||
decrypterKeyPassword string
|
decrypterKeyPassword string
|
||||||
}
|
}
|
||||||
o := old{scepProv.ChallengePassword, scepProv.DecrypterCert, scepProv.DecrypterKey, scepProv.DecrypterKeyPassword}
|
o := old{scepProv.ChallengePassword, scepProv.DecrypterCertificate, scepProv.DecrypterKey, scepProv.DecrypterKeyPassword}
|
||||||
scepProv.ChallengePassword = "*** REDACTED ***"
|
scepProv.ChallengePassword = "*** REDACTED ***"
|
||||||
// TODO: remove the details in the API response
|
// TODO: remove the details in the API response
|
||||||
// scepProv.DecrypterCert = ""
|
// scepProv.DecrypterCert = ""
|
||||||
|
@ -259,7 +262,7 @@ func (p ProvisionersResponse) MarshalJSON() ([]byte, error) {
|
||||||
|
|
||||||
defer func(o old) { //nolint:gocritic // defer in loop required to restore initial state of provisioners
|
defer func(o old) { //nolint:gocritic // defer in loop required to restore initial state of provisioners
|
||||||
scepProv.ChallengePassword = o.challengePassword
|
scepProv.ChallengePassword = o.challengePassword
|
||||||
scepProv.DecrypterCert = o.decrypterCertificate
|
scepProv.DecrypterCertificate = o.decrypterCertificate
|
||||||
scepProv.DecrypterKey = o.decrypterKey
|
scepProv.DecrypterKey = o.decrypterKey
|
||||||
scepProv.DecrypterKeyPassword = o.decrypterKeyPassword
|
scepProv.DecrypterKeyPassword = o.decrypterKeyPassword
|
||||||
}(o)
|
}(o)
|
||||||
|
|
|
@ -641,56 +641,45 @@ func (a *Authority) init() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a KMS with decryption capability is required and available
|
// The SCEP functionality is provided through an instance of
|
||||||
if a.requiresDecrypter() {
|
// scep.Service. It is initialized once when the CA is started.
|
||||||
if _, ok := a.keyManager.(kmsapi.Decrypter); !ok {
|
// TODO: should the SCEP service support reloading? For example,
|
||||||
return errors.New("keymanager doesn't provide crypto.Decrypter")
|
// when the admin resources are reloaded, specifically the provisioners,
|
||||||
}
|
// it can happen that the SCEP service is no longer required and can
|
||||||
}
|
// be destroyed, or that it needs to be instantiated. It may also need
|
||||||
|
// to be revalidated, because not all SCEP provisioner may have a
|
||||||
// TODO: decide if this is a good approach for providing the SCEP functionality
|
// valid decrypter available.
|
||||||
// It currently mirrors the logic for the x509CAService
|
if a.requiresSCEP() && a.GetSCEP() == nil {
|
||||||
if a.requiresSCEPService() && a.scepService == nil {
|
|
||||||
var options scep.Options
|
var options scep.Options
|
||||||
|
options.Roots = a.rootX509Certs
|
||||||
// Read intermediate and create X509 signer and decrypter for default CAS.
|
options.Intermediates, err = pemutil.ReadCertificateBundle(a.config.IntermediateCert)
|
||||||
options.CertificateChain, err = pemutil.ReadCertificateBundle(a.config.IntermediateCert)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
options.CertificateChain = append(options.CertificateChain, a.rootX509Certs...)
|
options.SignerCert = options.Intermediates[0]
|
||||||
options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
|
if options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{
|
||||||
SigningKey: a.config.IntermediateKey,
|
SigningKey: a.config.IntermediateKey,
|
||||||
Password: a.password,
|
Password: a.password,
|
||||||
})
|
}); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
options.SignerCert = options.CertificateChain[0]
|
|
||||||
options.DecrypterCert = options.CertificateChain[0]
|
|
||||||
|
|
||||||
// TODO: instead of creating the decrypter here, pass the
|
// TODO: instead of creating the decrypter here, pass the
|
||||||
// intermediate key + chain down to the SCEP service / authority,
|
// intermediate key + chain down to the SCEP service / authority,
|
||||||
// and only instantiate it when required there.
|
// and only instantiate it when required there. Is that possible?
|
||||||
|
// Also with entering passwords?
|
||||||
// TODO: if moving the logic, try improving the logic for the
|
// TODO: if moving the logic, try improving the logic for the
|
||||||
// decrypter password too?
|
// decrypter password too? Right now it needs to be entered multiple
|
||||||
if km, ok := a.keyManager.(kmsapi.Decrypter); ok {
|
// times; I've observed it to be three times maximum, every time
|
||||||
options.Decrypter, err = km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{
|
// the intermediate key is read.
|
||||||
|
_, isRSA := options.Signer.Public().(*rsa.PublicKey)
|
||||||
|
if km, ok := a.keyManager.(kmsapi.Decrypter); ok && isRSA {
|
||||||
|
if decrypter, err := km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{
|
||||||
DecryptionKey: a.config.IntermediateKey,
|
DecryptionKey: a.config.IntermediateKey,
|
||||||
Password: a.password,
|
Password: a.password,
|
||||||
})
|
}); err == nil {
|
||||||
if err == nil {
|
// only pass the decrypter down when it was successfully created
|
||||||
// when creating the decrypter fails, ignore the error
|
options.Decrypter = decrypter
|
||||||
// TODO(hs): decide if this is OK. It could fail at startup, but it
|
|
||||||
// could be up later. Right now decryption would always fail.
|
|
||||||
key, ok := options.Decrypter.Public().(*rsa.PublicKey)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("only RSA keys are currently supported as decrypters")
|
|
||||||
}
|
|
||||||
if !key.Equal(options.DecrypterCert.PublicKey) {
|
|
||||||
return errors.New("mismatch between decryption certificate and decrypter public keys")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -698,8 +687,6 @@ func (a *Authority) init() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: mimick the x509CAService GetCertificateAuthority here too?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load X509 constraints engine.
|
// Load X509 constraints engine.
|
||||||
|
@ -851,17 +838,9 @@ func (a *Authority) IsRevoked(sn string) (bool, error) {
|
||||||
return a.db.IsRevoked(sn)
|
return a.db.IsRevoked(sn)
|
||||||
}
|
}
|
||||||
|
|
||||||
// requiresDecrypter returns whether the Authority
|
|
||||||
// requires a KMS that provides a crypto.Decrypter
|
|
||||||
// Currently this is only required when SCEP is
|
|
||||||
// enabled.
|
|
||||||
func (a *Authority) requiresDecrypter() bool {
|
|
||||||
return a.requiresSCEPService()
|
|
||||||
}
|
|
||||||
|
|
||||||
// requiresSCEPService iterates over the configured provisioners
|
// requiresSCEPService iterates over the configured provisioners
|
||||||
// and determines if one of them is a SCEP provisioner.
|
// and determines if one of them is a SCEP provisioner.
|
||||||
func (a *Authority) requiresSCEPService() bool {
|
func (a *Authority) requiresSCEP() bool {
|
||||||
for _, p := range a.config.AuthorityConfig.Provisioners {
|
for _, p := range a.config.AuthorityConfig.Provisioners {
|
||||||
if p.GetType() == provisioner.TypeSCEP {
|
if p.GetType() == provisioner.TypeSCEP {
|
||||||
return true
|
return true
|
||||||
|
@ -870,12 +849,8 @@ func (a *Authority) requiresSCEPService() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSCEPService returns the configured SCEP Service.
|
// GetSCEP returns the configured SCEP Service.
|
||||||
//
|
func (a *Authority) GetSCEP() *scep.Service {
|
||||||
// TODO: this function is intended to exist temporarily in order to make SCEP
|
|
||||||
// work more easily. It can be made more correct by using the right
|
|
||||||
// interfaces/abstractions after it works as expected.
|
|
||||||
func (a *Authority) GetSCEPService() *scep.Service {
|
|
||||||
return a.scepService
|
return a.scepService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -478,7 +478,7 @@ func testScepAuthority(t *testing.T, opts ...Option) *Authority {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthority_GetSCEPService(t *testing.T) {
|
func TestAuthority_GetSCEP(t *testing.T) {
|
||||||
_ = testScepAuthority(t)
|
_ = testScepAuthority(t)
|
||||||
p := provisioner.List{
|
p := provisioner.List{
|
||||||
&provisioner.SCEP{
|
&provisioner.SCEP{
|
||||||
|
@ -542,7 +542,7 @@ func TestAuthority_GetSCEPService(t *testing.T) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if tt.wantService {
|
if tt.wantService {
|
||||||
if got := a.GetSCEPService(); (got != nil) != tt.wantService {
|
if got := a.GetSCEP(); (got != nil) != tt.wantService {
|
||||||
t.Errorf("Authority.GetSCEPService() = %v, wantService %v", got, tt.wantService)
|
t.Errorf("Authority.GetSCEPService() = %v, wantService %v", got, tt.wantService)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
@ -14,7 +15,6 @@ import (
|
||||||
|
|
||||||
"go.step.sm/crypto/kms"
|
"go.step.sm/crypto/kms"
|
||||||
kmsapi "go.step.sm/crypto/kms/apiv1"
|
kmsapi "go.step.sm/crypto/kms/apiv1"
|
||||||
"go.step.sm/crypto/pemutil"
|
|
||||||
"go.step.sm/linkedca"
|
"go.step.sm/linkedca"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/webhook"
|
"github.com/smallstep/certificates/webhook"
|
||||||
|
@ -40,7 +40,7 @@ type SCEP struct {
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
KMS *kms.Options `json:"kms,omitempty"`
|
KMS *kms.Options `json:"kms,omitempty"`
|
||||||
DecrypterCert string `json:"decrypterCert"`
|
DecrypterCertificate []byte `json:"decrypterCertificate"`
|
||||||
DecrypterKey string `json:"decrypterKey"`
|
DecrypterKey string `json:"decrypterKey"`
|
||||||
DecrypterKeyPassword string `json:"decrypterKeyPassword"`
|
DecrypterKeyPassword string `json:"decrypterKeyPassword"`
|
||||||
|
|
||||||
|
@ -198,18 +198,32 @@ func (s *SCEP) Init(config Config) (err error) {
|
||||||
}
|
}
|
||||||
km, ok := s.keyManager.(kmsapi.Decrypter)
|
km, ok := s.keyManager.(kmsapi.Decrypter)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf(`%q is not a kmsapi.Decrypter`, s.KMS.Type)
|
return fmt.Errorf("%q is not a kmsapi.Decrypter", s.KMS.Type)
|
||||||
}
|
}
|
||||||
if s.DecrypterKey != "" || s.DecrypterCert != "" {
|
if s.DecrypterKey != "" || len(s.DecrypterCertificate) > 0 {
|
||||||
if s.decrypter, err = km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{
|
if s.decrypter, err = km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{
|
||||||
DecryptionKey: s.DecrypterKey,
|
DecryptionKey: s.DecrypterKey,
|
||||||
Password: []byte(s.DecrypterKeyPassword),
|
Password: []byte(s.DecrypterKeyPassword),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("failed creating decrypter: %w", err)
|
return fmt.Errorf("failed creating decrypter: %w", err)
|
||||||
}
|
}
|
||||||
if s.decrypterCertificate, err = pemutil.ReadCertificate(s.DecrypterCert); err != nil {
|
|
||||||
return fmt.Errorf("failed reading certificate: %w", err)
|
// Parse decrypter certificate
|
||||||
|
block, rest := pem.Decode(s.DecrypterCertificate)
|
||||||
|
if len(rest) > 0 {
|
||||||
|
fmt.Println(string(rest))
|
||||||
|
return errors.New("failed parsing decrypter certificate: trailing data")
|
||||||
}
|
}
|
||||||
|
if block == nil {
|
||||||
|
return errors.New("failed parsing decrypter certificate: no PEM block found")
|
||||||
|
}
|
||||||
|
if s.decrypterCertificate, err = x509.ParseCertificate(block.Bytes); err != nil {
|
||||||
|
return fmt.Errorf("failed parsing decrypter certificate: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if s.decrypterCertificate, err = pemutil.ReadCertificate(s.DecrypterCertFile); err != nil {
|
||||||
|
// return fmt.Errorf("failed reading certificate: %w", err)
|
||||||
|
// }
|
||||||
decrypterPublicKey, ok := s.decrypter.Public().(*rsa.PublicKey)
|
decrypterPublicKey, ok := s.decrypter.Public().(*rsa.PublicKey)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("only RSA keys are supported")
|
return fmt.Errorf("only RSA keys are supported")
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gopkg.in/square/go-jose.v2/jwt"
|
"gopkg.in/square/go-jose.v2/jwt"
|
||||||
|
@ -15,6 +16,7 @@ import (
|
||||||
"go.step.sm/cli-utils/step"
|
"go.step.sm/cli-utils/step"
|
||||||
"go.step.sm/cli-utils/ui"
|
"go.step.sm/cli-utils/ui"
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
|
"go.step.sm/crypto/kms"
|
||||||
"go.step.sm/linkedca"
|
"go.step.sm/linkedca"
|
||||||
|
|
||||||
"github.com/smallstep/certificates/authority/admin"
|
"github.com/smallstep/certificates/authority/admin"
|
||||||
|
@ -235,7 +237,7 @@ func (a *Authority) StoreProvisioner(ctx context.Context, prov *linkedca.Provisi
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := certProv.Init(provisionerConfig); err != nil {
|
if err := certProv.Init(provisionerConfig); err != nil {
|
||||||
return admin.WrapError(admin.ErrorBadRequestType, err, "error validating configuration for provisioner %s", prov.Name)
|
return admin.WrapError(admin.ErrorBadRequestType, err, "error validating configuration for provisioner %q", prov.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store to database -- this will set the ID.
|
// Store to database -- this will set the ID.
|
||||||
|
@ -960,7 +962,7 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface,
|
||||||
}, nil
|
}, nil
|
||||||
case *linkedca.ProvisionerDetails_SCEP:
|
case *linkedca.ProvisionerDetails_SCEP:
|
||||||
cfg := d.SCEP
|
cfg := d.SCEP
|
||||||
return &provisioner.SCEP{
|
s := &provisioner.SCEP{
|
||||||
ID: p.Id,
|
ID: p.Id,
|
||||||
Type: p.Type.String(),
|
Type: p.Type.String(),
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
|
@ -972,7 +974,19 @@ func ProvisionerToCertificates(p *linkedca.Provisioner) (provisioner.Interface,
|
||||||
EncryptionAlgorithmIdentifier: int(cfg.EncryptionAlgorithmIdentifier),
|
EncryptionAlgorithmIdentifier: int(cfg.EncryptionAlgorithmIdentifier),
|
||||||
Claims: claims,
|
Claims: claims,
|
||||||
Options: options,
|
Options: options,
|
||||||
}, nil
|
}
|
||||||
|
if decrypter := cfg.GetDecrypter(); decrypter != nil {
|
||||||
|
if dkms := decrypter.GetKms(); dkms != nil {
|
||||||
|
s.KMS = &kms.Options{
|
||||||
|
Type: kms.Type(strings.ToLower(linkedca.KMS_Type_name[int32(dkms.Type)])),
|
||||||
|
CredentialsFile: dkms.CredentialsFile,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s.DecrypterCertificate = decrypter.DecrypterCertificate
|
||||||
|
s.DecrypterKey = decrypter.DecrypterKey
|
||||||
|
s.DecrypterKeyPassword = decrypter.DecrypterKeyPassword
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
case *linkedca.ProvisionerDetails_Nebula:
|
case *linkedca.ProvisionerDetails_Nebula:
|
||||||
var roots []byte
|
var roots []byte
|
||||||
for i, root := range d.Nebula.GetRoots() {
|
for i, root := range d.Nebula.GetRoots() {
|
||||||
|
|
27
ca/ca.go
27
ca/ca.go
|
@ -250,19 +250,24 @@ func (ca *CA) Init(cfg *config.Config) (*CA, error) {
|
||||||
|
|
||||||
var scepAuthority *scep.Authority
|
var scepAuthority *scep.Authority
|
||||||
if ca.shouldServeSCEPEndpoints() {
|
if ca.shouldServeSCEPEndpoints() {
|
||||||
scepPrefix := "scep"
|
if scepAuthority, err = scep.New(auth, scep.AuthorityOptions{
|
||||||
scepAuthority, err = scep.New(auth, scep.AuthorityOptions{
|
Service: auth.GetSCEP(),
|
||||||
Service: auth.GetSCEPService(),
|
}); err != nil {
|
||||||
DNS: dns,
|
return nil, errors.Wrap(err, "failed creating SCEP authority")
|
||||||
Prefix: scepPrefix,
|
}
|
||||||
})
|
|
||||||
if err != nil {
|
// TODO: validate that the scepAuthority is fully valid? E.g. initialization
|
||||||
return nil, errors.Wrap(err, "error creating SCEP authority")
|
// may have configured the default decrypter, but if that's not set or if it's
|
||||||
|
// somehow not usable, all SCEP provisioners should have a valid decrypter
|
||||||
|
// configured by now.
|
||||||
|
if err := scepAuthority.Validate(); err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed validating SCEP authority")
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the RFC (https://tools.ietf.org/html/rfc8894#section-7.10),
|
// According to the RFC (https://tools.ietf.org/html/rfc8894#section-7.10),
|
||||||
// SCEP operations are performed using HTTP, so that's why the API is mounted
|
// SCEP operations are performed using HTTP, so that's why the API is mounted
|
||||||
// to the insecure mux.
|
// to the insecure mux.
|
||||||
|
scepPrefix := "scep"
|
||||||
insecureMux.Route("/"+scepPrefix, func(r chi.Router) {
|
insecureMux.Route("/"+scepPrefix, func(r chi.Router) {
|
||||||
scepAPI.Route(r)
|
scepAPI.Route(r)
|
||||||
})
|
})
|
||||||
|
@ -584,10 +589,10 @@ func (ca *CA) getTLSConfig(auth *authority.Authority) (*tls.Config, *tls.Config,
|
||||||
|
|
||||||
// shouldServeSCEPEndpoints returns if the CA should be
|
// shouldServeSCEPEndpoints returns if the CA should be
|
||||||
// configured with endpoints for SCEP. This is assumed to be
|
// configured with endpoints for SCEP. This is assumed to be
|
||||||
// true if a SCEPService exists, which is true in case a
|
// true if a SCEPService exists, which is true in case at
|
||||||
// SCEP provisioner was configured.
|
// least one SCEP provisioner was configured.
|
||||||
func (ca *CA) shouldServeSCEPEndpoints() bool {
|
func (ca *CA) shouldServeSCEPEndpoints() bool {
|
||||||
return ca.auth.GetSCEPService() != nil
|
return ca.auth.GetSCEP() != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:unused // useful for debugging
|
//nolint:unused // useful for debugging
|
||||||
|
|
20
go.mod
20
go.mod
|
@ -12,7 +12,7 @@ require (
|
||||||
github.com/google/go-cmp v0.5.9
|
github.com/google/go-cmp v0.5.9
|
||||||
github.com/google/go-tpm v0.3.3
|
github.com/google/go-tpm v0.3.3
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/googleapis/gax-go/v2 v2.8.0
|
github.com/googleapis/gax-go/v2 v2.9.0
|
||||||
github.com/hashicorp/vault/api v1.9.1
|
github.com/hashicorp/vault/api v1.9.1
|
||||||
github.com/hashicorp/vault/api/auth/approle v0.4.0
|
github.com/hashicorp/vault/api/auth/approle v0.4.0
|
||||||
github.com/hashicorp/vault/api/auth/kubernetes v0.4.0
|
github.com/hashicorp/vault/api/auth/kubernetes v0.4.0
|
||||||
|
@ -25,16 +25,16 @@ require (
|
||||||
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262
|
github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262
|
||||||
github.com/smallstep/go-attestation v0.4.4-0.20230509120429-e17291421738
|
github.com/smallstep/go-attestation v0.4.4-0.20230509120429-e17291421738
|
||||||
github.com/smallstep/nosql v0.6.0
|
github.com/smallstep/nosql v0.6.0
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.3
|
||||||
github.com/urfave/cli v1.22.13
|
github.com/urfave/cli v1.22.13
|
||||||
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352
|
||||||
go.step.sm/cli-utils v0.7.6
|
go.step.sm/cli-utils v0.7.6
|
||||||
go.step.sm/crypto v0.30.0
|
go.step.sm/crypto v0.31.0
|
||||||
go.step.sm/linkedca v0.19.1
|
go.step.sm/linkedca v0.19.1
|
||||||
golang.org/x/crypto v0.8.0
|
golang.org/x/crypto v0.9.0
|
||||||
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
|
golang.org/x/exp v0.0.0-20230310171629-522b1b587ee0
|
||||||
golang.org/x/net v0.9.0
|
golang.org/x/net v0.10.0
|
||||||
google.golang.org/api v0.121.0
|
google.golang.org/api v0.123.0
|
||||||
google.golang.org/grpc v1.55.0
|
google.golang.org/grpc v1.55.0
|
||||||
google.golang.org/protobuf v1.30.0
|
google.golang.org/protobuf v1.30.0
|
||||||
gopkg.in/square/go-jose.v2 v2.6.0
|
gopkg.in/square/go-jose.v2 v2.6.0
|
||||||
|
@ -57,7 +57,7 @@ require (
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||||
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
github.com/ThalesIgnite/crypto11 v1.2.5 // indirect
|
||||||
github.com/aws/aws-sdk-go v1.44.259 // indirect
|
github.com/aws/aws-sdk-go v1.44.267 // indirect
|
||||||
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
|
github.com/cenkalti/backoff/v3 v3.0.0 // indirect
|
||||||
github.com/cespare/xxhash v1.1.0 // indirect
|
github.com/cespare/xxhash v1.1.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
@ -80,7 +80,7 @@ require (
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
github.com/google/btree v1.1.2 // indirect
|
github.com/google/btree v1.1.2 // indirect
|
||||||
github.com/google/certificate-transparency-go v1.1.4 // indirect
|
github.com/google/certificate-transparency-go v1.1.4 // indirect
|
||||||
github.com/google/go-tpm-tools v0.3.11 // indirect
|
github.com/google/go-tpm-tools v0.3.12 // indirect
|
||||||
github.com/google/go-tspi v0.3.0 // indirect
|
github.com/google/go-tspi v0.3.0 // indirect
|
||||||
github.com/google/s2a-go v0.1.3 // indirect
|
github.com/google/s2a-go v0.1.3 // indirect
|
||||||
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
github.com/googleapis/enterprise-certificate-proxy v0.2.3 // indirect
|
||||||
|
@ -129,7 +129,7 @@ require (
|
||||||
go.etcd.io/bbolt v1.3.7 // indirect
|
go.etcd.io/bbolt v1.3.7 // indirect
|
||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
golang.org/x/oauth2 v0.7.0 // indirect
|
golang.org/x/oauth2 v0.7.0 // indirect
|
||||||
golang.org/x/sys v0.7.0 // indirect
|
golang.org/x/sys v0.8.0 // indirect
|
||||||
golang.org/x/text v0.9.0 // indirect
|
golang.org/x/text v0.9.0 // indirect
|
||||||
golang.org/x/time v0.1.0 // indirect
|
golang.org/x/time v0.1.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
|
@ -145,3 +145,5 @@ require (
|
||||||
|
|
||||||
// use github.com/smallstep/pkcs7 fork with patches applied
|
// use github.com/smallstep/pkcs7 fork with patches applied
|
||||||
replace go.mozilla.org/pkcs7 => github.com/smallstep/pkcs7 v0.0.0-20230302202335-4c094085c948
|
replace go.mozilla.org/pkcs7 => github.com/smallstep/pkcs7 v0.0.0-20230302202335-4c094085c948
|
||||||
|
|
||||||
|
replace go.step.sm/linkedca => ./../linkedca
|
||||||
|
|
39
go.sum
39
go.sum
|
@ -165,8 +165,8 @@ github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi
|
||||||
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.25.37/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
|
||||||
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
github.com/aws/aws-sdk-go v1.44.259 h1:7yDn1dcv4DZFMKpu+2exIH5O6ipNj9qXrKfdMUaIJwY=
|
github.com/aws/aws-sdk-go v1.44.267 h1:Asrp6EMqqRxZvjK0NjzkWcrOk15RnWtupuUrUuZMabk=
|
||||||
github.com/aws/aws-sdk-go v1.44.259/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
github.com/aws/aws-sdk-go v1.44.267/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||||
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
|
||||||
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
|
||||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||||
|
@ -430,7 +430,7 @@ github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOm
|
||||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||||
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE=
|
||||||
github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
|
github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no=
|
||||||
github.com/google/go-sev-guest v0.5.2 h1:dlCehnxU9aJWEIcTb0j7oZ/yM4qeno7AO6zWokb4mu0=
|
github.com/google/go-sev-guest v0.6.1 h1:NajHkAaLqN9/aW7bCFSUplUMtDgk2+HcN7jC2btFtk0=
|
||||||
github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI=
|
github.com/google/go-tpm v0.1.2-0.20190725015402-ae6dd98980d4/go.mod h1:H9HbmUG2YgV/PHITkO7p6wxEEj/v5nlsVWIwumwH2NI=
|
||||||
github.com/google/go-tpm v0.3.0/go.mod h1:iVLWvrPp/bHeEkxTFi9WG6K9w0iy2yIszHwZGHPbzAw=
|
github.com/google/go-tpm v0.3.0/go.mod h1:iVLWvrPp/bHeEkxTFi9WG6K9w0iy2yIszHwZGHPbzAw=
|
||||||
github.com/google/go-tpm v0.3.2/go.mod h1:j71sMBTfp3X5jPHz852ZOfQMUOf65Gb/Th8pRmp7fvg=
|
github.com/google/go-tpm v0.3.2/go.mod h1:j71sMBTfp3X5jPHz852ZOfQMUOf65Gb/Th8pRmp7fvg=
|
||||||
|
@ -441,8 +441,8 @@ github.com/google/go-tpm-tools v0.2.0/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N
|
||||||
github.com/google/go-tpm-tools v0.2.1/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4=
|
github.com/google/go-tpm-tools v0.2.1/go.mod h1:npUd03rQ60lxN7tzeBJreG38RvWwme2N1reF/eeiBk4=
|
||||||
github.com/google/go-tpm-tools v0.3.1/go.mod h1:PSg+r5hSZI5tP3X7LBQx2sW1VSZUqZHBSrKyDqrB21U=
|
github.com/google/go-tpm-tools v0.3.1/go.mod h1:PSg+r5hSZI5tP3X7LBQx2sW1VSZUqZHBSrKyDqrB21U=
|
||||||
github.com/google/go-tpm-tools v0.3.9/go.mod h1:22JvWmHcD5w55cs+nMeqDGDxgNS15/2pDq2cLqnc3rc=
|
github.com/google/go-tpm-tools v0.3.9/go.mod h1:22JvWmHcD5w55cs+nMeqDGDxgNS15/2pDq2cLqnc3rc=
|
||||||
github.com/google/go-tpm-tools v0.3.11 h1:imObhmECgDS+ua4aAVPkMfCzE9LTZjS/MmVMCrAG4VY=
|
github.com/google/go-tpm-tools v0.3.12 h1:hpWglH4RaZnGVbgOK3IThI5K++jnFvjQ94EIN34xrUU=
|
||||||
github.com/google/go-tpm-tools v0.3.11/go.mod h1:5UcOsOyG5B2hWhKsqNI3TtOjTcZs5sh+3913uMN29Y8=
|
github.com/google/go-tpm-tools v0.3.12/go.mod h1:2OtmyPGPuaWWIOjr+IDhNQb6t5njjbSmZtzc350Q6Ro=
|
||||||
github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
github.com/google/go-tspi v0.2.1-0.20190423175329-115dea689aad/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
||||||
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
|
github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus=
|
||||||
github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI=
|
||||||
|
@ -491,8 +491,8 @@ github.com/googleapis/enterprise-certificate-proxy v0.2.3/go.mod h1:AwSRAtLfXpU5
|
||||||
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK67vJZc=
|
github.com/googleapis/gax-go/v2 v2.9.0 h1:ie5/2yPjucjZW6fEGjLhS5+PhEg6owWMrFB5d7TFFhw=
|
||||||
github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI=
|
github.com/googleapis/gax-go/v2 v2.9.0/go.mod h1:qf/E3rjAvrwLsAnQW+IClIu+z03yUf4KOoO82NfZ+QY=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
|
||||||
github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ=
|
github.com/goreleaser/goreleaser v0.134.0/go.mod h1:ZT6Y2rSYa6NxQzIsdfWWNWAlYGXGbreo66NmE+3X3WQ=
|
||||||
|
@ -968,8 +968,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||||
|
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
|
github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
|
||||||
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
|
github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU=
|
||||||
|
@ -1062,8 +1063,8 @@ go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16g
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.step.sm/cli-utils v0.7.6 h1:YkpLVrepmy2c5+eaz/wduiGxlgrRx3YdAStE37if25g=
|
go.step.sm/cli-utils v0.7.6 h1:YkpLVrepmy2c5+eaz/wduiGxlgrRx3YdAStE37if25g=
|
||||||
go.step.sm/cli-utils v0.7.6/go.mod h1:j+FxFZ2gbWkAJl0eded/rksuxmNqWpmyxbkXcukGJaY=
|
go.step.sm/cli-utils v0.7.6/go.mod h1:j+FxFZ2gbWkAJl0eded/rksuxmNqWpmyxbkXcukGJaY=
|
||||||
go.step.sm/crypto v0.30.0 h1:EzqPTvW1g6kxEnfIf/exDW+MhHGeEhtoNMhQX7P/UwI=
|
go.step.sm/crypto v0.31.0 h1:8ZG/BxC+0+LzPpk/764h5yubpG3GfxcRVR4E+Aye72g=
|
||||||
go.step.sm/crypto v0.30.0/go.mod h1:6jFFgUoafyHvb6rNq3NJrBByof4SCzj1n8ThyXuMVAM=
|
go.step.sm/crypto v0.31.0/go.mod h1:Dv4lpkijKiZVkoc6zp+Xaw1xmy+voia1mykvbpQIvuc=
|
||||||
go.step.sm/linkedca v0.19.1 h1:uY0ByT/uB3FCQ8zIo9mU7MWG7HKf5sDXNEBeN94MuP8=
|
go.step.sm/linkedca v0.19.1 h1:uY0ByT/uB3FCQ8zIo9mU7MWG7HKf5sDXNEBeN94MuP8=
|
||||||
go.step.sm/linkedca v0.19.1/go.mod h1:vPV2ad3LFQJmV7XWt87VlnJSs6UOqgsbVGVWe3veEmI=
|
go.step.sm/linkedca v0.19.1/go.mod h1:vPV2ad3LFQJmV7XWt87VlnJSs6UOqgsbVGVWe3veEmI=
|
||||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
|
@ -1111,8 +1112,8 @@ golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0
|
||||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||||
golang.org/x/crypto v0.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ=
|
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
|
||||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -1211,8 +1212,8 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
|
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -1340,8 +1341,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
||||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
@ -1349,7 +1350,7 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
|
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -1490,8 +1491,8 @@ google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtuk
|
||||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||||
google.golang.org/api v0.121.0 h1:8Oopoo8Vavxx6gt+sgs8s8/X60WBAtKQq6JqnkF+xow=
|
google.golang.org/api v0.123.0 h1:yHVU//vA+qkOhm4reEC9LtzHVUCN/IqqNRl1iQ9xE20=
|
||||||
google.golang.org/api v0.121.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
|
google.golang.org/api v0.123.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
|
|
||||||
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"
|
||||||
|
@ -19,9 +18,7 @@ import (
|
||||||
|
|
||||||
// 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
|
service *Service // TODO: refactor, so that this is not required
|
||||||
dns string
|
|
||||||
service *Service
|
|
||||||
signAuth SignAuthority
|
signAuth SignAuthority
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,15 +47,9 @@ func MustFromContext(ctx context.Context) *Authority {
|
||||||
|
|
||||||
// AuthorityOptions required to create a new SCEP Authority.
|
// AuthorityOptions required to create a new SCEP Authority.
|
||||||
type AuthorityOptions struct {
|
type AuthorityOptions struct {
|
||||||
// Service provides the certificate chain, the signer and the decrypter to the Authority
|
// Service provides the roots, intermediates, the signer and the (default)
|
||||||
|
// decrypter to the SCEP Authority.
|
||||||
Service *Service
|
Service *Service
|
||||||
// DNS is the host used to generate accurate SCEP links. By default the authority
|
|
||||||
// will use the Host from the request, so this value will only be used if
|
|
||||||
// request.Host is empty.
|
|
||||||
DNS string
|
|
||||||
// Prefix is a URL path prefix under which the SCEP api is served. This
|
|
||||||
// prefix is required to generate accurate SCEP links.
|
|
||||||
Prefix string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignAuthority is the interface for a signing authority
|
// SignAuthority is the interface for a signing authority
|
||||||
|
@ -70,14 +61,35 @@ type SignAuthority interface {
|
||||||
// New returns a new Authority that implements the SCEP interface.
|
// New returns a new Authority that implements the SCEP interface.
|
||||||
func New(signAuth SignAuthority, ops AuthorityOptions) (*Authority, error) {
|
func New(signAuth SignAuthority, ops AuthorityOptions) (*Authority, error) {
|
||||||
authority := &Authority{
|
authority := &Authority{
|
||||||
prefix: ops.Prefix,
|
|
||||||
dns: ops.DNS,
|
|
||||||
signAuth: signAuth,
|
signAuth: signAuth,
|
||||||
service: ops.Service,
|
service: ops.Service,
|
||||||
}
|
}
|
||||||
return authority, nil
|
return authority, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *Authority) Validate() error {
|
||||||
|
// if a default decrypter is set, the Authority is able
|
||||||
|
// to decrypt SCEP requests. No need to verify the provisioners.
|
||||||
|
if a.service.defaultDecrypter != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range []string{"scepca"} { // TODO: correct names; provided through options
|
||||||
|
p, err := a.LoadProvisionerByName(name)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("prov load fail: %w", err)
|
||||||
|
}
|
||||||
|
if scepProv, ok := p.(*provisioner.SCEP); ok {
|
||||||
|
if cert, decrypter := scepProv.GetDecrypter(); cert == nil || decrypter == nil {
|
||||||
|
fmt.Println(fmt.Sprintf("SCEP provisioner %q doesn't have valid decrypter", scepProv.GetName()))
|
||||||
|
// TODO: return error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// TODO: check the default capabilities; https://tools.ietf.org/html/rfc8894#section-3.5.2
|
// TODO: check the default capabilities; https://tools.ietf.org/html/rfc8894#section-3.5.2
|
||||||
defaultCapabilities = []string{
|
defaultCapabilities = []string{
|
||||||
|
@ -97,79 +109,38 @@ func (a *Authority) LoadProvisionerByName(name string) (provisioner.Interface, e
|
||||||
return a.signAuth.LoadProvisionerByName(name)
|
return a.signAuth.LoadProvisionerByName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLinkExplicit returns the requested link from the directory.
|
// GetCACertificates returns the certificate (chain) for the CA.
|
||||||
func (a *Authority) GetLinkExplicit(provName string, abs bool, baseURL *url.URL, inputs ...string) string {
|
//
|
||||||
return a.getLinkExplicit(provName, abs, baseURL, inputs...)
|
// This methods returns the "SCEP Server (RA)" certificate, the issuing CA up to and excl. the root.
|
||||||
}
|
// Some clients do need the root certificate however; also see: https://github.com/openxpki/openxpki/issues/73
|
||||||
|
//
|
||||||
// getLinkExplicit returns an absolute or partial path to the given resource and a base
|
// In case a provisioner specific decrypter is available, this is used as the "SCEP Server (RA)" certificate
|
||||||
// URL dynamically obtained from the request for which the link is being calculated.
|
// instead of the CA intermediate directly. This uses a distinct instance of a KMS for doing the SCEp key
|
||||||
func (a *Authority) getLinkExplicit(provisionerName string, abs bool, baseURL *url.URL, _ ...string) string {
|
// operations, so that RSA can be used for just SCEP.
|
||||||
link := "/" + provisionerName
|
//
|
||||||
if abs {
|
// Using an RA does not seem to exist in https://tools.ietf.org/html/rfc8894, but is mentioned in
|
||||||
// Copy the baseURL value from the pointer. https://github.com/golang/go/issues/38351
|
// https://tools.ietf.org/id/draft-nourse-scep-21.html.
|
||||||
u := url.URL{}
|
func (a *Authority) GetCACertificates(ctx context.Context) (certs []*x509.Certificate, err error) {
|
||||||
if baseURL != nil {
|
|
||||||
u = *baseURL
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no Scheme is set, then default to http (in case of SCEP)
|
|
||||||
if u.Scheme == "" {
|
|
||||||
u.Scheme = "http"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(ctx context.Context) ([]*x509.Certificate, error) {
|
|
||||||
// TODO: this should return: the "SCEP Server (RA)" certificate, the issuing CA up to and excl. the root
|
|
||||||
// Some clients do need the root certificate however; also see: https://github.com/openxpki/openxpki/issues/73
|
|
||||||
//
|
|
||||||
// This means we might need to think about if we should use the current intermediate CA
|
|
||||||
// certificate as the "SCEP Server (RA)" certificate. It might be better to have a distinct
|
|
||||||
// RA certificate, with a corresponding rsa.PrivateKey, just for SCEP usage, which is signed by
|
|
||||||
// the intermediate CA. Will need to look how we can provide this nicely within step-ca.
|
|
||||||
//
|
|
||||||
// This might also mean that we might want to use a distinct instance of KMS for doing the key operations,
|
|
||||||
// so that we can use RSA just for SCEP.
|
|
||||||
//
|
|
||||||
// Using an RA does not seem to exist in https://tools.ietf.org/html/rfc8894, but is mentioned in
|
|
||||||
// https://tools.ietf.org/id/draft-nourse-scep-21.html. Will continue using the CA directly for now.
|
|
||||||
//
|
|
||||||
// The certificate to use should probably depend on the (configured) provisioner and may
|
|
||||||
// use a distinct certificate, apart from the intermediate.
|
|
||||||
|
|
||||||
p, err := provisionerFromContext(ctx)
|
p, err := provisionerFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(a.service.certificateChain) == 0 {
|
// if a provisioner specific RSA decrypter is available, it is returned as
|
||||||
return nil, errors.New("no intermediate certificate available in SCEP authority")
|
// the first certificate.
|
||||||
}
|
|
||||||
|
|
||||||
certs := []*x509.Certificate{}
|
|
||||||
if decrypterCertificate, _ := p.GetDecrypter(); decrypterCertificate != nil {
|
if decrypterCertificate, _ := p.GetDecrypter(); decrypterCertificate != nil {
|
||||||
certs = append(certs, decrypterCertificate)
|
certs = append(certs, decrypterCertificate)
|
||||||
certs = append(certs, a.service.signerCertificate)
|
|
||||||
} else {
|
|
||||||
certs = append(certs, a.service.defaultDecrypterCertificate)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: we're adding the CA roots here, but they are (highly likely) different than what the RFC means.
|
// TODO: ensure logic, so that signer is first intermediate and that
|
||||||
// Clients are responsible to select the right cert(s) to use, though.
|
// there are no doubles certificates.
|
||||||
if p.ShouldIncludeRootInChain() && len(a.service.certificateChain) > 1 {
|
//certs = append(certs, a.service.signerCertificate)
|
||||||
certs = append(certs, a.service.certificateChain[1])
|
certs = append(certs, a.service.intermediates...)
|
||||||
|
|
||||||
|
// the CA roots are added for completeness. Clients are responsible
|
||||||
|
// to select the right cert(s) to store and use.
|
||||||
|
if p.ShouldIncludeRootInChain() {
|
||||||
|
certs = append(certs, a.service.roots...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return certs, nil
|
return certs, nil
|
||||||
|
@ -182,7 +153,7 @@ func (a *Authority) DecryptPKIEnvelope(ctx context.Context, msg *PKIMessage) err
|
||||||
return fmt.Errorf("error parsing pkcs7 content: %w", err)
|
return fmt.Errorf("error parsing pkcs7 content: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(fmt.Sprintf("%#+v", a.service.defaultDecrypterCertificate))
|
fmt.Println(fmt.Sprintf("%#+v", a.service.signerCertificate))
|
||||||
fmt.Println(fmt.Sprintf("%#+v", a.service.defaultDecrypter))
|
fmt.Println(fmt.Sprintf("%#+v", a.service.defaultDecrypter))
|
||||||
|
|
||||||
cert, pkey, err := a.selectDecrypter(ctx)
|
cert, pkey, err := a.selectDecrypter(ctx)
|
||||||
|
@ -246,7 +217,7 @@ func (a *Authority) selectDecrypter(ctx context.Context) (cert *x509.Certificate
|
||||||
}
|
}
|
||||||
|
|
||||||
// fallback to the CA wide decrypter
|
// fallback to the CA wide decrypter
|
||||||
cert = a.service.defaultDecrypterCertificate
|
cert = a.service.signerCertificate
|
||||||
pkey = a.service.defaultDecrypter
|
pkey = a.service.defaultDecrypter
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -2,77 +2,76 @@ package scep
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto"
|
"crypto"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"errors"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// CertificateChain is the issuer certificate, along with any other bundled certificates
|
// Roots contains the (federated) CA roots certificate(s)
|
||||||
// to be returned in the chain for consumers. Configured in the ca.json crt property.
|
Roots []*x509.Certificate `json:"-"`
|
||||||
CertificateChain []*x509.Certificate
|
// Intermediates points issuer certificate, along with any other bundled certificates
|
||||||
SignerCert *x509.Certificate
|
// to be returned in the chain for consumers.
|
||||||
DecrypterCert *x509.Certificate
|
Intermediates []*x509.Certificate `json:"-"`
|
||||||
|
// SignerCert points to the certificate of the CA signer. It usually is the same as the
|
||||||
|
// first certificate in the CertificateChain.
|
||||||
|
SignerCert *x509.Certificate `json:"-"`
|
||||||
// Signer signs CSRs in SCEP. Configured in the ca.json key property.
|
// Signer signs CSRs in SCEP. Configured in the ca.json key property.
|
||||||
Signer crypto.Signer `json:"-"`
|
Signer crypto.Signer `json:"-"`
|
||||||
// Decrypter decrypts encrypted SCEP messages. Configured in the ca.json key property.
|
// Decrypter decrypts encrypted SCEP messages. Configured in the ca.json key property.
|
||||||
Decrypter crypto.Decrypter `json:"-"`
|
Decrypter crypto.Decrypter `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type comparablePublicKey interface {
|
||||||
|
Equal(crypto.PublicKey) bool
|
||||||
|
}
|
||||||
|
|
||||||
// Validate checks the fields in Options.
|
// Validate checks the fields in Options.
|
||||||
func (o *Options) Validate() error {
|
func (o *Options) Validate() error {
|
||||||
if o.CertificateChain == nil {
|
switch {
|
||||||
return errors.New("certificate chain not configured correctly")
|
case len(o.Intermediates) == 0:
|
||||||
|
return errors.New("no intermediate certificate available for SCEP authority")
|
||||||
|
case o.Signer == nil:
|
||||||
|
return errors.New("no signer available for SCEP authority")
|
||||||
|
case o.SignerCert == nil:
|
||||||
|
return errors.New("no signer certificate available for SCEP authority")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(o.CertificateChain) < 1 {
|
// check if the signer (intermediate CA) certificate has the same public key as
|
||||||
return errors.New("certificate chain should at least have one certificate")
|
// the signer. According to the RFC it seems valid to have different keys for
|
||||||
|
// the intermediate and the CA signing new certificates, so this might change
|
||||||
|
// in the future.
|
||||||
|
signerPublicKey := o.Signer.Public().(comparablePublicKey)
|
||||||
|
if !signerPublicKey.Equal(o.SignerCert.PublicKey) {
|
||||||
|
return errors.New("mismatch between signer certificate and public key")
|
||||||
}
|
}
|
||||||
|
|
||||||
// According to the RFC: https://tools.ietf.org/html/rfc8894#section-3.1, SCEP
|
// decrypter can be nil in case a signing only key is used; validation complete.
|
||||||
// can be used with something different than RSA, but requires the encryption
|
if o.Decrypter == nil {
|
||||||
// to be performed using the challenge password. An older version of specification
|
return nil
|
||||||
// states that only RSA is supported: https://tools.ietf.org/html/draft-nourse-scep-23#section-2.1.1
|
}
|
||||||
// Other algorithms than RSA do not seem to be supported in certnanny/sscep, but it might work
|
|
||||||
|
// If a decrypter is available, check that it's backed by an RSA key. According to the
|
||||||
|
// RFC: https://tools.ietf.org/html/rfc8894#section-3.1, SCEP can be used with something
|
||||||
|
// different than RSA, but requires the encryption to be performed using the challenge
|
||||||
|
// password in that case. An older version of specification states that only RSA is
|
||||||
|
// supported: https://tools.ietf.org/html/draft-nourse-scep-23#section-2.1.1. Other
|
||||||
|
// algorithms do not seem to be supported in certnanny/sscep, but it might work
|
||||||
// in micromdm/scep. Currently only RSA is allowed, but it might be an option
|
// in micromdm/scep. Currently only RSA is allowed, but it might be an option
|
||||||
// to try other algorithms in the future.
|
// to try other algorithms in the future.
|
||||||
//intermediate := o.CertificateChain[0]
|
decrypterPublicKey, ok := o.Decrypter.Public().(*rsa.PublicKey)
|
||||||
//intermediate := o.SignerCert
|
if !ok {
|
||||||
// if intermediate.PublicKeyAlgorithm != x509.RSA {
|
return errors.New("only RSA keys are (currently) supported as decrypters")
|
||||||
// return errors.New("only the RSA algorithm is (currently) supported")
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: add checks for key usage?
|
|
||||||
|
|
||||||
//signerPublicKey, ok := o.Signer.Public().(*rsa.PublicKey)
|
|
||||||
// if !ok {
|
|
||||||
// return errors.New("only RSA public keys are (currently) supported as signers")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// check if the intermediate ca certificate has the same public key as the signer.
|
|
||||||
// According to the RFC it seems valid to have different keys for the intermediate
|
|
||||||
// and the CA signing new certificates, so this might change in the future.
|
|
||||||
// if !signerPublicKey.Equal(intermediate.PublicKey) {
|
|
||||||
// return errors.New("mismatch between certificate chain and signer public keys")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: this could be a different decrypter, based on the value
|
|
||||||
// in the provisioner.
|
|
||||||
// decrypterPublicKey, ok := o.Decrypter.Public().(*rsa.PublicKey)
|
|
||||||
// if !ok {
|
|
||||||
// return errors.New("only RSA public keys are (currently) supported as decrypters")
|
|
||||||
// }
|
|
||||||
|
|
||||||
// check if intermediate public key is the same as the decrypter public key.
|
// check if intermediate public key is the same as the decrypter public key.
|
||||||
// In certnanny/sscep it's mentioned that the signing key can be different
|
// In certnanny/sscep it's mentioned that the signing key can be different
|
||||||
// from the decrypting (and encrypting) key. Currently that's not supported.
|
// from the decrypting (and encrypting) key. These options are only used and
|
||||||
// if !decrypterPublicKey.Equal(intermediate.PublicKey) {
|
// validated when the intermediate CA is also used as the decrypter, though,
|
||||||
// return errors.New("mismatch between certificate chain and decrypter public keys")
|
// so they should match.
|
||||||
// }
|
if !decrypterPublicKey.Equal(o.SignerCert.PublicKey) {
|
||||||
|
return errors.New("mismatch between certificate chain and decrypter public keys")
|
||||||
// if !decrypterPublicKey.Equal(o.DecrypterCert.PublicKey) {
|
}
|
||||||
// return errors.New("mismatch between certificate chain and decrypter public keys")
|
|
||||||
// }
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,15 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Service is a wrapper for crypto.Signer and crypto.Decrypter
|
// Service is a wrapper for a crypto.Decrypter and crypto.Signer for
|
||||||
|
// decrypting SCEP requests and signing certificates in response to
|
||||||
|
// SCEP certificate requests.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
certificateChain []*x509.Certificate
|
roots []*x509.Certificate
|
||||||
signerCertificate *x509.Certificate
|
intermediates []*x509.Certificate
|
||||||
signer crypto.Signer
|
signerCertificate *x509.Certificate
|
||||||
defaultDecrypterCertificate *x509.Certificate
|
signer crypto.Signer
|
||||||
defaultDecrypter crypto.Decrypter
|
defaultDecrypter crypto.Decrypter
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewService returns a new Service type.
|
// NewService returns a new Service type.
|
||||||
|
@ -20,13 +22,11 @@ func NewService(_ context.Context, opts Options) (*Service, error) {
|
||||||
if err := opts.Validate(); err != nil {
|
if err := opts.Validate(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: should this become similar to the New CertificateAuthorityService as in x509CAService?
|
|
||||||
return &Service{
|
return &Service{
|
||||||
certificateChain: opts.CertificateChain,
|
roots: opts.Roots,
|
||||||
signerCertificate: opts.SignerCert,
|
intermediates: opts.Intermediates,
|
||||||
signer: opts.Signer,
|
signerCertificate: opts.SignerCert,
|
||||||
defaultDecrypterCertificate: opts.DecrypterCert,
|
signer: opts.Signer,
|
||||||
defaultDecrypter: opts.Decrypter,
|
defaultDecrypter: opts.Decrypter,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue