Refactor SCEP provisioner and decrypter

pull/1523/head
Herman Slatman 1 year ago
parent 0377fe559b
commit 180162bd6a
No known key found for this signature in database
GPG Key ID: F4D8A44EA0A75A4F

@ -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() {

@ -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

@ -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

@ -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 {
return nil, errors.New("no intermediate certificate available in SCEP authority")
} }
certs := []*x509.Certificate{} // if a provisioner specific RSA decrypter is available, it is returned as
// the first 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…
Cancel
Save