|
|
@ -446,18 +446,12 @@ type wireDpopPayload struct {
|
|
|
|
AccessToken string `json:"access_token,omitempty"`
|
|
|
|
AccessToken string `json:"access_token,omitempty"`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSONWebKey, payload []byte) error {
|
|
|
|
func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, accountJWK *jose.JSONWebKey, payload []byte) error {
|
|
|
|
prov, ok := ProvisionerFromContext(ctx)
|
|
|
|
prov, ok := ProvisionerFromContext(ctx)
|
|
|
|
if !ok {
|
|
|
|
if !ok {
|
|
|
|
return NewErrorISE("missing provisioner")
|
|
|
|
return NewErrorISE("missing provisioner")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
rawKid, err := jwk.Thumbprint(crypto.SHA256)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return storeError(ctx, db, ch, false, WrapError(ErrorServerInternalType, err, "failed to compute JWK thumbprint"))
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
kid := base64.RawURLEncoding.EncodeToString(rawKid)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var dpopPayload wireDpopPayload
|
|
|
|
var dpopPayload wireDpopPayload
|
|
|
|
if err := json.Unmarshal(payload, &dpopPayload); err != nil {
|
|
|
|
if err := json.Unmarshal(payload, &dpopPayload); err != nil {
|
|
|
|
return storeError(ctx, db, ch, false, WrapError(ErrorRejectedIdentifierType, err,
|
|
|
|
return storeError(ctx, db, ch, false, WrapError(ErrorRejectedIdentifierType, err,
|
|
|
@ -475,17 +469,15 @@ func wireDPOP01Validate(ctx context.Context, ch *Challenge, db DB, jwk *jose.JSO
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dpopOptions := prov.GetOptions().GetWireOptions().GetDPOPOptions()
|
|
|
|
dpopOptions := prov.GetOptions().GetWireOptions().GetDPOPOptions()
|
|
|
|
|
|
|
|
|
|
|
|
issuer, err := dpopOptions.GetTarget(clientID.DeviceID)
|
|
|
|
issuer, err := dpopOptions.GetTarget(clientID.DeviceID)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return WrapErrorISE(err, "invalid Go template registered for 'target'")
|
|
|
|
return WrapErrorISE(err, "invalid Go template registered for 'target'")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
key := dpopOptions.GetSigningKey()
|
|
|
|
|
|
|
|
params := verifyParams{
|
|
|
|
params := verifyParams{
|
|
|
|
token: dpopPayload.AccessToken,
|
|
|
|
token: dpopPayload.AccessToken,
|
|
|
|
key: key,
|
|
|
|
key: dpopOptions.GetSigningKey(),
|
|
|
|
kid: kid,
|
|
|
|
accountJWK: accountJWK,
|
|
|
|
issuer: issuer,
|
|
|
|
issuer: issuer,
|
|
|
|
wireID: wireID,
|
|
|
|
wireID: wireID,
|
|
|
|
challenge: ch,
|
|
|
|
challenge: ch,
|
|
|
@ -541,7 +533,7 @@ type verifyParams struct {
|
|
|
|
token string
|
|
|
|
token string
|
|
|
|
key string
|
|
|
|
key string
|
|
|
|
issuer string
|
|
|
|
issuer string
|
|
|
|
kid string
|
|
|
|
accountJWK *jose.JSONWebKey
|
|
|
|
wireID wire.ID
|
|
|
|
wireID wire.ID
|
|
|
|
challenge *Challenge
|
|
|
|
challenge *Challenge
|
|
|
|
t time.Time
|
|
|
|
t time.Time
|
|
|
@ -565,7 +557,7 @@ func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopT
|
|
|
|
|
|
|
|
|
|
|
|
var accessToken wireAccessToken
|
|
|
|
var accessToken wireAccessToken
|
|
|
|
if err = jwt.Claims(pk, &accessToken); err != nil {
|
|
|
|
if err = jwt.Claims(pk, &accessToken); err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("failed getting token claims: %w", err)
|
|
|
|
return nil, nil, fmt.Errorf("failed validating Wire DPoP token claims: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := accessToken.ValidateWithLeeway(jose.Expected{
|
|
|
|
if err := accessToken.ValidateWithLeeway(jose.Expected{
|
|
|
@ -575,11 +567,17 @@ func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopT
|
|
|
|
return nil, nil, fmt.Errorf("failed validation: %w", err)
|
|
|
|
return nil, nil, fmt.Errorf("failed validation: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rawKid, err := v.accountJWK.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 {
|
|
|
|
if accessToken.Cnf == nil {
|
|
|
|
return nil, nil, errors.New("'cnf' is nil")
|
|
|
|
return nil, nil, errors.New("'cnf' is nil")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if accessToken.Cnf.Kid != v.kid {
|
|
|
|
if accessToken.Cnf.Kid != kid {
|
|
|
|
return nil, nil, fmt.Errorf("expected kid %q; got %q", v.kid, accessToken.Cnf.Kid)
|
|
|
|
return nil, nil, fmt.Errorf("expected kid %q; got %q", kid, accessToken.Cnf.Kid)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if accessToken.ClientID != v.wireID.ClientID {
|
|
|
|
if accessToken.ClientID != v.wireID.ClientID {
|
|
|
|
return nil, nil, fmt.Errorf("invalid Wire client ID %q", accessToken.ClientID)
|
|
|
|
return nil, nil, fmt.Errorf("invalid Wire client ID %q", accessToken.ClientID)
|
|
|
@ -592,13 +590,13 @@ func parseAndVerifyWireAccessToken(v verifyParams) (*wireAccessToken, *wireDpopT
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("invalid Wire DPoP token: %w", err)
|
|
|
|
return nil, nil, fmt.Errorf("invalid Wire DPoP token: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var dpopToken wireDpopToken
|
|
|
|
var dpopToken wireDpopToken
|
|
|
|
if err := dpopJWT.UnsafeClaimsWithoutVerification(&dpopToken); err != nil {
|
|
|
|
if err := dpopJWT.Claims(v.accountJWK.Key, &dpopToken); err != nil {
|
|
|
|
return nil, nil, fmt.Errorf("failed parsing Wire DPoP token: %w", err)
|
|
|
|
fmt.Println(err)
|
|
|
|
|
|
|
|
return nil, nil, fmt.Errorf("failed validating Wire DPoP token claims: %w", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TODO(hs): DPoP verification
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
challenge, ok := dpopToken["chal"].(string)
|
|
|
|
challenge, ok := dpopToken["chal"].(string)
|
|
|
|
if !ok {
|
|
|
|
if !ok {
|
|
|
|
return nil, nil, fmt.Errorf("invalid challenge in Wire DPoP token")
|
|
|
|
return nil, nil, fmt.Errorf("invalid challenge in Wire DPoP token")
|
|
|
|