Skip to content

Commit

Permalink
feat: separate future and expired checks
Browse files Browse the repository at this point in the history
As the RFC says that proofs signed in the future MAY be accepted, the default behavior should then be that a proof signed in the future should NOT be accepted. [See section 11.1-4](https://datatracker.ietf.org/doc/html/rfc9449#section-11.1-4)

This PR adds a new default value for allowed proof age, `DEFAULT_ALLOWED_PROOF_AGE`, that is set to a more generous 5 minutes. It also changes the existing default time window into the future to 0 seconds.

Now if a `TimeWindow` is not set in the `ParseOptions`, future proofs will all be rejected. The functionality to control how long a proof is allowed to live is controlled by the new parse option `AllowedProofAge`.
  • Loading branch information
SalladinBalwer committed Jun 25, 2024
1 parent dbf4ecf commit 6599f44
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 44 deletions.
17 changes: 11 additions & 6 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ const (
CONNECT HTTPVerb = "CONNECT"
)

const DEFAULT_TIME_WINDOW = time.Second * 30
const DEFAULT_ALLOWED_PROOF_AGE = time.Minute * 5
const DEFAULT_ALLOWED_TIME_WINDOW = time.Second * 0

// ParseOptions and its contents are optional for the Parse function.
type ParseOptions struct {
Expand All @@ -45,9 +46,12 @@ type ParseOptions struct {
// If set to true the authorization server has to validate the nonce timestamp itself.
NonceHasTimestamp bool

// The allowed clock-skew on the `iat` of the proof. Defaults to 1 minute if not specified.
// The allowed clock-skew (into the future) on the `iat` of the proof. If not set proof is rejected if issued in the future.
TimeWindow *time.Duration

// The allowed age of a proof. If not set the default is 5 minutes.
AllowedProofAge *time.Duration

// dpop_jkt parameter that is optionally sent by the client to the authorization server on token request.
// If set the proof proof-of-possession public key needs to match or the proof is rejected.
JKT string
Expand Down Expand Up @@ -107,16 +111,16 @@ func Parse(
// This satisfies point 11 in https://datatracker.ietf.org/doc/html/rfc9449#section-4.3
if !opts.NonceHasTimestamp {
// Check that `iat` is not too far into the past.
past := DEFAULT_TIME_WINDOW
if opts.TimeWindow != nil {
past = *opts.TimeWindow
past := DEFAULT_ALLOWED_PROOF_AGE
if opts.AllowedProofAge != nil {
past = *opts.AllowedProofAge
}
if claims.IssuedAt.Before(time.Now().Add(-past)) {
return nil, errors.Join(ErrInvalidProof, ErrExpired)
}

// Check that `iat` is not too far into the future.
future := DEFAULT_TIME_WINDOW
future := DEFAULT_ALLOWED_TIME_WINDOW
if opts.TimeWindow != nil {
future = *opts.TimeWindow
}
Expand All @@ -130,6 +134,7 @@ func Parse(
// without the need for extracting and hashing it again.
jwk, ok := dpopToken.Header["jwk"].(map[string]interface{})
if !ok {
// keyFunc used with parseWithClaims should ensure that this can not happen but better safe than sorry.
return nil, ErrMissingJWK
}
jwkJSONbytes, err := getThumbprintableJwkJSONbytes(jwk)
Expand Down
Loading

0 comments on commit 6599f44

Please sign in to comment.