Restructure refimpl into go-lang and python subdirectories
Move Go reference implementation to refimpl/go-lang/ and add new Python reference implementation in refimpl/python/. Update build.sh with renamed draft and simplified tool paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
243
refimpl/go-lang/ect/verify_test.go
Normal file
243
refimpl/go-lang/ect/verify_test.go
Normal file
@@ -0,0 +1,243 @@
|
||||
package ect
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
now := time.Now()
|
||||
payload := &Payload{
|
||||
Iss: "iss",
|
||||
Aud: []string{"aud"},
|
||||
Iat: now.Unix(),
|
||||
Exp: now.Add(time.Hour).Unix(),
|
||||
Jti: "jti-parse",
|
||||
ExecAct: "act",
|
||||
Par: []string{},
|
||||
Pol: "pol",
|
||||
PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compact, err := Create(payload, key, CreateOptions{KeyID: "kid"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
parsed, err := Parse(compact)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if parsed.Payload.Jti != "jti-parse" {
|
||||
t.Errorf("jti: got %q", parsed.Payload.Jti)
|
||||
}
|
||||
if parsed.Raw != compact {
|
||||
t.Error("Raw should match compact")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_InvalidTyp(t *testing.T) {
|
||||
// Create token then tamper header to test typ check would need different alg or manual JWS;
|
||||
// instead test Verify with bad token
|
||||
_, err := Verify("not-a-jws", VerifyOptions{})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid JWS")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_Expired(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
now := time.Now()
|
||||
payload := &Payload{
|
||||
Iss: "iss",
|
||||
Aud: []string{"verifier"},
|
||||
Iat: now.Add(-1 * time.Hour).Unix(),
|
||||
Exp: now.Add(-1 * time.Minute).Unix(),
|
||||
Jti: "jti-exp",
|
||||
ExecAct: "act",
|
||||
Par: []string{},
|
||||
Pol: "pol",
|
||||
PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compact, _ := Create(payload, key, CreateOptions{KeyID: "kid"})
|
||||
resolver := func(kid string) (*ecdsa.PublicKey, error) {
|
||||
if kid == "kid" {
|
||||
return &key.PublicKey, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := Verify(compact, VerifyOptions{
|
||||
VerifierID: "verifier",
|
||||
ResolveKey: resolver,
|
||||
Now: now,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for expired token")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_Replay(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
now := time.Now()
|
||||
payload := &Payload{
|
||||
Iss: "iss",
|
||||
Aud: []string{"v"},
|
||||
Iat: now.Unix(),
|
||||
Exp: now.Add(time.Hour).Unix(),
|
||||
Jti: "jti-replay",
|
||||
ExecAct: "act",
|
||||
Par: []string{},
|
||||
Pol: "p",
|
||||
PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compact, _ := Create(payload, key, CreateOptions{KeyID: "kid"})
|
||||
resolver := func(kid string) (*ecdsa.PublicKey, error) {
|
||||
if kid == "kid" {
|
||||
return &key.PublicKey, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
opts := VerifyOptions{
|
||||
VerifierID: "v",
|
||||
ResolveKey: resolver,
|
||||
Now: now,
|
||||
JTISeen: func(jti string) bool { return jti == "jti-replay" },
|
||||
}
|
||||
_, err := Verify(compact, opts)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for replay")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultVerifyOptions(t *testing.T) {
|
||||
opts := DefaultVerifyOptions()
|
||||
if opts.IATMaxAge != 15*time.Minute {
|
||||
t.Errorf("IATMaxAge: got %v", opts.IATMaxAge)
|
||||
}
|
||||
if opts.DAG.ClockSkewTolerance != DefaultClockSkewTolerance {
|
||||
t.Errorf("DAG: got %d", opts.DAG.ClockSkewTolerance)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_WITSubjectMismatch(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
now := time.Now()
|
||||
payload := &Payload{
|
||||
Iss: "iss", Aud: []string{"v"}, Iat: now.Unix(), Exp: now.Add(time.Hour).Unix(),
|
||||
Jti: "jti-wit", ExecAct: "act", Par: []string{}, Pol: "p", PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compact, _ := Create(payload, key, CreateOptions{KeyID: "kid"})
|
||||
resolver := func(kid string) (*ecdsa.PublicKey, error) {
|
||||
if kid == "kid" {
|
||||
return &key.PublicKey, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := Verify(compact, VerifyOptions{
|
||||
VerifierID: "v", ResolveKey: resolver, Now: now, WITSubject: "other-iss",
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for WIT subject mismatch")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_IATTooFarPast(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
now := time.Now()
|
||||
payload := &Payload{
|
||||
Iss: "iss", Aud: []string{"v"}, Iat: now.Add(-1 * time.Hour).Unix(), Exp: now.Add(time.Hour).Unix(),
|
||||
Jti: "jti-iat", ExecAct: "act", Par: []string{}, Pol: "p", PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compact, _ := Create(payload, key, CreateOptions{KeyID: "kid"})
|
||||
resolver := func(kid string) (*ecdsa.PublicKey, error) {
|
||||
if kid == "kid" {
|
||||
return &key.PublicKey, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := Verify(compact, VerifyOptions{
|
||||
VerifierID: "v", ResolveKey: resolver, Now: now, IATMaxAge: 30 * time.Minute,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for iat too far in past")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_IATInFuture(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
now := time.Now()
|
||||
payload := &Payload{
|
||||
Iss: "iss", Aud: []string{"v"}, Iat: now.Add(60 * time.Second).Unix(), Exp: now.Add(2 * time.Hour).Unix(),
|
||||
Jti: "jti-fut", ExecAct: "act", Par: []string{}, Pol: "p", PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compact, _ := Create(payload, key, CreateOptions{KeyID: "kid"})
|
||||
resolver := func(kid string) (*ecdsa.PublicKey, error) {
|
||||
if kid == "kid" {
|
||||
return &key.PublicKey, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
_, err := Verify(compact, VerifyOptions{
|
||||
VerifierID: "v", ResolveKey: resolver, Now: now, IATMaxFuture: 30 * time.Second,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error for iat in future")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_ResolveKeyError(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
now := time.Now()
|
||||
payload := &Payload{
|
||||
Iss: "iss", Aud: []string{"v"}, Iat: now.Unix(), Exp: now.Add(time.Hour).Unix(),
|
||||
Jti: "jti-err", ExecAct: "act", Par: []string{}, Pol: "p", PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compact, _ := Create(payload, key, CreateOptions{KeyID: "kid"})
|
||||
resolver := func(kid string) (*ecdsa.PublicKey, error) {
|
||||
return nil, errors.New("key lookup failed")
|
||||
}
|
||||
_, err := Verify(compact, VerifyOptions{
|
||||
VerifierID: "v", ResolveKey: resolver, Now: now,
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("expected error from ResolveKey")
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerify_WithDAG(t *testing.T) {
|
||||
key, _ := GenerateKey()
|
||||
ledger := NewMemoryLedger()
|
||||
now := time.Now()
|
||||
root := &Payload{
|
||||
Iss: "iss", Aud: []string{"v"}, Iat: now.Unix(), Exp: now.Add(time.Hour).Unix(),
|
||||
Jti: "jti-root", ExecAct: "act", Par: []string{}, Pol: "p", PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compactRoot, _ := Create(root, key, CreateOptions{KeyID: "kid"})
|
||||
resolver := func(kid string) (*ecdsa.PublicKey, error) {
|
||||
if kid == "kid" {
|
||||
return &key.PublicKey, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
opts := VerifyOptions{
|
||||
VerifierID: "v", ResolveKey: resolver, Store: ledger, Now: now,
|
||||
}
|
||||
parsed, err := Verify(compactRoot, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, _ = ledger.Append(compactRoot, parsed.Payload)
|
||||
child := &Payload{
|
||||
Iss: "iss", Aud: []string{"v"}, Iat: now.Unix() + 1, Exp: now.Add(time.Hour).Unix(),
|
||||
Jti: "jti-child", ExecAct: "act2", Par: []string{"jti-root"}, Pol: "p", PolDecision: PolDecisionApproved,
|
||||
}
|
||||
compactChild, _ := Create(child, key, CreateOptions{KeyID: "kid"})
|
||||
parsed2, err := Verify(compactChild, opts)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if parsed2.Payload.Jti != "jti-child" {
|
||||
t.Errorf("got %q", parsed2.Payload.Jti)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user