Change `kid` and `dpop` validation

pull/1672/head
Herman Slatman 4 months ago
parent 3f37feae78
commit 9bb1b24bf1
No known key found for this signature in database
GPG Key ID: F4D8A44EA0A75A4F

@ -352,9 +352,9 @@ func dns01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebK
type wireOidcPayload struct {
// IDToken contains the OIDC identity token
IDToken string `json:"id_token,omitempty"`
IDToken string `json:"id_token"`
// KeyAuth ({challenge-token}.{jwk-thumbprint})
KeyAuth string `json:"keyauth,omitempty"`
KeyAuth string `json:"keyauth"`
}
func wireOIDC01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, payload []byte) error {
@ -448,7 +448,7 @@ func wireOIDC01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSO
type wireDpopPayload struct {
// AccessToken is the token generated by wire-server
AccessToken string `json:"access_token,omitempty"`
AccessToken string `json:"access_token"`
}
func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, accountJWK *jose.JSONWebKey, payload []byte) error {
@ -484,13 +484,14 @@ func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, accountJWK *j
return WrapErrorISE(err, "invalid Go template registered for 'target'")
}
params := verifyParams{
params := wireVerifyParams{
token: dpopPayload.AccessToken,
tokenKey: dpopOptions.GetSigningKey(),
dpopKey: accountJWK,
dpopKey: accountJWK.Public(),
dpopKeyID: accountJWK.KeyID,
issuer: issuer,
wireID: wireID,
challenge: ch,
chToken: ch.Token,
t: clock.Now().UTC(),
}
_, dpop, err := parseAndVerifyWireAccessToken(params)
@ -523,33 +524,34 @@ func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, accountJWK *j
return nil
}
type cnf struct {
Kid string `json:"kid,omitempty"`
type wireCnf struct {
Kid string `json:"kid"`
}
type wireAccessToken struct {
jose.Claims
Challenge string `json:"chal,omitempty"`
Cnf *cnf `json:"cnf,omitempty"`
Proof string `json:"proof,omitempty"`
ClientID string `json:"client_id,omitempty"`
APIVersion int `json:"api_version,omitempty"`
Scope string `json:"scope,omitempty"`
Challenge string `json:"chal"`
Cnf wireCnf `json:"cnf"`
Proof string `json:"proof"`
ClientID string `json:"client_id"`
APIVersion int `json:"api_version"`
Scope string `json:"scope"`
}
type wireDpopToken map[string]any
type verifyParams struct {
type wireVerifyParams struct {
token string
tokenKey crypto.PublicKey
dpopKey *jose.JSONWebKey
dpopKey crypto.PublicKey
dpopKeyID string
issuer string
wireID wire.ID
challenge *Challenge
chToken string
t time.Time
}
func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopToken, error) {
func parseAndVerifyWireAccessToken(v wireVerifyParams) (*wireAccessToken, *wireDpopToken, error) {
jwt, err := jose.ParseSigned(v.token)
if err != nil {
return nil, nil, fmt.Errorf("failed parsing token: %w", err)
@ -567,17 +569,8 @@ func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopT
return nil, nil, fmt.Errorf("failed validation: %w", err)
}
rawKid, err := v.dpopKey.Thumbprint(crypto.SHA256)
if err != nil {
return nil, nil, fmt.Errorf("failed to compute JWK thumbprint")
}
kid := base64.RawURLEncoding.EncodeToString(rawKid)
if accessToken.Cnf == nil {
return nil, nil, errors.New("'cnf' is nil")
}
if accessToken.Cnf.Kid != kid {
return nil, nil, fmt.Errorf("expected kid %q; got %q", kid, accessToken.Cnf.Kid)
if accessToken.Cnf.Kid != v.dpopKeyID {
return nil, nil, fmt.Errorf("expected kid %q; got %q", v.dpopKeyID, accessToken.Cnf.Kid)
}
if accessToken.ClientID != v.wireID.ClientID {
return nil, nil, fmt.Errorf("invalid Wire client ID %q", accessToken.ClientID)
@ -591,7 +584,7 @@ func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopT
return nil, nil, fmt.Errorf("invalid Wire DPoP token: %w", err)
}
var dpopToken wireDpopToken
if err := dpopJWT.Claims(v.dpopKey.Key, &dpopToken); err != nil {
if err := dpopJWT.Claims(v.dpopKey, &dpopToken); err != nil {
return nil, nil, fmt.Errorf("failed validating Wire DPoP token claims: %w", err)
}
@ -599,7 +592,7 @@ func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopT
if !ok {
return nil, nil, fmt.Errorf("invalid challenge in Wire DPoP token")
}
if challenge != v.challenge.Token {
if challenge != v.chToken {
return nil, nil, fmt.Errorf("invalid Wire DPoP challenge %q", challenge)
}

@ -4332,13 +4332,18 @@ MCowBQYDK2VwAyEAB2IYqBWXAouDt3WcCZgCM3t9gumMEKMlgMsGenSu+fA=
var accountJWK jose.JSONWebKey
json.Unmarshal(jwkBytes, &accountJWK)
at, dpop, err := parseAndVerifyWireAccessToken(verifyParams{
rawKid, err := accountJWK.Thumbprint(crypto.SHA256)
require.NoError(t, err)
accountJWK.KeyID = base64.RawURLEncoding.EncodeToString(rawKid)
at, dpop, err := parseAndVerifyWireAccessToken(wireVerifyParams{
token: token,
tokenKey: publicKey,
dpopKey: &accountJWK,
dpopKey: accountJWK.Public(),
dpopKeyID: accountJWK.KeyID,
issuer: issuer,
wireID: wireID,
challenge: ch,
chToken: ch.Token,
t: issuedAt.Add(1 * time.Minute), // set validation time to be one minute after issuance
})
if assert.NoError(t, err) {

Loading…
Cancel
Save