diff --git a/go.mod b/go.mod index ae6850e..eda8c1d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/cofide/minispire go 1.25.3 require ( - github.com/cofide/cofide-sdk-go v0.4.0 + github.com/cofide/cofide-sdk-go v0.4.1 github.com/go-jose/go-jose/v4 v4.1.3 github.com/spiffe/go-spiffe/v2 v2.6.0 github.com/spiffe/spire v1.13.2 diff --git a/go.sum b/go.sum index 5f09e2a..5de39df 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129 h1:MzBOUgng9or github.com/andres-erbsen/clock v0.0.0-20160526145045-9e14626cd129/go.mod h1:rFgpPQZYZ8vdbc+48xibu8ALc3yeyd64IhHS+PU6Yyg= github.com/cofide/cofide-sdk-go v0.4.0 h1:1mbn1Slszz3onkp5SHf332MRDJE4ui4uie5Z2OZmhjQ= github.com/cofide/cofide-sdk-go v0.4.0/go.mod h1:MJ0iPUH0AmYZebiH5trHRWMvvBo+jLc5J4HwY7bcS0g= +github.com/cofide/cofide-sdk-go v0.4.1 h1:VLF+t4Ixe8+lCB/sjOnt8o/jnRXN2WjEscIMDqgXsTk= +github.com/cofide/cofide-sdk-go v0.4.1/go.mod h1:MJ0iPUH0AmYZebiH5trHRWMvvBo+jLc5J4HwY7bcS0g= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= diff --git a/pkg/spire-devserver/memory-ca.go b/pkg/spire-devserver/memory-ca.go index f1ab7a5..86bec14 100644 --- a/pkg/spire-devserver/memory-ca.go +++ b/pkg/spire-devserver/memory-ca.go @@ -15,6 +15,7 @@ import ( "math/big" "time" + cofideid "github.com/cofide/cofide-sdk-go/pkg/id" "github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4/cryptosigner" "github.com/go-jose/go-jose/v4/jwt" @@ -207,7 +208,7 @@ func (i *InMemoryCA) SignWorkloadWITSVID(ctx context.Context, params WorkloadWIT } claims := map[string]any{ - "sub": params.SPIFFEID, + "sub": cofideid.FromSpiffeID(params.SPIFFEID).WIMSEIDString(), "aud": "", // TODO: aud is not part of the WIMSE WIT spec, but is required by the signer here "exp": jwt.NewNumericDate(time.Now().Add(params.TTL)), "iat": jwt.NewNumericDate(time.Now()), @@ -243,13 +244,38 @@ func (i *InMemoryCA) SignWorkloadWITSVID(ctx context.Context, params WorkloadWIT return "", fmt.Errorf("failed to sign WIT SVID: %w", err) } - if _, err := i.ValidateWorkloadJWTSVID(signedToken, params.SPIFFEID); err != nil { + if _, err := i.ValidateWorkloadWITSVID(signedToken, params.SPIFFEID); err != nil { return "", err } return signedToken, nil } +func (i *InMemoryCA) ValidateWorkloadWITSVID(rawToken string, id spiffeid.ID) (*jwt.Claims, error) { + token, err := jwt.ParseSigned(rawToken, jwtsvid.AllowedSignatureAlgorithms) + if err != nil { + return nil, fmt.Errorf("failed to parse WIT-SVID for validation: %w", err) + } + + var claims jwt.Claims + if err := token.UnsafeClaimsWithoutVerification(&claims); err != nil { + return nil, fmt.Errorf("failed to extract WIT-SVID claims for validation: %w", err) + } + + now := time.Now() + switch { + case claims.Subject != cofideid.FromSpiffeID(id).WIMSEIDString(): + return nil, fmt.Errorf(`invalid WIT-SVID "sub" claim: expected %q but got %q`, id, claims.Subject) + case claims.Expiry == nil: + return nil, errors.New(`invalid WIT-SVID "exp" claim: required but missing`) + case !claims.Expiry.Time().After(now): + return nil, fmt.Errorf(`invalid WIT-SVID "exp" claim: already expired as of %s`, claims.Expiry.Time().Format(time.RFC3339)) + case claims.NotBefore != nil && claims.NotBefore.Time().After(now): + return nil, fmt.Errorf(`invalid WIT-SVID "nbf" claim: not yet valid until %s`, claims.NotBefore.Time().Format(time.RFC3339)) + } + return &claims, nil +} + func generateJTI(claims map[string]any, spiffeID string) string { // generate a unique identifier for the token using the claims, spiffeID and nonce in SHA256