diff --git a/.goreleaser.yml b/.goreleaser.yml index 41747192..ec14e405 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -268,7 +268,7 @@ winget: # Release notes URL. # # Templates: allowed - release_notes_url: "https://github.com/smallstep/certificates/releases/tag/{{.Version}}" + release_notes_url: "https://github.com/smallstep/certificates/releases/tag/{{ .Tag }}" # Create the PR - for testing skip_upload: auto @@ -283,7 +283,7 @@ winget: repository: owner: smallstep name: winget-pkgs - branch: step + branch: "step-ca-{{.Version}}" # Optionally a token can be provided, if it differs from the token # provided to GoReleaser diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e9e2029..6141fba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,35 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. --- +## [0.26.0] - 2024-03-28 + +### Added + +- [TPM KMS](https://github.com/smallstep/crypto/tree/master/kms/tpmkms) support for CA keys (smallstep/certificates#1772) +- Propagation of HTTP request identifier using X-Request-Id header (smallstep/certificates#1743, smallstep/certificates#1542) +- Expires header in CRL response (smallstep/certificates#1708) +- Support for providing TLS configuration programmatically (smallstep/certificates#1685) +- Support for providing external CAS implementation (smallstep/certificates#1684) +- AWS `ca-west-1` identity document root certificate (smallstep/certificates#1715) +- [COSE RS1](https://www.rfc-editor.org/rfc/rfc8812.html#section-2) as a supported algorithm with ACME `device-attest-01` challenge (smallstep/certificates#1663) + +### Changed + +- In an RA setup, let the CA decide the RA certificate lifetime (smallstep/certificates#1764) +- Use Debian Bookworm in Docker containers (smallstep/certificates#1615) +- Error message for CSR validation (smallstep/certificates#1665) +- Updated dependencies + +### Fixed + +- Stop CA when any of the required servers fails to start (smallstep/certificates#1751). Before the fix, the CA would continue running and only log the server failure when stopped. +- Configuration loading errors when not using context were not returned. Fixed in [cli-utils/109](https://github.com/smallstep/cli-utils/pull/109). +- HTTP_PROXY and HTTPS_PROXY support for ACME validation client (smallstep/certificates#1658). + +### Security + +- Upgrade to using cosign v2 for signing artifacts + ## [0.25.1] - 2023-11-28 ### Added diff --git a/acme/challenge.go b/acme/challenge.go index 14ff29cc..4f707713 100644 --- a/acme/challenge.go +++ b/acme/challenge.go @@ -1117,7 +1117,7 @@ var ( oidTCGKpAIKCertificate = asn1.ObjectIdentifier{2, 23, 133, 8, 3} ) -// validateAKCertifiate validates the X.509 AK certificate to be +// validateAKCertificate validates the X.509 AK certificate to be // in accordance with the required properties. The requirements come from: // https://www.w3.org/TR/webauthn-2/#sctn-tpm-cert-requirements. // @@ -1126,7 +1126,7 @@ var ( // - The Subject Alternative Name extension MUST be set as defined // in [TPMv2-EK-Profile] section 3.2.9. // - The Extended Key Usage extension MUST contain the OID 2.23.133.8.3 -// ("joint-iso-itu-t(2) internationalorganizations(23) 133 tcg-kp(8) tcg-kp-AIKCertificate(3)"). +// ("joint-iso-itu-t(2) international-organizations(23) 133 tcg-kp(8) tcg-kp-AIKCertificate(3)"). // - The Basic Constraints extension MUST have the CA component set to false. // - An Authority Information Access (AIA) extension with entry id-ad-ocsp // and a CRL Distribution Point extension [RFC5280] are both OPTIONAL as diff --git a/acme/common.go b/acme/common.go index e86b23e9..a9a023cd 100644 --- a/acme/common.go +++ b/acme/common.go @@ -130,7 +130,7 @@ func (m *MockProvisioner) GetName() string { return m.Mret1.(string) } -// AuthorizeOrderIdentifiers mock +// AuthorizeOrderIdentifier mock func (m *MockProvisioner) AuthorizeOrderIdentifier(ctx context.Context, identifier provisioner.ACMEIdentifier) error { if m.MauthorizeOrderIdentifier != nil { return m.MauthorizeOrderIdentifier(ctx, identifier) diff --git a/acme/order.go b/acme/order.go index c5b9a6ba..be38a523 100644 --- a/acme/order.go +++ b/acme/order.go @@ -138,7 +138,7 @@ func (o *Order) UpdateStatus(ctx context.Context, db DB) error { return nil } -// getKeyFingerprint returns a fingerprint from the list of authorizations. This +// getAuthorizationFingerprint returns a fingerprint from the list of authorizations. This // fingerprint is used on the device-attest-01 flow to verify the attestation // certificate public key with the CSR public key. // diff --git a/api/models/scep.go b/api/models/scep.go index f4aa1502..7b3c0793 100644 --- a/api/models/scep.go +++ b/api/models/scep.go @@ -97,7 +97,7 @@ func (s *SCEP) AuthorizeSSHSign(context.Context, string) ([]provisioner.SignOpti return nil, errDummyImplementation } -// AuthorizeRevoke returns an unimplemented error. Provisioners should overwrite +// AuthorizeSSHRevoke returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for revoking SSH Certificates. func (s *SCEP) AuthorizeSSHRevoke(context.Context, string) error { return errDummyImplementation diff --git a/authority/admin/api/policy.go b/authority/admin/api/policy.go index 89744893..c45bc947 100644 --- a/authority/admin/api/policy.go +++ b/authority/admin/api/policy.go @@ -35,7 +35,7 @@ type PolicyAdminResponder interface { // policyAdminResponder implements PolicyAdminResponder. type policyAdminResponder struct{} -// NewACMEAdminResponder returns a new PolicyAdminResponder. +// NewPolicyAdminResponder returns a new PolicyAdminResponder. func NewPolicyAdminResponder() PolicyAdminResponder { return &policyAdminResponder{} } diff --git a/authority/authority.go b/authority/authority.go index c112bc25..d3b93288 100644 --- a/authority/authority.go +++ b/authority/authority.go @@ -62,9 +62,10 @@ type Authority struct { x509Enforcers []provisioner.CertificateEnforcer // SCEP CA - scepOptions *scep.Options - validateSCEP bool - scepAuthority *scep.Authority + scepOptions *scep.Options + validateSCEP bool + scepAuthority *scep.Authority + scepKeyManager provisioner.SCEPKeyManager // SSH CA sshHostPassword []byte @@ -139,7 +140,7 @@ func New(cfg *config.Config, opts ...Option) (*Authority, error) { } } if a.keyManager != nil { - a.keyManager = &instrumentedKeyManager{a.keyManager, a.meter} + a.keyManager = newInstrumentedKeyManager(a.keyManager, a.meter) } if !a.skipInit { @@ -168,7 +169,7 @@ func NewEmbedded(opts ...Option) (*Authority, error) { } } if a.keyManager != nil { - a.keyManager = &instrumentedKeyManager{a.keyManager, a.meter} + a.keyManager = newInstrumentedKeyManager(a.keyManager, a.meter) } // Validate required options @@ -349,7 +350,7 @@ func (a *Authority) init() error { return err } - a.keyManager = &instrumentedKeyManager{a.keyManager, a.meter} + a.keyManager = newInstrumentedKeyManager(a.keyManager, a.meter) } // Initialize linkedca client if necessary. On a linked RA, the issuer @@ -446,6 +447,7 @@ func (a *Authority) init() error { return err } a.rootX509Certs = append(a.rootX509Certs, resp.RootCertificate) + a.intermediateX509Certs = append(a.intermediateX509Certs, resp.IntermediateCertificates...) } } @@ -694,32 +696,42 @@ func (a *Authority) init() error { options := &scep.Options{ Roots: a.rootX509Certs, Intermediates: a.intermediateX509Certs, - SignerCert: a.intermediateX509Certs[0], } - if options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ - SigningKey: a.config.IntermediateKey, - Password: a.password, - }); err != nil { - return err + + // intermediate certificates can be empty in RA mode + if len(a.intermediateX509Certs) > 0 { + options.SignerCert = a.intermediateX509Certs[0] } - // TODO(hs): instead of creating the decrypter here, pass the - // intermediate key + chain down to the SCEP authority, - // and only instantiate it when required there. Is that possible? - // Also with entering passwords? - // TODO(hs): if moving the logic, try improving the logic for the - // decrypter password too? Right now it needs to be entered multiple - // times; I've observed it to be three times maximum, every time - // 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, - Password: a.password, - }); err == nil { - // only pass the decrypter down when it was successfully created, - // meaning it's an RSA key, and `CreateDecrypter` did not fail. - options.Decrypter = decrypter - options.DecrypterCert = options.Intermediates[0] + + // attempt to create the (default) SCEP signer if the intermediate + // key is configured. + if a.config.IntermediateKey != "" { + if options.Signer, err = a.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ + SigningKey: a.config.IntermediateKey, + Password: a.password, + }); err != nil { + return err + } + + // TODO(hs): instead of creating the decrypter here, pass the + // intermediate key + chain down to the SCEP authority, + // and only instantiate it when required there. Is that possible? + // Also with entering passwords? + // TODO(hs): if moving the logic, try improving the logic for the + // decrypter password too? Right now it needs to be entered multiple + // times; I've observed it to be three times maximum, every time + // the intermediate key is read. + _, isRSAKey := options.Signer.Public().(*rsa.PublicKey) + if km, ok := a.keyManager.(kmsapi.Decrypter); ok && isRSAKey { + if decrypter, err := km.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ + DecryptionKey: a.config.IntermediateKey, + Password: a.password, + }); err == nil { + // only pass the decrypter down when it was successfully created, + // meaning it's an RSA key, and `CreateDecrypter` did not fail. + options.Decrypter = decrypter + options.DecrypterCert = options.Intermediates[0] + } } } diff --git a/authority/meter.go b/authority/meter.go index cccda22a..c99069a4 100644 --- a/authority/meter.go +++ b/authority/meter.go @@ -66,6 +66,22 @@ type instrumentedKeyManager struct { meter Meter } +type instrumentedKeyAndDecrypterManager struct { + kms.KeyManager + decrypter kmsapi.Decrypter + meter Meter +} + +func newInstrumentedKeyManager(k kms.KeyManager, m Meter) kms.KeyManager { + decrypter, isDecrypter := k.(kmsapi.Decrypter) + switch { + case isDecrypter: + return &instrumentedKeyAndDecrypterManager{&instrumentedKeyManager{k, m}, decrypter, m} + default: + return &instrumentedKeyManager{k, m} + } +} + func (i *instrumentedKeyManager) CreateSigner(req *kmsapi.CreateSignerRequest) (s crypto.Signer, err error) { if s, err = i.KeyManager.CreateSigner(req); err == nil { s = &instrumentedKMSSigner{s, i.meter} @@ -74,6 +90,10 @@ func (i *instrumentedKeyManager) CreateSigner(req *kmsapi.CreateSignerRequest) ( return } +func (i *instrumentedKeyAndDecrypterManager) CreateDecrypter(req *kmsapi.CreateDecrypterRequest) (s crypto.Decrypter, err error) { + return i.decrypter.CreateDecrypter(req) +} + type instrumentedKMSSigner struct { crypto.Signer meter Meter @@ -85,3 +105,7 @@ func (i *instrumentedKMSSigner) Sign(rand io.Reader, digest []byte, opts crypto. return } + +var _ kms.KeyManager = (*instrumentedKeyManager)(nil) +var _ kms.KeyManager = (*instrumentedKeyAndDecrypterManager)(nil) +var _ kmsapi.Decrypter = (*instrumentedKeyAndDecrypterManager)(nil) diff --git a/authority/options.go b/authority/options.go index 55c27321..9738b391 100644 --- a/authority/options.go +++ b/authority/options.go @@ -226,6 +226,16 @@ func WithFullSCEPOptions(options *scep.Options) Option { } } +// WithSCEPKeyManager defines the key manager used on SCEP provisioners. +// +// This feature is EXPERIMENTAL and might change at any time. +func WithSCEPKeyManager(skm provisioner.SCEPKeyManager) Option { + return func(a *Authority) error { + a.scepKeyManager = skm + return nil + } +} + // WithSSHUserSigner defines the signer used to sign SSH user certificates. func WithSSHUserSigner(s crypto.Signer) Option { return func(a *Authority) error { diff --git a/authority/provisioner/provisioner.go b/authority/provisioner/provisioner.go index a9b17066..73397a39 100644 --- a/authority/provisioner/provisioner.go +++ b/authority/provisioner/provisioner.go @@ -10,6 +10,7 @@ import ( "strings" "github.com/pkg/errors" + kmsapi "go.step.sm/crypto/kms/apiv1" "golang.org/x/crypto/ssh" "github.com/smallstep/certificates/errs" @@ -206,6 +207,13 @@ type SSHKeys struct { HostKeys []ssh.PublicKey } +// SCEPKeyManager is a KMS interface that combines a KeyManager with a +// Decrypter. +type SCEPKeyManager interface { + kmsapi.KeyManager + kmsapi.Decrypter +} + // Config defines the default parameters used in the initialization of // provisioners. type Config struct { @@ -226,6 +234,8 @@ type Config struct { AuthorizeSSHRenewFunc AuthorizeSSHRenewFunc // WebhookClient is an http client to use in webhook request WebhookClient *http.Client + // SCEPKeyManager, if defined, is the interface used by SCEP provisioners. + SCEPKeyManager SCEPKeyManager } type provisioner struct { @@ -320,7 +330,7 @@ func (b *base) AuthorizeSSHSign(context.Context, string) ([]SignOption, error) { return nil, errs.Unauthorized("provisioner.AuthorizeSSHSign not implemented") } -// AuthorizeRevoke returns an unimplemented error. Provisioners should overwrite +// AuthorizeSSHRevoke returns an unimplemented error. Provisioners should overwrite // this method if they will support authorizing tokens for revoking SSH Certificates. func (b *base) AuthorizeSSHRevoke(context.Context, string) error { return errs.Unauthorized("provisioner.AuthorizeSSHRevoke not implemented") diff --git a/authority/provisioner/scep.go b/authority/provisioner/scep.go index f4067bc5..7213285c 100644 --- a/authority/provisioner/scep.go +++ b/authority/provisioner/scep.go @@ -15,7 +15,6 @@ import ( "go.step.sm/crypto/kms" kmsapi "go.step.sm/crypto/kms/apiv1" - "go.step.sm/crypto/kms/uri" "go.step.sm/linkedca" "github.com/smallstep/certificates/webhook" @@ -59,7 +58,7 @@ type SCEP struct { encryptionAlgorithm int challengeValidationController *challengeValidationController notificationController *notificationController - keyManager kmsapi.KeyManager + keyManager SCEPKeyManager decrypter crypto.Decrypter decrypterCertificate *x509.Certificate signer crypto.Signer @@ -269,34 +268,38 @@ func (s *SCEP) Init(config Config) (err error) { ) // parse the decrypter key PEM contents if available - if decryptionKeyPEM := s.DecrypterKeyPEM; len(decryptionKeyPEM) > 0 { + if len(s.DecrypterKeyPEM) > 0 { // try reading the PEM for validation - block, rest := pem.Decode(decryptionKeyPEM) + block, rest := pem.Decode(s.DecrypterKeyPEM) if len(rest) > 0 { return errors.New("failed parsing decrypter key: trailing data") } if block == nil { return errors.New("failed parsing decrypter key: no PEM block found") } + opts := kms.Options{ Type: kmsapi.SoftKMS, } - if s.keyManager, err = kms.New(context.Background(), opts); err != nil { + km, err := kms.New(context.Background(), opts) + if err != nil { return fmt.Errorf("failed initializing kms: %w", err) } - kmsDecrypter, ok := s.keyManager.(kmsapi.Decrypter) + scepKeyManager, ok := km.(SCEPKeyManager) if !ok { return fmt.Errorf("%q is not a kmsapi.Decrypter", opts.Type) } - if s.decrypter, err = kmsDecrypter.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ - DecryptionKeyPEM: decryptionKeyPEM, + s.keyManager = scepKeyManager + + if s.decrypter, err = s.keyManager.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ + DecryptionKeyPEM: s.DecrypterKeyPEM, Password: []byte(s.DecrypterKeyPassword), PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, }); err != nil { return fmt.Errorf("failed creating decrypter: %w", err) } if s.signer, err = s.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ - SigningKeyPEM: decryptionKeyPEM, // TODO(hs): support distinct signer key in the future? + SigningKeyPEM: s.DecrypterKeyPEM, // TODO(hs): support distinct signer key in the future? Password: []byte(s.DecrypterKeyPassword), PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, }); err != nil { @@ -304,41 +307,44 @@ func (s *SCEP) Init(config Config) (err error) { } } - if decryptionKeyURI := s.DecrypterKeyURI; decryptionKeyURI != "" { - u, err := uri.Parse(s.DecrypterKeyURI) + if s.DecrypterKeyURI != "" { + kmsType, err := kmsapi.TypeOf(s.DecrypterKeyURI) if err != nil { return fmt.Errorf("failed parsing decrypter key: %w", err) } - var kmsType kmsapi.Type - switch { - case u.Scheme != "": - kmsType = kms.Type(u.Scheme) - default: - kmsType = kmsapi.SoftKMS - } - opts := kms.Options{ - Type: kmsType, - URI: s.DecrypterKeyURI, - } - if s.keyManager, err = kms.New(context.Background(), opts); err != nil { - return fmt.Errorf("failed initializing kms: %w", err) - } - kmsDecrypter, ok := s.keyManager.(kmsapi.Decrypter) - if !ok { - return fmt.Errorf("%q is not a kmsapi.Decrypter", opts.Type) - } - if kmsType != "softkms" { // TODO(hs): this should likely become more transparent? - decryptionKeyURI = u.Opaque - } - if s.decrypter, err = kmsDecrypter.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ - DecryptionKey: decryptionKeyURI, + + if config.SCEPKeyManager != nil { + s.keyManager = config.SCEPKeyManager + } else { + if kmsType == kmsapi.DefaultKMS { + kmsType = kmsapi.SoftKMS + } + opts := kms.Options{ + Type: kmsType, + URI: s.DecrypterKeyURI, + } + km, err := kms.New(context.Background(), opts) + if err != nil { + return fmt.Errorf("failed initializing kms: %w", err) + } + scepKeyManager, ok := km.(SCEPKeyManager) + if !ok { + return fmt.Errorf("%q is not a kmsapi.Decrypter", opts.Type) + } + s.keyManager = scepKeyManager + } + + // Create decrypter and signer with the same key: + // TODO(hs): support distinct signer key in the future? + if s.decrypter, err = s.keyManager.CreateDecrypter(&kmsapi.CreateDecrypterRequest{ + DecryptionKey: s.DecrypterKeyURI, Password: []byte(s.DecrypterKeyPassword), PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, }); err != nil { return fmt.Errorf("failed creating decrypter: %w", err) } if s.signer, err = s.keyManager.CreateSigner(&kmsapi.CreateSignerRequest{ - SigningKey: decryptionKeyURI, // TODO(hs): support distinct signer key in the future? + SigningKey: s.DecrypterKeyURI, Password: []byte(s.DecrypterKeyPassword), PasswordPrompter: kmsapi.NonInteractivePasswordPrompter, }); err != nil { diff --git a/authority/provisioner/scep_test.go b/authority/provisioner/scep_test.go index 2e9f3419..4e2081ee 100644 --- a/authority/provisioner/scep_test.go +++ b/authority/provisioner/scep_test.go @@ -2,19 +2,27 @@ package provisioner import ( "context" + "crypto" + "crypto/rand" + "crypto/rsa" "crypto/x509" + "crypto/x509/pkix" "encoding/json" + "encoding/pem" "errors" "net/http" "net/http/httptest" + "os" + "path/filepath" "testing" + "github.com/smallstep/certificates/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - + "go.step.sm/crypto/kms/softkms" + "go.step.sm/crypto/minica" + "go.step.sm/crypto/pemutil" "go.step.sm/linkedca" - - "github.com/smallstep/certificates/webhook" ) func Test_challengeValidationController_Validate(t *testing.T) { @@ -366,3 +374,270 @@ func TestSCEP_ValidateChallenge(t *testing.T) { }) } } + +func TestSCEP_Init(t *testing.T) { + serialize := func(key crypto.PrivateKey, password string) []byte { + var opts []pemutil.Options + if password == "" { + opts = append(opts, pemutil.WithPasswordPrompt("no password", func(s string) ([]byte, error) { + return nil, nil + })) + } else { + opts = append(opts, pemutil.WithPassword([]byte("password"))) + } + block, err := pemutil.Serialize(key, opts...) + require.NoError(t, err) + return pem.EncodeToMemory(block) + } + + ca, err := minica.New() + require.NoError(t, err) + + key, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err) + badKey, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err) + + cert, err := ca.Sign(&x509.Certificate{ + Subject: pkix.Name{CommonName: "SCEP decryptor"}, + PublicKey: key.Public(), + }) + require.NoError(t, err) + + certPEM := pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", Bytes: cert.Raw, + }) + certPEMWithIntermediate := append(pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", Bytes: cert.Raw, + }), pem.EncodeToMemory(&pem.Block{ + Type: "CERTIFICATE", Bytes: ca.Intermediate.Raw, + })...) + + keyPEM := serialize(key, "password") + keyPEMNoPassword := serialize(key, "") + badKeyPEM := serialize(badKey, "password") + + tmp := t.TempDir() + path := filepath.Join(tmp, "rsa.priv") + pathNoPassword := filepath.Join(tmp, "rsa.key") + + require.NoError(t, os.WriteFile(path, keyPEM, 0600)) + require.NoError(t, os.WriteFile(pathNoPassword, keyPEMNoPassword, 0600)) + + type args struct { + config Config + } + tests := []struct { + name string + s *SCEP + args args + wantErr bool + }{ + {"ok", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, false}, + {"ok no password", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEMNoPassword, + DecrypterKeyPassword: "", + EncryptionAlgorithmIdentifier: 1, + }, args{Config{Claims: globalProvisionerClaims}}, false}, + {"ok with uri", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 1024, + DecrypterCertificate: certPEM, + DecrypterKeyURI: "softkms:path=" + path, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 2, + }, args{Config{Claims: globalProvisionerClaims}}, false}, + {"ok with uri no password", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 2048, + DecrypterCertificate: certPEM, + DecrypterKeyURI: "softkms:path=" + pathNoPassword, + DecrypterKeyPassword: "", + EncryptionAlgorithmIdentifier: 3, + }, args{Config{Claims: globalProvisionerClaims}}, false}, + {"ok with SCEPKeyManager", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 2048, + DecrypterCertificate: certPEM, + DecrypterKeyURI: "softkms:path=" + pathNoPassword, + DecrypterKeyPassword: "", + EncryptionAlgorithmIdentifier: 4, + }, args{Config{Claims: globalProvisionerClaims, SCEPKeyManager: &softkms.SoftKMS{}}}, false}, + {"ok intermediate", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: nil, + DecrypterKeyPEM: nil, + DecrypterKeyPassword: "", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, false}, + {"fail type", &SCEP{ + Type: "", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail name", &SCEP{ + Type: "SCEP", + Name: "", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail minimumPublicKeyLength", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 2001, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail encryptionAlgorithmIdentifier", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 5, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail negative encryptionAlgorithmIdentifier", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: -1, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail key decode", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: []byte("not a pem"), + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail certificate decode", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: []byte("not a pem"), + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail certificate with intermediate", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEMWithIntermediate, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail decrypter password", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "badpassword", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail uri", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyURI: "softkms:path=missing.key", + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail uri password", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyURI: "softkms:path=" + path, + DecrypterKeyPassword: "badpassword", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail uri type", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyURI: "foo:path=" + path, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail missing certificate", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: nil, + DecrypterKeyPEM: keyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + {"fail key match", &SCEP{ + Type: "SCEP", + Name: "scep", + ChallengePassword: "password123", + MinimumPublicKeyLength: 0, + DecrypterCertificate: certPEM, + DecrypterKeyPEM: badKeyPEM, + DecrypterKeyPassword: "password", + EncryptionAlgorithmIdentifier: 0, + }, args{Config{Claims: globalProvisionerClaims}}, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := tt.s.Init(tt.args.config); (err != nil) != tt.wantErr { + t.Errorf("SCEP.Init() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/authority/provisioners.go b/authority/provisioners.go index 34cc75ed..1502ea2b 100644 --- a/authority/provisioners.go +++ b/authority/provisioners.go @@ -201,6 +201,7 @@ func (a *Authority) generateProvisionerConfig(ctx context.Context) (provisioner. AuthorizeRenewFunc: a.authorizeRenewFunc, AuthorizeSSHRenewFunc: a.authorizeSSHRenewFunc, WebhookClient: a.webhookClient, + SCEPKeyManager: a.scepKeyManager, }, nil } diff --git a/cas/apiv1/requests.go b/cas/apiv1/requests.go index fdbb285e..35cf9251 100644 --- a/cas/apiv1/requests.go +++ b/cas/apiv1/requests.go @@ -116,7 +116,8 @@ type GetCertificateAuthorityRequest struct { // GetCertificateAuthorityResponse is the response that contains // the root certificate. type GetCertificateAuthorityResponse struct { - RootCertificate *x509.Certificate + RootCertificate *x509.Certificate + IntermediateCertificates []*x509.Certificate } // CreateKeyRequest is the request used to generate a new key using a KMS. diff --git a/cas/vaultcas/vaultcas.go b/cas/vaultcas/vaultcas.go index 73d1b926..16adccc4 100644 --- a/cas/vaultcas/vaultcas.go +++ b/cas/vaultcas/vaultcas.go @@ -165,7 +165,8 @@ func (v *VaultCAS) GetCertificateAuthority(*apiv1.GetCertificateAuthorityRequest } return &apiv1.GetCertificateAuthorityResponse{ - RootCertificate: cert.root, + RootCertificate: cert.root, + IntermediateCertificates: cert.intermediates, }, nil } diff --git a/go.mod b/go.mod index e0e3b513..8419abdc 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,10 @@ module github.com/smallstep/certificates -go 1.20 +go 1.21 require ( cloud.google.com/go/longrunning v0.5.6 - cloud.google.com/go/security v1.15.6 + cloud.google.com/go/security v1.16.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/coreos/go-oidc/v3 v3.4.0 github.com/dgraph-io/badger v1.6.2 @@ -17,10 +17,10 @@ require ( github.com/google/go-tpm v0.9.0 github.com/google/uuid v1.6.0 github.com/googleapis/gax-go/v2 v2.12.3 - github.com/hashicorp/vault/api v1.12.2 + github.com/hashicorp/vault/api v1.13.0 github.com/hashicorp/vault/api/auth/approle v0.6.0 github.com/hashicorp/vault/api/auth/kubernetes v0.6.0 - github.com/newrelic/go-agent/v3 v3.30.0 + github.com/newrelic/go-agent/v3 v3.32.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.19.0 github.com/rs/xid v1.5.0 @@ -34,47 +34,48 @@ require ( github.com/stretchr/testify v1.9.0 github.com/urfave/cli v1.22.14 go.step.sm/cli-utils v0.9.0 - go.step.sm/crypto v0.44.1 + go.step.sm/crypto v0.44.6 go.step.sm/linkedca v0.20.1 - golang.org/x/crypto v0.21.0 - golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc - golang.org/x/net v0.22.0 - google.golang.org/api v0.171.0 - google.golang.org/grpc v1.62.1 + golang.org/x/crypto v0.22.0 + golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 + golang.org/x/net v0.24.0 + google.golang.org/api v0.176.0 + google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.33.0 ) require ( cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute v1.24.0 // indirect - cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.6 // indirect - cloud.google.com/go/kms v1.15.7 // indirect + cloud.google.com/go/auth v0.2.2 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.1 // indirect + cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/iam v1.1.7 // indirect + cloud.google.com/go/kms v1.15.8 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect github.com/ThalesIgnite/crypto11 v1.2.5 // indirect - github.com/aws/aws-sdk-go-v2 v1.26.0 // indirect - github.com/aws/aws-sdk-go-v2/config v1.27.8 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.8 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 // indirect + github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.11 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.11 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 // indirect - github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 // indirect - github.com/aws/smithy-go v1.20.1 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 // indirect + github.com/aws/aws-sdk-go-v2/service/kms v1.31.0 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 // indirect + github.com/aws/smithy-go v1.20.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v3 v3.0.0 // indirect github.com/cespare/xxhash v1.1.0 // indirect @@ -86,6 +87,7 @@ require ( github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/go-jose/go-jose/v4 v4.0.1 // indirect github.com/go-kit/kit v0.13.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect @@ -93,14 +95,14 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-piv/piv-go v1.11.0 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect - github.com/golang-jwt/jwt/v5 v5.2.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/certificate-transparency-go v1.1.6 // indirect - github.com/google/go-tpm-tools v0.4.3 // indirect + github.com/google/go-tpm-tools v0.4.4 // indirect github.com/google/go-tspi v0.3.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect @@ -155,15 +157,14 @@ require ( go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/oauth2 v0.18.0 // indirect + golang.org/x/oauth2 v0.19.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect + google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 868b71f2..f7ed72e7 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,10 @@ cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w9 cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= cloud.google.com/go v0.112.1/go.mod h1:+Vbu+Y1UU+I1rjmzeMOb/8RfkKJK2Gyxi1X6jJCZLo4= +cloud.google.com/go/auth v0.2.2 h1:gmxNJs4YZYcw6YvKRtVBaF2fyUE6UrWPyzU8jHvYfmI= +cloud.google.com/go/auth v0.2.2/go.mod h1:2bDNJWtWziDT3Pu1URxHHbkHE/BbOCuyUiKIGcNvafo= +cloud.google.com/go/auth/oauth2adapt v0.2.1 h1:VSPmMmUlT8CkIZ2PzD9AlLN+R3+D1clXMWHHa6vG/Ag= +cloud.google.com/go/auth/oauth2adapt v0.2.1/go.mod h1:tOdK/k+D2e4GEwfBRA48dKNQiDsqIXxLh7VU319eV0g= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -42,25 +46,23 @@ cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6m cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= +cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= +cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= -cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= -cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= -cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= -cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= +cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= +cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= +cloud.google.com/go/kms v1.15.8 h1:szIeDCowID8th2i8XE4uRev5PMxQFqW+JjwYxL9h6xs= +cloud.google.com/go/kms v1.15.8/go.mod h1:WoUHcDjD9pluCg7pNds131awnH429QGvRM3N/4MyoVs= cloud.google.com/go/longrunning v0.5.6 h1:xAe8+0YaWoCKr9t1+aWe+OeQgN/iJK1fEgZSXmjuEaE= cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/security v1.15.6 h1:LYMj7ISEEjVQ0ub6E6ygGhjVbNQTH5CawKZz0bbPMVE= -cloud.google.com/go/security v1.15.6/go.mod h1:UMEAGVBMqE6xZvkCR1FvUIeBEmGOCRIDwtwT357xmok= +cloud.google.com/go/security v1.16.0 h1:dzc3oYxFG/9+uMwmxpnG+te4ZEEkbzvBoAFR1Va36N4= +cloud.google.com/go/security v1.16.0/go.mod h1:e1GsICfB1nLCRXOq0yaRlKE/6RUAlBqmalTYQH4J2Xo= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= @@ -72,18 +74,18 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 h1:FDif4R1+UUR+00q6wquyX90K7A8dN+R5E8GEadoP7sU= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2/go.mod h1:aiYBYui4BJ/BJCAIKs92XiPyQfTaBWqvHujDwKb6CBU= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 h1:m/sWOGCREuSBqg2htVQTBY8nOZpyajYztF0vUvSZTuM= github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0/go.mod h1:Pu5Zksi2KrU7LPbZbNINx6fuVrUp/ffvpxdDj+i8LeE= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1 h1:FbH3BbSb4bvGluTesZZ+ttN/MDsnMmQP36OSnDuSXqw= github.com/Azure/azure-sdk-for-go/sdk/keyvault/internal v0.7.1/go.mod h1:9V2j0jn9jDEkCkv8w/bKTNppX/d0FVA1ud77xCIP4KA= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -101,34 +103,34 @@ github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go-v2 v1.26.0 h1:/Ce4OCiM3EkpW7Y+xUnfAFpchU78K7/Ug01sZni9PgA= -github.com/aws/aws-sdk-go-v2 v1.26.0/go.mod h1:35hUlJVYd+M++iLI3ALmVwMOyRYMmRqUXpTtRGW+K9I= -github.com/aws/aws-sdk-go-v2/config v1.27.8 h1:0r8epOsiJ7YJz65MGcb8i91ehFp4kvvFe2qkq5oYeRI= -github.com/aws/aws-sdk-go-v2/config v1.27.8/go.mod h1:XsmYKxYNuIhLsFddpNds+j9H5XKzjWDdg/SZngiwFio= -github.com/aws/aws-sdk-go-v2/credentials v1.17.8 h1:WUdNLXbyNbU07V/WFrSOBXqZTDgmmMNMgUFzpYOKJhw= -github.com/aws/aws-sdk-go-v2/credentials v1.17.8/go.mod h1:iPZzLpaBIfhyvVS/XGD3JvR1GP3YdHTqpySKDlqkfs8= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4 h1:S+L2QSKhUuShih3aq9P/mkzDBiOO5tTyVg+vXREfsfg= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.4/go.mod h1:nQ3how7DMnFMWiU1SpECohgC82fpn4cKZ875NDMmwtA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4 h1:0ScVK/4qZ8CIW0k8jOeFVsyS/sAiXpYxRBLolMkuLQM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.4/go.mod h1:84KyjNZdHC6QZW08nfHI6yZgPd+qRgaWcYsyLUo3QY8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4 h1:sHmMWWX5E7guWEFQ9SVo6A3S4xpPrWnd77a6y4WM6PU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.4/go.mod h1:WjpDrhWisWOIoS9n3nk67A3Ll1vfULJ9Kq6h29HTD48= +github.com/aws/aws-sdk-go-v2 v1.26.1 h1:5554eUqIYVWpU0YmeeYZ0wU64H2VLBs8TlhRB2L+EkA= +github.com/aws/aws-sdk-go-v2 v1.26.1/go.mod h1:ffIFB97e2yNsv4aTSGkqtHnppsIJzw7G7BReUZ3jCXM= +github.com/aws/aws-sdk-go-v2/config v1.27.11 h1:f47rANd2LQEYHda2ddSCKYId18/8BhSRM4BULGmfgNA= +github.com/aws/aws-sdk-go-v2/config v1.27.11/go.mod h1:SMsV78RIOYdve1vf36z8LmnszlRWkwMQtomCAI0/mIE= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11 h1:YuIB1dJNf1Re822rriUOTxopaHHvIq0l/pX3fwO+Tzs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.11/go.mod h1:AQtFPsDH9bI2O+71anW6EKL+NcD7LG3dpKGMV4SShgo= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1 h1:FVJ0r5XTHSmIHJV6KuDmdYhEpvlHpiSd38RQWhut5J4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.1/go.mod h1:zusuAeqezXzAB24LGuzuekqMAEgWkVYukBec3kr3jUg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5 h1:aw39xVGeRWlWx9EzGVnhOR4yOjQDHPQ6o6NmBlscyQg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.5/go.mod h1:FSaRudD0dXiMPK2UjknVwwTYyZMRsHv3TtkabsZih5I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5 h1:PG1F3OD1szkuQPzDw3CIQsRIrtTlUC3lP84taWzHlq0= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.5/go.mod h1:jU1li6RFryMz+so64PpKtudI+QzbKoIEivqdf6LNpOc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 h1:EyBZibRTVAs6ECHZOw5/wlylS9OcTzwyjeQMudmREjE= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1/go.mod h1:JKpmtYhhPs7D97NL/ltqz7yCkERFW5dOlHyVl66ZYF8= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6 h1:b+E7zIUHMmcB4Dckjpkapoy47W6C9QBv/zoUP+Hn8Kc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.6/go.mod h1:S2fNV0rxrP78NhPbCZeQgY8H9jdDMeGtwcfZIRxzBqU= -github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= -github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.3 h1:mnbuWHOcM70/OFUlZZ5rcdfA8PflGXXiefU/O+1S3+8= -github.com/aws/aws-sdk-go-v2/service/sso v1.20.3/go.mod h1:5HFu51Elk+4oRBZVxmHrSds5jFXmFj8C3w7DVF2gnrs= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3 h1:uLq0BKatTmDzWa/Nu4WO0M1AaQDaPpwTKAeByEc6WFM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.3/go.mod h1:b+qdhjnxj8GSR6t5YfphOffeoQSQ1KmpoVVuBn+PWxs= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.5 h1:J/PpTf/hllOjx8Xu9DMflff3FajfLxqM5+tepvVXmxg= -github.com/aws/aws-sdk-go-v2/service/sts v1.28.5/go.mod h1:0ih0Z83YDH/QeQ6Ori2yGE2XvWYv/Xm+cZc01LC6oK0= -github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= -github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2 h1:Ji0DY1xUsUr3I8cHps0G+XM3WWU16lP6yG8qu1GAZAs= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.2/go.mod h1:5CsjAbs3NlGQyZNFACh+zztPDI7fU6eW9QsxjfnuBKg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7 h1:ogRAwT1/gxJBcSWDMZlgyFUM962F51A5CRhDLbxLdmo= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.7/go.mod h1:YCsIZhXfRPLFFCl5xxY+1T9RKzOKjCut+28JSX2DnAk= +github.com/aws/aws-sdk-go-v2/service/kms v1.31.0 h1:yl7wcqbisxPzknJVfWTLnK83McUvXba+pz2+tPbIUmQ= +github.com/aws/aws-sdk-go-v2/service/kms v1.31.0/go.mod h1:2snWQJQUKsbN66vAawJuOGX7dr37pfOq9hb0tZDGIqQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5 h1:vN8hEbpRnL7+Hopy9dzmRle1xmDc7o8tmY0klsr175w= +github.com/aws/aws-sdk-go-v2/service/sso v1.20.5/go.mod h1:qGzynb/msuZIE8I75DVRCUXw3o3ZyBmUvMwQ2t/BrGM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4 h1:Jux+gDDyi1Lruk+KHF91tK2KCuY61kzoCpvtvJJBtOE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.4/go.mod h1:mUYPBhaF2lGiukDEjJX2BLRRKTmoUSitGDUgM4tRxak= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6 h1:cwIxeBttqPN3qkaAjcEcsh8NYr8n2HZPkcKgPAi1phU= +github.com/aws/aws-sdk-go-v2/service/sts v1.28.6/go.mod h1:FZf1/nKNEkHdGGJP/cI2MoIMquumuRK6ol3QQJNDxmw= +github.com/aws/smithy-go v1.20.2 h1:tbp628ireGtzcHDDmLT/6ADHidqnwgF57XOXZe6tp4Q= +github.com/aws/smithy-go v1.20.2/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -187,6 +189,7 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUn github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= @@ -202,6 +205,7 @@ github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go. github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= @@ -216,6 +220,8 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2 github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= +github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= github.com/go-kit/kit v0.4.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU= github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg= @@ -241,8 +247,8 @@ github.com/go-test/deep v1.0.2 h1:onZX1rnHT3Wv6cqNgYyFOOlgVKJrksuCMCRvJStbMYw= github.com/go-test/deep v1.0.2/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= -github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= @@ -308,15 +314,19 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-configfs-tsm v0.2.2 h1:YnJ9rXIOj5BYD7/0DNnzs8AOp7UcvjfTvt215EWcs98= +github.com/google/go-configfs-tsm v0.2.2/go.mod h1:EL1GTDFMb5PZQWDviGfZV9n87WeGTR/JUg13RfwkgRo= github.com/google/go-sev-guest v0.9.3 h1:GOJ+EipURdeWFl/YYdgcCxyPeMgQUWlI056iFkBD8UU= +github.com/google/go-sev-guest v0.9.3/go.mod h1:hc1R4R6f8+NcJwITs0L90fYWTsBpd1Ix+Gur15sqHDs= github.com/google/go-tdx-guest v0.3.1 h1:gl0KvjdsD4RrJzyLefDOvFOUH3NAJri/3qvaL5m83Iw= +github.com/google/go-tdx-guest v0.3.1/go.mod h1:/rc3d7rnPykOPuY8U9saMyEps0PZDThLk/RygXm04nE= github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= -github.com/google/go-tpm-tools v0.4.3 h1:L5dc34fttMIREoKRmnIJfv2NSZDSZ+RfBD+izN0EZoA= -github.com/google/go-tpm-tools v0.4.3/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= +github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= +github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= 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/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= +github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -365,6 +375,7 @@ github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/S github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.2.2 h1:ihRI7YFwcZdiSD7SIenIhHfQH3OuDvWerAUBZbeQS3M= +github.com/hashicorp/go-hclog v1.2.2/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= @@ -384,8 +395,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/vault/api v1.12.0/go.mod h1:si+lJCYO7oGkIoNPAN8j3azBLTn9SjMGS+jFaHd1Cck= -github.com/hashicorp/vault/api v1.12.2 h1:7YkCTE5Ni90TcmYHDBExdt4WGJxhpzaHqR6uGbQb/rE= -github.com/hashicorp/vault/api v1.12.2/go.mod h1:LSGf1NGT1BnvFFnKVtnvcaLBM2Lz+gJdpL6HUYed8KE= +github.com/hashicorp/vault/api v1.13.0 h1:RTCGpE2Rgkn9jyPcFlc7YmNocomda44k5ck8FKMH41Y= +github.com/hashicorp/vault/api v1.13.0/go.mod h1:0cb/uZUv1w2cVu9DIvuW1SMlXXC6qtATJt+LXJRx+kg= github.com/hashicorp/vault/api/auth/approle v0.6.0 h1:ELfFFQlTM/e97WJKu1HvNFa7lQ3tlTwwzrR1NJE1V7Y= github.com/hashicorp/vault/api/auth/approle v0.6.0/go.mod h1:CCoIl1xBC3lAWpd1HV+0ovk76Z8b8Mdepyk21h3pGk0= github.com/hashicorp/vault/api/auth/kubernetes v0.6.0 h1:K8sKGhtTAqGKfzaaYvUSIOAqTOIn3Gk1EsCEAMzZHtM= @@ -456,10 +467,12 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxv github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -467,6 +480,7 @@ github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= @@ -504,9 +518,10 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/newrelic/go-agent/v3 v3.30.0 h1:ZXHCT/Cot4iIPwcegCZURuRQOsfmGA6wilW+S3bfBjY= -github.com/newrelic/go-agent/v3 v3.30.0/go.mod h1:9utrgxlSryNqRrTvII2XBL+0lpofXbqXApvVWPpbzUg= +github.com/newrelic/go-agent/v3 v3.32.0 h1:99Et9lXXzeQV1CfYldfeTXv+d9W9KatpMbb50kIscWo= +github.com/newrelic/go-agent/v3 v3.32.0/go.mod h1:SMdqPzE/ghkWdY0rYGSD7Clw2daK/XH6pUnVd4albg4= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= +github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv/v3 v3.0.1 h1:x06SQA46+PKIUftmEujdwSEpIx8kR+M9eLYsUxeYveU= github.com/peterbourgon/diskv/v3 v3.0.1/go.mod h1:kJ5Ny7vLdARGU3WUuy6uzO6T0nb/2gWcT1JiBvRmb5o= @@ -530,6 +545,7 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -629,13 +645,14 @@ go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= +go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.step.sm/cli-utils v0.9.0 h1:55jYcsQbnArNqepZyAwcato6Zy2MoZDRkWW+jF+aPfQ= go.step.sm/cli-utils v0.9.0/go.mod h1:Y/CRoWl1FVR9j+7PnAewufAwKmBOTzR6l9+7EYGAnp8= -go.step.sm/crypto v0.44.1 h1:8ouq8JEYXVxSymuVuX54Ilh5X2dqyjgOGGXyPeXDzV8= -go.step.sm/crypto v0.44.1/go.mod h1:hKl+QUIS4oJFRwQBRcVPz8NOYhRaoOJmwXHd2Y3XTA0= +go.step.sm/crypto v0.44.6 h1:vQg8ujce7fNXDO8EWdriSz+ZSJpYnNh22QrFtRjdyoY= +go.step.sm/crypto v0.44.6/go.mod h1:oKRO4jaf2MaCohJDN+/8ShImkvIgUKfJxxy87gqsnXs= go.step.sm/linkedca v0.20.1 h1:bHDn1+UG1NgRrERkWbbCiAIvv4lD5NOFaswPDTyO5vU= go.step.sm/linkedca v0.20.1/go.mod h1:Vaq4+Umtjh7DLFI1KuIxeo598vfBzgSYZUjgVJ7Syxw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -646,6 +663,7 @@ go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/ go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -667,8 +685,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 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-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -679,8 +697,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= -golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81 h1:6R2FC06FonbXQ8pK11/PDFY6N6LWlf9KlzibaCapmqc= +golang.org/x/exp v0.0.0-20240318143956-a85f2c67cd81/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -757,8 +775,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -780,8 +798,8 @@ golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= -golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= +golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= +golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -881,8 +899,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -892,7 +910,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 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.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -902,7 +921,6 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -1021,8 +1039,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69 google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= -google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= -google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/api v0.176.0 h1:dHj1/yv5Dm/eQTXiP9hNCRT3xzJHWXeNdRq29XbMxoE= +google.golang.org/api v0.176.0/go.mod h1:Rra+ltKu14pps/4xTycZfobMgLpbosoaaL7c+SEMrO8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -1030,8 +1048,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1110,12 +1126,12 @@ google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= -google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1:rIo7ocm2roD9DcFIX67Ym8icoGCKSARAiPljFhh5suQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda h1:b6F6WIV4xHHD0FA4oIyzU6mHWg2WI2X1RBehwa5QN38= +google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda/go.mod h1:AHcE/gZH76Bk/ROZhQphlRoWo5xKDEtz3eVEO1LfA8c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1147,8 +1163,8 @@ google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11 google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= -google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1170,6 +1186,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= diff --git a/scep/api/api.go b/scep/api/api.go index bab60302..fd3c61ea 100644 --- a/scep/api/api.go +++ b/scep/api/api.go @@ -387,9 +387,10 @@ func PKIOperation(ctx context.Context, req request) (Response, error) { if msg.MessageType == smallscep.PKCSReq || msg.MessageType == smallscep.RenewalReq { if err := auth.ValidateChallenge(ctx, csr, challengePassword, transactionID); err != nil { if errors.Is(err, provisioner.ErrSCEPChallengeInvalid) { - return createFailureResponse(ctx, csr, msg, smallscep.BadRequest, err) + return createFailureResponse(ctx, csr, msg, smallscep.BadRequest, err.Error(), err) } - return createFailureResponse(ctx, csr, msg, smallscep.BadRequest, errors.New("failed validating challenge password")) + scepErr := errors.New("failed validating challenge password") + return createFailureResponse(ctx, csr, msg, smallscep.BadRequest, scepErr.Error(), scepErr) } } @@ -407,7 +408,7 @@ func PKIOperation(ctx context.Context, req request) (Response, error) { // TODO(hs): ignore this error case? It's not critical if the notification fails; but logging it might be good _ = notifyErr } - return createFailureResponse(ctx, csr, msg, smallscep.BadRequest, fmt.Errorf("error when signing new certificate: %w", err)) + return createFailureResponse(ctx, csr, msg, smallscep.BadRequest, "internal server error; please see the certificate authority logs for more info", fmt.Errorf("error when signing new certificate: %w", err)) } if notifyErr := auth.NotifySuccess(ctx, csr, certRep.Certificate, transactionID); notifyErr != nil { @@ -448,9 +449,9 @@ func fail(w http.ResponseWriter, err error) { http.Error(w, err.Error(), http.StatusInternalServerError) } -func createFailureResponse(ctx context.Context, csr *x509.CertificateRequest, msg *scep.PKIMessage, info smallscep.FailInfo, failError error) (Response, error) { +func createFailureResponse(ctx context.Context, csr *x509.CertificateRequest, msg *scep.PKIMessage, info smallscep.FailInfo, infoText string, failError error) (Response, error) { auth := scep.MustFromContext(ctx) - certRepMsg, err := auth.CreateFailureResponse(ctx, csr, msg, scep.FailInfoName(info), failError.Error()) + certRepMsg, err := auth.CreateFailureResponse(ctx, csr, msg, scep.FailInfoName(info), infoText) if err != nil { return Response{}, err } diff --git a/scep/authority.go b/scep/authority.go index 8ed065fb..00c58d8d 100644 --- a/scep/authority.go +++ b/scep/authority.go @@ -308,7 +308,7 @@ func (a *Authority) SignCSR(ctx context.Context, csr *x509.CertificateRequest, m certChain, err := a.signAuth.SignWithContext(ctx, csr, opts, signOps...) if err != nil { - return nil, fmt.Errorf("error generating certificate for order: %w", err) + return nil, fmt.Errorf("error generating certificate: %w", err) } // take the issued certificate (only); https://tools.ietf.org/html/rfc8894#section-3.3.2 diff --git a/scep/options.go b/scep/options.go index 8bc30a61..d173a76c 100644 --- a/scep/options.go +++ b/scep/options.go @@ -37,19 +37,21 @@ func (o *Options) Validate() error { switch { 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") } - // check if the signer (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. - signerPublicKey := o.Signer.Public().(comparablePublicKey) - if !signerPublicKey.Equal(o.SignerCert.PublicKey) { - return errors.New("mismatch between signer certificate and public key") + // the signer is optional, but if it's set, its public key must match the signer + // certificate public key. + if o.Signer != nil { + // check if the signer (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. + signerPublicKey := o.Signer.Public().(comparablePublicKey) + if !signerPublicKey.Equal(o.SignerCert.PublicKey) { + return errors.New("mismatch between signer certificate and public key") + } } // decrypter can be nil in case a signing only key is used; validation complete. diff --git a/scep/scep.go b/scep/scep.go index b89ed0ac..da7e202e 100644 --- a/scep/scep.go +++ b/scep/scep.go @@ -29,7 +29,7 @@ var ( oidSCEPsenderNonce = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 5} oidSCEPrecipientNonce = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 6} oidSCEPtransactionID = asn1.ObjectIdentifier{2, 16, 840, 1, 113733, 1, 9, 7} - oidSCEPfailInfoText = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 24} + oidSCEPfailInfoText = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 24, 1} //oidChallengePassword = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 7} ) diff --git a/test/integration/scep/common_test.go b/test/integration/scep/common_test.go new file mode 100644 index 00000000..86f64c3d --- /dev/null +++ b/test/integration/scep/common_test.go @@ -0,0 +1,273 @@ +package sceptest + +import ( + "context" + "crypto/rand" + "crypto/rsa" + "crypto/tls" + "crypto/x509" + "encoding/base64" + "errors" + "fmt" + "io" + "math/big" + "net" + "net/http" + "net/url" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/smallstep/pkcs7" + "github.com/smallstep/scep" + "go.step.sm/crypto/minica" + "go.step.sm/crypto/x509util" + + "github.com/smallstep/certificates/ca" + "github.com/smallstep/certificates/cas/apiv1" +) + +func newCAClient(t *testing.T, caURL, rootFilepath string) *ca.Client { + caClient, err := ca.NewClient( + caURL, + ca.WithRootFile(rootFilepath), + ) + require.NoError(t, err) + return caClient +} + +func requireHealthyCA(t *testing.T, caClient *ca.Client) { + ctx := context.Background() + healthResponse, err := caClient.HealthWithContext(ctx) + require.NoError(t, err) + if assert.NotNil(t, healthResponse) { + require.Equal(t, "ok", healthResponse.Status) + } +} + +// reservePort "reserves" a TCP port by opening a listener on a random +// port and immediately closing it. The port can then be assumed to be +// available for running a server on. +func reservePort(t *testing.T) (host, port string) { + t.Helper() + l, err := net.Listen("tcp", ":0") + require.NoError(t, err) + + address := l.Addr().String() + err = l.Close() + require.NoError(t, err) + + host, port, err = net.SplitHostPort(address) + require.NoError(t, err) + + return +} + +type client struct { + caURL string + caCert *x509.Certificate + httpClient *http.Client +} + +func createSCEPClient(t *testing.T, caURL string, root *x509.Certificate) *client { + t.Helper() + trustedRoots := x509.NewCertPool() + trustedRoots.AddCert(root) + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.TLSClientConfig = &tls.Config{ + RootCAs: trustedRoots, + } + httpClient := &http.Client{ + Transport: transport, + } + return &client{ + caURL: caURL, + httpClient: httpClient, + } +} + +func (c *client) getCACert(t *testing.T) error { + // return early if CA certificate already available + if c.caCert != nil { + return nil + } + + resp, err := c.httpClient.Get(fmt.Sprintf("%s?operation=GetCACert&message=test", c.caURL)) + if err != nil { + return fmt.Errorf("failed get request: %w", err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf("failed reading response body: %w", err) + } + + t.Log(string(body)) + + // SCEP CA/RA certificate selection. If there's only a single certificate, it will + // be used as the CA certificate at all times. If there's multiple, the first certificate + // is assumed to be the certificate of the recipient to encrypt messages to. + switch ct := resp.Header.Get("Content-Type"); ct { + case "application/x-x509-ca-cert": + cert, err := x509.ParseCertificate(body) + if err != nil { + return fmt.Errorf("failed parsing response body: %w", err) + } + if _, ok := cert.PublicKey.(*rsa.PublicKey); !ok { + return fmt.Errorf("certificate has unexpected public key type %T", cert.PublicKey) + } + c.caCert = cert + case "application/x-x509-ca-ra-cert": + certs, err := scep.CACerts(body) + if err != nil { + return fmt.Errorf("failed parsing response body: %w", err) + } + cert := certs[0] + if _, ok := cert.PublicKey.(*rsa.PublicKey); !ok { + return fmt.Errorf("certificate has unexpected public key type %T", cert.PublicKey) + } + c.caCert = cert + default: + return fmt.Errorf("unexpected content-type value %q", ct) + } + + return nil +} + +func (c *client) requestCertificate(t *testing.T, commonName string, sans []string) (*x509.Certificate, error) { + if err := c.getCACert(t); err != nil { + return nil, fmt.Errorf("failed getting CA certificate: %w", err) + } + + signer, err := rsa.GenerateKey(rand.Reader, 2048) + if err != nil { + return nil, fmt.Errorf("failed creating SCEP private key: %w", err) + } + + csr, err := x509util.CreateCertificateRequest(commonName, sans, signer) + if err != nil { + return nil, fmt.Errorf("failed creating CSR: %w", err) + } + + tmpl := &x509.Certificate{ + Subject: csr.Subject, + PublicKey: signer.Public(), + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-1 * time.Hour), + NotAfter: time.Now().Add(1 * time.Hour), + DNSNames: csr.DNSNames, + IPAddresses: csr.IPAddresses, + EmailAddresses: csr.EmailAddresses, + URIs: csr.URIs, + } + + selfSigned, err := x509.CreateCertificate(rand.Reader, tmpl, tmpl, signer.Public(), signer) + if err != nil { + return nil, fmt.Errorf("failed creating self signed certificate: %w", err) + } + selfSignedCertificate, err := x509.ParseCertificate(selfSigned) + if err != nil { + return nil, fmt.Errorf("failed parsing self signed certificate: %w", err) + } + + msgTmpl := &scep.PKIMessage{ + TransactionID: "test-1", + MessageType: scep.PKCSReq, + SenderNonce: []byte("test-nonce-1"), + Recipients: []*x509.Certificate{c.caCert}, + SignerCert: selfSignedCertificate, + SignerKey: signer, + } + + msg, err := scep.NewCSRRequest(csr, msgTmpl) + if err != nil { + return nil, fmt.Errorf("failed creating SCEP PKCSReq message: %w", err) + } + + t.Log(string(msg.Raw)) + + u, err := url.Parse(c.caURL) + if err != nil { + return nil, fmt.Errorf("failed parsing CA URL: %w", err) + } + + opURL := u.ResolveReference(&url.URL{RawQuery: fmt.Sprintf("operation=PKIOperation&message=%s", url.QueryEscape(base64.StdEncoding.EncodeToString(msg.Raw)))}) + resp, err := c.httpClient.Get(opURL.String()) + if err != nil { + return nil, fmt.Errorf("failed get request: %w", err) + } + defer resp.Body.Close() + + if ct := resp.Header.Get("Content-Type"); ct != "application/x-pki-message" { + return nil, fmt.Errorf("received unexpected content type %q", ct) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed reading response body: %w", err) + } + + t.Log(string(body)) + + signedData, err := pkcs7.Parse(body) + if err != nil { + return nil, fmt.Errorf("failed parsing response body: %w", err) + } + + // TODO: verify the signature? + + p7, err := pkcs7.Parse(signedData.Content) + if err != nil { + return nil, fmt.Errorf("failed decrypting inner p7: %w", err) + } + + content, err := p7.Decrypt(selfSignedCertificate, signer) + if err != nil { + return nil, fmt.Errorf("failed decrypting response: %w", err) + } + + p7, err = pkcs7.Parse(content) + if err != nil { + return nil, fmt.Errorf("failed parsing p7 content: %w", err) + } + + cert := p7.Certificates[0] + + return cert, nil +} + +type testCAS struct { + ca *minica.CA +} + +func (c *testCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1.CreateCertificateResponse, error) { + cert, err := c.ca.SignCSR(req.CSR) + if err != nil { + return nil, fmt.Errorf("failed signing CSR: %w", err) + } + + return &apiv1.CreateCertificateResponse{ + Certificate: cert, + CertificateChain: []*x509.Certificate{cert, c.ca.Intermediate}, + }, nil +} +func (c *testCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.RenewCertificateResponse, error) { + return nil, errors.New("not implemented") +} + +func (c *testCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) { + return nil, errors.New("not implemented") +} + +func (c *testCAS) GetCertificateAuthority(req *apiv1.GetCertificateAuthorityRequest) (*apiv1.GetCertificateAuthorityResponse, error) { + return &apiv1.GetCertificateAuthorityResponse{ + RootCertificate: c.ca.Root, + IntermediateCertificates: []*x509.Certificate{c.ca.Intermediate}, + }, nil +} + +var _ apiv1.CertificateAuthorityService = (*testCAS)(nil) +var _ apiv1.CertificateAuthorityGetter = (*testCAS)(nil) diff --git a/test/integration/scep/decrypter_cas_test.go b/test/integration/scep/decrypter_cas_test.go new file mode 100644 index 00000000..f19a2c91 --- /dev/null +++ b/test/integration/scep/decrypter_cas_test.go @@ -0,0 +1,149 @@ +package sceptest + +import ( + "context" + "crypto" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "fmt" + "math/big" + "net" + "net/http" + "path/filepath" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.step.sm/crypto/keyutil" + "go.step.sm/crypto/minica" + "go.step.sm/crypto/pemutil" + + "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/authority/provisioner" + "github.com/smallstep/certificates/ca" + "github.com/smallstep/certificates/cas/apiv1" +) + +func TestIssuesCertificateUsingSCEPWithDecrypterAndUpstreamCAS(t *testing.T) { + signer, err := keyutil.GenerateSigner("EC", "P-256", 0) + require.NoError(t, err) + + dir := t.TempDir() + m, err := minica.New(minica.WithName("Step E2E | SCEP Decrypter w/ Upstream CAS"), minica.WithGetSignerFunc(func() (crypto.Signer, error) { + return signer, nil + })) + require.NoError(t, err) + + rootFilepath := filepath.Join(dir, "root.crt") + _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) + require.NoError(t, err) + + intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") + _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) + require.NoError(t, err) + + intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") + _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) + require.NoError(t, err) + + decrypterKey, err := keyutil.GenerateKey("RSA", "", 2048) + require.NoError(t, err) + + decrypter, ok := decrypterKey.(crypto.Decrypter) + require.True(t, ok) + + decrypterCertifiate, err := m.Sign(&x509.Certificate{ + Subject: pkix.Name{CommonName: "decrypter"}, + PublicKey: decrypter.Public(), + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-1 * time.Hour), + NotAfter: time.Now().Add(1 * time.Hour), + DNSNames: []string{"decrypter"}, + }) + require.NoError(t, err) + + b, err := pemutil.Serialize(decrypterCertifiate) + require.NoError(t, err) + decrypterCertificatePEMBytes := pem.EncodeToMemory(b) + + b, err = pemutil.Serialize(decrypter, pemutil.WithPassword([]byte("1234"))) + require.NoError(t, err) + decrypterKeyPEMBytes := pem.EncodeToMemory(b) + + // get a random address to listen on and connect to; currently no nicer way to get one before starting the server + // TODO(hs): find/implement a nicer way to expose the CA URL, similar to how e.g. httptest.Server exposes it? + host, port := reservePort(t) + + prov := &provisioner.SCEP{ + ID: "scep", + Name: "scep", + Type: "SCEP", + ForceCN: false, + ChallengePassword: "", + EncryptionAlgorithmIdentifier: 2, + MinimumPublicKeyLength: 2048, + Claims: &config.GlobalProvisionerClaims, + DecrypterCertificate: decrypterCertificatePEMBytes, + DecrypterKeyPEM: decrypterKeyPEMBytes, + DecrypterKeyPassword: "1234", + } + + err = prov.Init(provisioner.Config{}) + require.NoError(t, err) + + apiv1.Register("test-scep-cas", func(_ context.Context, opts apiv1.Options) (apiv1.CertificateAuthorityService, error) { + return &testCAS{ + ca: m, + }, nil + }) + + cfg := &config.Config{ + Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" + DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, + AuthorityConfig: &config.AuthConfig{ + Options: &apiv1.Options{ + AuthorityID: "stepca-test-scep", + Type: "test-scep-cas", + CertificateAuthority: "test-cas", + }, + AuthorityID: "stepca-test-scep", + DeploymentType: "standalone-test", + Provisioners: provisioner.List{prov}, + }, + Logger: json.RawMessage(`{"format": "text"}`), + } + c, err := ca.New(cfg) + require.NoError(t, err) + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + err = c.Run() + require.ErrorIs(t, err, http.ErrServerClosed) + }() + + // instantiate a client for the CA running at the random address + caClient := newCAClient(t, fmt.Sprintf("https://localhost:%s", port), rootFilepath) + requireHealthyCA(t, caClient) + + scepClient := createSCEPClient(t, fmt.Sprintf("https://localhost:%s/scep/scep", port), m.Root) + cert, err := scepClient.requestCertificate(t, "test.localhost", []string{"test.localhost"}) + assert.NoError(t, err) + require.NotNil(t, cert) + + assert.Equal(t, "test.localhost", cert.Subject.CommonName) + assert.Equal(t, "Step E2E | SCEP Decrypter w/ Upstream CAS Intermediate CA", cert.Issuer.CommonName) + + // done testing; stop and wait for the server to quit + err = c.Stop() + require.NoError(t, err) + + wg.Wait() +} diff --git a/test/integration/scep/decrypter_test.go b/test/integration/scep/decrypter_test.go new file mode 100644 index 00000000..f59ae8b1 --- /dev/null +++ b/test/integration/scep/decrypter_test.go @@ -0,0 +1,139 @@ +package sceptest + +import ( + "crypto" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "fmt" + "math/big" + "net" + "net/http" + "path/filepath" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.step.sm/crypto/keyutil" + "go.step.sm/crypto/minica" + "go.step.sm/crypto/pemutil" + + "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/authority/provisioner" + "github.com/smallstep/certificates/ca" +) + +func TestIssuesCertificateUsingSCEPWithDecrypter(t *testing.T) { + signer, err := keyutil.GenerateSigner("EC", "P-256", 0) + require.NoError(t, err) + + dir := t.TempDir() + m, err := minica.New(minica.WithName("Step E2E | SCEP Decrypter"), minica.WithGetSignerFunc(func() (crypto.Signer, error) { + return signer, nil + })) + require.NoError(t, err) + + rootFilepath := filepath.Join(dir, "root.crt") + _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) + require.NoError(t, err) + + intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") + _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) + require.NoError(t, err) + + intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") + _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) + require.NoError(t, err) + + decrypterKey, err := keyutil.GenerateKey("RSA", "", 2048) + require.NoError(t, err) + + decrypter, ok := decrypterKey.(crypto.Decrypter) + require.True(t, ok) + + decrypterCertifiate, err := m.Sign(&x509.Certificate{ + Subject: pkix.Name{CommonName: "decrypter"}, + PublicKey: decrypter.Public(), + SerialNumber: big.NewInt(1), + NotBefore: time.Now().Add(-1 * time.Hour), + NotAfter: time.Now().Add(1 * time.Hour), + DNSNames: []string{"decrypter"}, + }) + require.NoError(t, err) + + b, err := pemutil.Serialize(decrypterCertifiate) + require.NoError(t, err) + decrypterCertificatePEMBytes := pem.EncodeToMemory(b) + + b, err = pemutil.Serialize(decrypter, pemutil.WithPassword([]byte("1234"))) + require.NoError(t, err) + decrypterKeyPEMBytes := pem.EncodeToMemory(b) + + // get a random address to listen on and connect to; currently no nicer way to get one before starting the server + // TODO(hs): find/implement a nicer way to expose the CA URL, similar to how e.g. httptest.Server exposes it? + host, port := reservePort(t) + + prov := &provisioner.SCEP{ + ID: "scep", + Name: "scep", + Type: "SCEP", + ForceCN: false, + ChallengePassword: "", + EncryptionAlgorithmIdentifier: 2, + MinimumPublicKeyLength: 2048, + Claims: &config.GlobalProvisionerClaims, + DecrypterCertificate: decrypterCertificatePEMBytes, + DecrypterKeyPEM: decrypterKeyPEMBytes, + DecrypterKeyPassword: "1234", + } + + err = prov.Init(provisioner.Config{}) + require.NoError(t, err) + + cfg := &config.Config{ + Root: []string{rootFilepath}, + IntermediateCert: intermediateCertFilepath, + IntermediateKey: intermediateKeyFilepath, + Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" + DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, + AuthorityConfig: &config.AuthConfig{ + AuthorityID: "stepca-test-scep", + DeploymentType: "standalone-test", + Provisioners: provisioner.List{prov}, + }, + Logger: json.RawMessage(`{"format": "text"}`), + } + c, err := ca.New(cfg) + require.NoError(t, err) + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + err = c.Run() + require.ErrorIs(t, err, http.ErrServerClosed) + }() + + // instantiate a client for the CA running at the random address + caClient := newCAClient(t, fmt.Sprintf("https://localhost:%s", port), rootFilepath) + requireHealthyCA(t, caClient) + + scepClient := createSCEPClient(t, fmt.Sprintf("https://localhost:%s/scep/scep", port), m.Root) + cert, err := scepClient.requestCertificate(t, "test.localhost", []string{"test.localhost"}) + assert.NoError(t, err) + require.NotNil(t, cert) + + assert.Equal(t, "test.localhost", cert.Subject.CommonName) + assert.Equal(t, "Step E2E | SCEP Decrypter Intermediate CA", cert.Issuer.CommonName) + + // done testing; stop and wait for the server to quit + err = c.Stop() + require.NoError(t, err) + + wg.Wait() +} diff --git a/test/integration/scep/regular_cas_test.go b/test/integration/scep/regular_cas_test.go new file mode 100644 index 00000000..ae5ebbfd --- /dev/null +++ b/test/integration/scep/regular_cas_test.go @@ -0,0 +1,116 @@ +package sceptest + +import ( + "context" + "crypto" + "encoding/json" + "fmt" + "net" + "net/http" + "path/filepath" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.step.sm/crypto/keyutil" + "go.step.sm/crypto/minica" + "go.step.sm/crypto/pemutil" + + "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/authority/provisioner" + "github.com/smallstep/certificates/ca" + "github.com/smallstep/certificates/cas/apiv1" +) + +func TestFailsIssuingCertificateUsingRegularSCEPWithUpstreamCAS(t *testing.T) { + signer, err := keyutil.GenerateSigner("RSA", "", 2048) + require.NoError(t, err) + + dir := t.TempDir() + m, err := minica.New(minica.WithName("Step E2E | SCEP Regular w/ Upstream CAS"), minica.WithGetSignerFunc(func() (crypto.Signer, error) { + return signer, nil + })) + require.NoError(t, err) + + rootFilepath := filepath.Join(dir, "root.crt") + _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) + require.NoError(t, err) + + intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") + _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) + require.NoError(t, err) + + intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") + _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) + require.NoError(t, err) + + // get a random address to listen on and connect to; currently no nicer way to get one before starting the server + // TODO(hs): find/implement a nicer way to expose the CA URL, similar to how e.g. httptest.Server exposes it? + host, port := reservePort(t) + + prov := &provisioner.SCEP{ + ID: "scep", + Name: "scep", + Type: "SCEP", + ForceCN: false, + ChallengePassword: "", + EncryptionAlgorithmIdentifier: 2, + MinimumPublicKeyLength: 2048, + Claims: &config.GlobalProvisionerClaims, + } + + err = prov.Init(provisioner.Config{}) + require.NoError(t, err) + + apiv1.Register("test-scep-cas", func(_ context.Context, opts apiv1.Options) (apiv1.CertificateAuthorityService, error) { + return &testCAS{ + ca: m, + }, nil + }) + + cfg := &config.Config{ + Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" + DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, + AuthorityConfig: &config.AuthConfig{ + Options: &apiv1.Options{ + AuthorityID: "stepca-test-scep", + Type: "test-scep-cas", + CertificateAuthority: "test-cas", + }, + AuthorityID: "stepca-test-scep", + DeploymentType: "standalone-test", + Provisioners: provisioner.List{prov}, + }, + Logger: json.RawMessage(`{"format": "text"}`), + } + c, err := ca.New(cfg) + require.NoError(t, err) + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + err = c.Run() + require.ErrorIs(t, err, http.ErrServerClosed) + }() + + // instantiate a client for the CA running at the random address + caClient := newCAClient(t, fmt.Sprintf("https://localhost:%s", port), rootFilepath) + requireHealthyCA(t, caClient) + + // issuance is expected to fail when an upstream CAS is configured, as the current + // CAS interfaces do not support providing a decrypter. + scepClient := createSCEPClient(t, fmt.Sprintf("https://localhost:%s/scep/scep", port), m.Root) + cert, err := scepClient.requestCertificate(t, "test.localhost", []string{"test.localhost"}) + assert.Error(t, err) + assert.Nil(t, cert) + + // done testing; stop and wait for the server to quit + err = c.Stop() + require.NoError(t, err) + + wg.Wait() +} diff --git a/test/integration/scep/regular_test.go b/test/integration/scep/regular_test.go new file mode 100644 index 00000000..fc2d4d58 --- /dev/null +++ b/test/integration/scep/regular_test.go @@ -0,0 +1,107 @@ +package sceptest + +import ( + "crypto" + "encoding/json" + "fmt" + "net" + "net/http" + "path/filepath" + "sync" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "go.step.sm/crypto/keyutil" + "go.step.sm/crypto/minica" + "go.step.sm/crypto/pemutil" + + "github.com/smallstep/certificates/authority/config" + "github.com/smallstep/certificates/authority/provisioner" + "github.com/smallstep/certificates/ca" +) + +func TestIssuesCertificateUsingRegularSCEPConfiguration(t *testing.T) { + signer, err := keyutil.GenerateSigner("RSA", "", 2048) + require.NoError(t, err) + + dir := t.TempDir() + m, err := minica.New(minica.WithName("Step E2E | SCEP Regular"), minica.WithGetSignerFunc(func() (crypto.Signer, error) { + return signer, nil + })) + require.NoError(t, err) + + rootFilepath := filepath.Join(dir, "root.crt") + _, err = pemutil.Serialize(m.Root, pemutil.WithFilename(rootFilepath)) + require.NoError(t, err) + + intermediateCertFilepath := filepath.Join(dir, "intermediate.crt") + _, err = pemutil.Serialize(m.Intermediate, pemutil.WithFilename(intermediateCertFilepath)) + require.NoError(t, err) + + intermediateKeyFilepath := filepath.Join(dir, "intermediate.key") + _, err = pemutil.Serialize(m.Signer, pemutil.WithFilename(intermediateKeyFilepath)) + require.NoError(t, err) + + // get a random address to listen on and connect to; currently no nicer way to get one before starting the server + // TODO(hs): find/implement a nicer way to expose the CA URL, similar to how e.g. httptest.Server exposes it? + host, port := reservePort(t) + + prov := &provisioner.SCEP{ + ID: "scep", + Name: "scep", + Type: "SCEP", + ForceCN: false, + ChallengePassword: "", + EncryptionAlgorithmIdentifier: 2, + MinimumPublicKeyLength: 2048, + Claims: &config.GlobalProvisionerClaims, + } + + err = prov.Init(provisioner.Config{}) + require.NoError(t, err) + + cfg := &config.Config{ + Root: []string{rootFilepath}, + IntermediateCert: intermediateCertFilepath, + IntermediateKey: intermediateKeyFilepath, + Address: net.JoinHostPort(host, port), // reuse the address that was just "reserved" + DNSNames: []string{"127.0.0.1", "[::1]", "localhost"}, + AuthorityConfig: &config.AuthConfig{ + AuthorityID: "stepca-test-scep", + DeploymentType: "standalone-test", + Provisioners: provisioner.List{prov}, + }, + Logger: json.RawMessage(`{"format": "text"}`), + } + c, err := ca.New(cfg) + require.NoError(t, err) + + var wg sync.WaitGroup + wg.Add(1) + + go func() { + defer wg.Done() + err = c.Run() + require.ErrorIs(t, err, http.ErrServerClosed) + }() + + // instantiate a client for the CA running at the random address + caClient := newCAClient(t, fmt.Sprintf("https://localhost:%s", port), rootFilepath) + requireHealthyCA(t, caClient) + + scepClient := createSCEPClient(t, fmt.Sprintf("https://localhost:%s/scep/scep", port), m.Root) + cert, err := scepClient.requestCertificate(t, "test.localhost", []string{"test.localhost"}) + assert.NoError(t, err) + require.NotNil(t, cert) + + assert.Equal(t, "test.localhost", cert.Subject.CommonName) + assert.Equal(t, "Step E2E | SCEP Regular Intermediate CA", cert.Issuer.CommonName) + + // done testing; stop and wait for the server to quit + err = c.Stop() + require.NoError(t, err) + + wg.Wait() +}