mirror of
https://github.com/smallstep/certificates.git
synced 2024-10-31 03:20:16 +00:00
Merge branch 'herman/scep-provisioner-decrypter' of github.com:smallstep/certificates into herman/scep-provisioner-decrypter
This commit is contained in:
commit
a3c9dd796a
@ -143,12 +143,14 @@ var (
|
||||
// that case, the other webhooks will be skipped. If none of
|
||||
// the webhooks indicates the value of the challenge was accepted,
|
||||
// an error is returned.
|
||||
func (c *challengeValidationController) Validate(ctx context.Context, challenge, transactionID string) error {
|
||||
func (c *challengeValidationController) Validate(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error {
|
||||
for _, wh := range c.webhooks {
|
||||
req := &webhook.RequestBody{
|
||||
SCEPChallenge: challenge,
|
||||
SCEPTransactionID: transactionID,
|
||||
req, err := webhook.NewRequestBody(webhook.WithX509CertificateRequest(csr))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed creating new webhook request: %w", err)
|
||||
}
|
||||
req.SCEPChallenge = challenge
|
||||
req.SCEPTransactionID = transactionID
|
||||
resp, err := wh.DoWithContext(ctx, c.client, req, nil) // TODO(hs): support templated URL? Requires some refactoring
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed executing webhook request: %w", err)
|
||||
@ -329,13 +331,13 @@ func (s *SCEP) GetContentEncryptionAlgorithm() int {
|
||||
// ValidateChallenge validates the provided challenge. It starts by
|
||||
// selecting the validation method to use, then performs validation
|
||||
// according to that method.
|
||||
func (s *SCEP) ValidateChallenge(ctx context.Context, challenge, transactionID string) error {
|
||||
func (s *SCEP) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error {
|
||||
if s.challengeValidationController == nil {
|
||||
return fmt.Errorf("provisioner %q wasn't initialized", s.Name)
|
||||
}
|
||||
switch s.selectValidationMethod() {
|
||||
case validationMethodWebhook:
|
||||
return s.challengeValidationController.Validate(ctx, challenge, transactionID)
|
||||
return s.challengeValidationController.Validate(ctx, csr, challenge, transactionID)
|
||||
default:
|
||||
if subtle.ConstantTimeCompare([]byte(s.ChallengePassword), []byte(challenge)) == 0 {
|
||||
return errors.New("invalid challenge password provided")
|
||||
|
@ -2,6 +2,7 @@ package provisioner
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
@ -12,12 +13,18 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"go.step.sm/linkedca"
|
||||
|
||||
"github.com/smallstep/certificates/webhook"
|
||||
)
|
||||
|
||||
func Test_challengeValidationController_Validate(t *testing.T) {
|
||||
dummyCSR := &x509.CertificateRequest{
|
||||
Raw: []byte{1},
|
||||
}
|
||||
type request struct {
|
||||
Challenge string `json:"scepChallenge"`
|
||||
TransactionID string `json:"scepTransactionID"`
|
||||
Request *webhook.X509CertificateRequest `json:"x509CertificateRequest,omitempty"`
|
||||
Challenge string `json:"scepChallenge"`
|
||||
TransactionID string `json:"scepTransactionID"`
|
||||
}
|
||||
type response struct {
|
||||
Allow bool `json:"allow"`
|
||||
@ -39,6 +46,9 @@ func Test_challengeValidationController_Validate(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "challenge", req.Challenge)
|
||||
assert.Equal(t, "transaction-1", req.TransactionID)
|
||||
if assert.NotNil(t, req.Request) {
|
||||
assert.Equal(t, []byte{1}, req.Request.Raw)
|
||||
}
|
||||
b, err := json.Marshal(response{Allow: true})
|
||||
require.NoError(t, err)
|
||||
w.WriteHeader(200)
|
||||
@ -141,7 +151,7 @@ func Test_challengeValidationController_Validate(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
err := c.Validate(ctx, tt.args.challenge, tt.args.transactionID)
|
||||
err := c.Validate(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID)
|
||||
|
||||
if tt.expErr != nil {
|
||||
assert.EqualError(t, err, tt.expErr.Error())
|
||||
@ -221,9 +231,13 @@ func Test_selectValidationMethod(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSCEP_ValidateChallenge(t *testing.T) {
|
||||
dummyCSR := &x509.CertificateRequest{
|
||||
Raw: []byte{1},
|
||||
}
|
||||
type request struct {
|
||||
Challenge string `json:"scepChallenge"`
|
||||
TransactionID string `json:"scepTransactionID"`
|
||||
Request *webhook.X509CertificateRequest `json:"x509CertificateRequest,omitempty"`
|
||||
Challenge string `json:"scepChallenge"`
|
||||
TransactionID string `json:"scepTransactionID"`
|
||||
}
|
||||
type response struct {
|
||||
Allow bool `json:"allow"`
|
||||
@ -234,6 +248,9 @@ func TestSCEP_ValidateChallenge(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "webhook-challenge", req.Challenge)
|
||||
assert.Equal(t, "webhook-transaction-1", req.TransactionID)
|
||||
if assert.NotNil(t, req.Request) {
|
||||
assert.Equal(t, []byte{1}, req.Request.Raw)
|
||||
}
|
||||
b, err := json.Marshal(response{Allow: true})
|
||||
require.NoError(t, err)
|
||||
w.WriteHeader(200)
|
||||
@ -330,7 +347,7 @@ func TestSCEP_ValidateChallenge(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
ctx := context.Background()
|
||||
|
||||
err = tt.p.ValidateChallenge(ctx, tt.args.challenge, tt.args.transactionID)
|
||||
err = tt.p.ValidateChallenge(ctx, dummyCSR, tt.args.challenge, tt.args.transactionID)
|
||||
if tt.expErr != nil {
|
||||
assert.EqualError(t, err, tt.expErr.Error())
|
||||
return
|
||||
|
@ -315,7 +315,7 @@ func PKIOperation(ctx context.Context, req request) (Response, error) {
|
||||
// a certificate exists; then it will use RenewalReq. Adding the challenge check here may be a small breaking change for clients.
|
||||
// We'll have to see how it works out.
|
||||
if msg.MessageType == microscep.PKCSReq || msg.MessageType == microscep.RenewalReq {
|
||||
if err := auth.ValidateChallenge(ctx, challengePassword, transactionID); err != nil {
|
||||
if err := auth.ValidateChallenge(ctx, csr, challengePassword, transactionID); err != nil {
|
||||
if errors.Is(err, provisioner.ErrSCEPChallengeInvalid) {
|
||||
return createFailureResponse(ctx, csr, msg, microscep.BadRequest, err)
|
||||
}
|
||||
|
@ -503,9 +503,9 @@ func (a *Authority) GetCACaps(ctx context.Context) []string {
|
||||
return caps
|
||||
}
|
||||
|
||||
func (a *Authority) ValidateChallenge(ctx context.Context, challenge, transactionID string) error {
|
||||
func (a *Authority) ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error {
|
||||
p := provisionerFromContext(ctx)
|
||||
return p.ValidateChallenge(ctx, challenge, transactionID)
|
||||
return p.ValidateChallenge(ctx, csr, challenge, transactionID)
|
||||
}
|
||||
|
||||
func (a *Authority) selectDecrypter(ctx context.Context) (cert *x509.Certificate, decrypter crypto.Decrypter, err error) {
|
||||
|
@ -20,7 +20,7 @@ type Provisioner interface {
|
||||
GetDecrypter() (*x509.Certificate, crypto.Decrypter)
|
||||
GetSigner() (*x509.Certificate, crypto.Signer)
|
||||
GetContentEncryptionAlgorithm() int
|
||||
ValidateChallenge(ctx context.Context, challenge, transactionID string) error
|
||||
ValidateChallenge(ctx context.Context, csr *x509.CertificateRequest, challenge, transactionID string) error
|
||||
}
|
||||
|
||||
// provisionerKey is the key type for storing and searching a
|
||||
|
Loading…
Reference in New Issue
Block a user