From abe86002ee9ea35f069c5d56562a2e1e3e30cc77 Mon Sep 17 00:00:00 2001 From: beltram Date: Tue, 16 May 2023 14:33:11 +0200 Subject: [PATCH] try by storing everything in db --- acme/challenge.go | 27 ++++++++++++++++++-- acme/db.go | 3 +++ acme/db/nosql/nosql.go | 1 + acme/db/nosql/wire.go | 58 ++++++++++++++++++++++++++++++++++++++++++ acme/order.go | 17 +++++++++++++ 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 acme/db/nosql/wire.go diff --git a/acme/challenge.go b/acme/challenge.go index 4fa01f13..2fb438ec 100644 --- a/acme/challenge.go +++ b/acme/challenge.go @@ -18,7 +18,6 @@ import ( "encoding/json" "errors" "fmt" - "gopkg.in/square/go-jose.v2/jwt" "io" "net" "net/url" @@ -30,6 +29,8 @@ import ( "strings" "time" + "gopkg.in/square/go-jose.v2/jwt" + "github.com/fxamacker/cbor/v2" "github.com/google/go-tpm/legacy/tpm2" "github.com/smallstep/go-attestation/attest" @@ -537,7 +538,6 @@ func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSO return WrapErrorISE(err, "error updating challenge") } - //var access := wireChallengePayload.AccessToken parsedAccessToken, err := jwt.ParseSigned(wireChallengePayload.AccessToken) if err != nil { return WrapErrorISE(err, "Invalid access token") @@ -549,6 +549,29 @@ func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSO ctx = context.WithValue(ctx, "access", access) + rawDpop, ok := access["proof"].(string) + if !ok { + return WrapErrorISE(err, "Invalid dpop proof format in access token") + } + + parsedDpopToken, err := jwt.ParseSigned(rawDpop) + if err != nil { + return WrapErrorISE(err, "Invalid DPoP token") + } + dpop := make(map[string]interface{}) + if err := parsedAccessToken.UnsafeClaimsWithoutVerification(&parsedDpopToken); err != nil { + return WrapErrorISE(err, "Failed parsing dpop token") + } + + order, err := db.GetOrdersByAccountID(ctx, ch.AccountID) + if err != nil { + return WrapErrorISE(err, "Could not find current order by account id") + } + + if err := db.CreateDpop(ctx, order[0], dpop); err != nil { + return WrapErrorISE(err, "Failed storing DPoP token") + } + return nil } diff --git a/acme/db.go b/acme/db.go index 4cbb3089..f14b67f8 100644 --- a/acme/db.go +++ b/acme/db.go @@ -53,6 +53,9 @@ type DB interface { GetOrder(ctx context.Context, id string) (*Order, error) GetOrdersByAccountID(ctx context.Context, accountID string) ([]string, error) UpdateOrder(ctx context.Context, o *Order) error + + CreateDpop(ctx context.Context, orderId string, dpop map[string]interface{}) error + GetDpop(ctx context.Context, orderId string) (map[string]interface{}, error) } type dbKey struct{} diff --git a/acme/db/nosql/nosql.go b/acme/db/nosql/nosql.go index d19e2987..5a0cb1f6 100644 --- a/acme/db/nosql/nosql.go +++ b/acme/db/nosql/nosql.go @@ -23,6 +23,7 @@ var ( externalAccountKeyTable = []byte("acme_external_account_keys") externalAccountKeyIDsByReferenceTable = []byte("acme_external_account_keyID_reference_index") externalAccountKeyIDsByProvisionerIDTable = []byte("acme_external_account_keyID_provisionerID_index") + dpopTable = []byte("acme_dpop") ) // DB is a struct that implements the AcmeDB interface. diff --git a/acme/db/nosql/wire.go b/acme/db/nosql/wire.go new file mode 100644 index 00000000..5cad6f0a --- /dev/null +++ b/acme/db/nosql/wire.go @@ -0,0 +1,58 @@ +package nosql + +import ( + "context" + "encoding/json" + "time" + + "github.com/pkg/errors" + "github.com/smallstep/certificates/acme" + "github.com/smallstep/nosql" +) + +type dbDpop struct { + ID string `json:"id"` + Content map[string]interface{} `json:"content"` + CreatedAt time.Time `json:"createdAt"` +} + +// getDBDpop retrieves and unmarshals an DPoP type from the database. +func (db *DB) getDBDpop(ctx context.Context, orderId string) (*dbDpop, error) { + b, err := db.db.Get(dpopTable, []byte(orderId)) + if nosql.IsErrNotFound(err) { + return nil, acme.NewError(acme.ErrorMalformedType, "dpop %s not found", orderId) + } else if err != nil { + return nil, errors.Wrapf(err, "error loading dpop %s", orderId) + } + o := new(dbDpop) + if err := json.Unmarshal(b, &o); err != nil { + return nil, errors.Wrapf(err, "error unmarshaling dpop %s into dbDpop", orderId) + } + return o, nil +} + +// GetDpop retrieves an DPoP from the database. +func (db *DB) GetDpop(ctx context.Context, orderId string) (map[string]interface{}, error) { + dbDpop, err := db.getDBDpop(ctx, orderId) + if err != nil { + return nil, err + } + + dpop := dbDpop.Content + + return dpop, nil +} + +// CreateDpop creates DPoP resources and saves them to the DB. +func (db *DB) CreateDpop(ctx context.Context, orderId string, dpop map[string]interface{}) error { + now := clock.Now() + dbDpop := &dbDpop{ + ID: orderId, + Content: dpop, + CreatedAt: now, + } + if err := db.save(ctx, orderId, dbDpop, nil, "dpop", dpopTable); err != nil { + return err + } + return nil +} diff --git a/acme/order.go b/acme/order.go index c404acd6..6d0a240d 100644 --- a/acme/order.go +++ b/acme/order.go @@ -208,6 +208,23 @@ func (o *Order) Finalize(ctx context.Context, db DB, csr *x509.CertificateReques } data.SetSubject(subject) + dpop, err := db.GetDpop(ctx, o.ID) + if err != nil { + return err + } + data.Set("Dpop", dpop) + + // inject the raw access token as template variable + /* + log.Printf(">> json raw content %v", ctx.Value(wire.AccessTokenKey{})) + access, ok := ctx.Value(wire.AccessTokenKey{}).(map[string]interface{}) + if !ok { + return WrapErrorISE(err, "Invalid or absent access in context") + } + if access == nil { + return WrapErrorISE(err, "Access was nil in context") + }*/ + /*// inject the raw dpop token as template variable dpop, ok := ctx.Value("dpop").(map[string]interface{}) if !ok {