Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions pkg/common/bundleutil/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type marshalConfig struct {
sequenceNumber uint64
noX509SVIDKeys bool
noJWTSVIDKeys bool
noWITSVIDKeys bool
standardJWKS bool
}

Expand Down Expand Up @@ -59,6 +60,14 @@ func NoJWTSVIDKeys() MarshalOption {
})
}

// NoWITSVIDKeys skips marshalling WIT SVID keys
func NoWITSVIDKeys() MarshalOption {
return marshalOption(func(c *marshalConfig) error {
c.noWITSVIDKeys = true
return nil
})
}

// StandardJWKS omits SPIFFE-specific parameters from the marshaled bundle
func StandardJWKS() MarshalOption {
return marshalOption(func(c *marshalConfig) error {
Expand All @@ -67,6 +76,25 @@ func StandardJWKS() MarshalOption {
})
}

func MarshalX509SVIDBundle(bundle *spiffebundle.Bundle, opts ...MarshalOption) ([]byte, error) {
allOpts := append([]MarshalOption{NoJWTSVIDKeys(), NoWITSVIDKeys()}, opts...)
return Marshal(bundle, allOpts...)
}

func MarshalJWTSVIDBundle(bundle *spiffebundle.Bundle, opts ...MarshalOption) ([]byte, error) {
allOpts := append([]MarshalOption{NoX509SVIDKeys(), NoWITSVIDKeys()}, opts...)
return Marshal(bundle, allOpts...)
}

func MarshalWITSVIDBundle(bundle *spiffebundle.Bundle, opts ...MarshalOption) (string, error) {
allOpts := append([]MarshalOption{NoX509SVIDKeys(), NoJWTSVIDKeys()}, opts...)
marshaledBundle, err := Marshal(bundle, allOpts...)
if err != nil {
return "", err
}
return string(marshaledBundle), nil
}
Comment on lines +89 to +96

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this decision was made for us by go-spiffe already. I don't think we can fix it there now, since it would be a breaking API change.


func Marshal(bundle *spiffebundle.Bundle, opts ...MarshalOption) ([]byte, error) {
refreshHint, ok := bundle.RefreshHint()
if !ok {
Expand Down Expand Up @@ -118,6 +146,16 @@ func Marshal(bundle *spiffebundle.Bundle, opts ...MarshalOption) ([]byte, error)
}
}

if !c.noWITSVIDKeys {
for keyID, witSigningKey := range bundle.WITAuthorities() {
jwks.Keys = append(jwks.Keys, jose.JSONWebKey{
Key: witSigningKey,
KeyID: keyID,
Use: maybeUse(witSVIDUse),
})
}
Comment on lines +149 to +156
}

var out any = jwks
if !c.standardJWKS {
out = bundleDoc{
Expand Down
166 changes: 162 additions & 4 deletions pkg/common/bundleutil/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ func TestMarshal(t *testing.T) {
rootCA := createCACertificate(t)

testCases := []struct {
name string
empty bool
opts []MarshalOption
out string
name string
empty bool
withWITKey bool
opts []MarshalOption
out string
}{
{
name: "empty bundle",
Expand Down Expand Up @@ -136,6 +137,73 @@ func TestMarshal(t *testing.T) {
]
}`, x5c(rootCA)),
},
{
name: "without WIT SVID keys",
withWITKey: true,
opts: []MarshalOption{
NoWITSVIDKeys(),
},
out: fmt.Sprintf(`{
"keys": [
{
"use": "x509-svid",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA",
"x5c": [
"%s"
]
},
{
"use": "jwt-svid",
"kid": "FOO",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA"
}
],
"spiffe_refresh_hint": 60,
"spiffe_sequence": 42
}`, x5c(rootCA)),
},
{
name: "with all SVID keys",
withWITKey: true,
out: fmt.Sprintf(`{
"keys": [
{
"use": "x509-svid",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA",
"x5c": [
"%s"
]
},
{
"use": "jwt-svid",
"kid": "FOO",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA"
},
{
"use": "wit-svid",
"kid": "BAR",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA"
}
],
"spiffe_refresh_hint": 60,
"spiffe_sequence": 42
}`, x5c(rootCA)),
},
}

trustDomain := spiffeid.RequireTrustDomainFromString("domain.test")
Expand All @@ -149,9 +217,99 @@ func TestMarshal(t *testing.T) {
bundle.AddX509Authority(rootCA)
require.NoError(t, bundle.AddJWTAuthority("FOO", testKey.Public()))
}
if testCase.withWITKey {
require.NoError(t, bundle.AddWITAuthority("BAR", testKey.Public()))
}
bundleBytes, err := Marshal(bundle, testCase.opts...)
require.NoError(t, err)
require.JSONEq(t, testCase.out, string(bundleBytes))
})
}
}

func TestMarshalX509SVIDBundle(t *testing.T) {
rootCA := createCACertificate(t)
trustDomain := spiffeid.RequireTrustDomainFromString("domain.test")

bundle := spiffebundle.New(trustDomain)
bundle.SetRefreshHint(time.Minute)
bundle.SetSequenceNumber(42)
bundle.AddX509Authority(rootCA)
require.NoError(t, bundle.AddJWTAuthority("FOO", testKey.Public()))
require.NoError(t, bundle.AddWITAuthority("BAR", testKey.Public()))

bundleBytes, err := MarshalX509SVIDBundle(bundle)
require.NoError(t, err)
require.JSONEq(t, fmt.Sprintf(`{
"keys": [
{
"use": "x509-svid",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA",
"x5c": ["%s"]
}
],
"spiffe_refresh_hint": 60,
"spiffe_sequence": 42
}`, x5c(rootCA)), string(bundleBytes))
}

func TestMarshalJWTSVIDBundle(t *testing.T) {
rootCA := createCACertificate(t)
trustDomain := spiffeid.RequireTrustDomainFromString("domain.test")

bundle := spiffebundle.New(trustDomain)
bundle.SetRefreshHint(time.Minute)
bundle.SetSequenceNumber(42)
bundle.AddX509Authority(rootCA)
require.NoError(t, bundle.AddJWTAuthority("FOO", testKey.Public()))
require.NoError(t, bundle.AddWITAuthority("BAR", testKey.Public()))

bundleBytes, err := MarshalJWTSVIDBundle(bundle)
require.NoError(t, err)
require.JSONEq(t, `{
"keys": [
{
"use": "jwt-svid",
"kid": "FOO",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA"
}
],
"spiffe_refresh_hint": 60,
"spiffe_sequence": 42
}`, string(bundleBytes))
}

func TestMarshalWITSVIDBundle(t *testing.T) {
rootCA := createCACertificate(t)
trustDomain := spiffeid.RequireTrustDomainFromString("domain.test")

bundle := spiffebundle.New(trustDomain)
bundle.SetRefreshHint(time.Minute)
bundle.SetSequenceNumber(42)
bundle.AddX509Authority(rootCA)
require.NoError(t, bundle.AddJWTAuthority("FOO", testKey.Public()))
require.NoError(t, bundle.AddWITAuthority("BAR", testKey.Public()))

bundleBytes, err := MarshalWITSVIDBundle(bundle)
require.NoError(t, err)
require.JSONEq(t, `{
"keys": [
{
"use": "wit-svid",
"kid": "BAR",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA"
}
],
"spiffe_refresh_hint": 60,
"spiffe_sequence": 42
}`, bundleBytes)
}
1 change: 1 addition & 0 deletions pkg/common/bundleutil/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
const (
x509SVIDUse = "x509-svid"
jwtSVIDUse = "jwt-svid"
witSVIDUse = "wit-svid"
)

type bundleDoc struct {
Expand Down
7 changes: 7 additions & 0 deletions pkg/common/bundleutil/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ func unmarshal(trustDomain spiffeid.TrustDomain, doc *bundleDoc) (*spiffebundle.
if err := bundle.AddJWTAuthority(key.KeyID, key.Key); err != nil {
return nil, fmt.Errorf("failed to add jwt-svid entry %d: %w", i, err)
}
case witSVIDUse:
if key.KeyID == "" {
return nil, fmt.Errorf("missing key ID in wit-svid entry %d", i)
}
if err := bundle.AddWITAuthority(key.KeyID, key.Key); err != nil {
return nil, fmt.Errorf("failed to add wit-svid entry %d: %w", i, err)
}
case "":
return nil, fmt.Errorf("missing use for key entry %d", i)
default:
Expand Down
29 changes: 29 additions & 0 deletions pkg/common/bundleutil/unmarshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,21 @@ func TestUnmarshal(t *testing.T) {
}`,
err: "missing key ID in jwt-svid entry 0",
},
{
name: "wit-svid with no keyid",
doc: `{
"keys": [
{
"use": "wit-svid",
"kty": "EC",
"crv": "P-256",
"x": "kkEn5E2Hd_rvCRDCVMNj3deN0ADij9uJVmN-El0CJz0",
"y": "qNrnjhtzrtTR0bRgI2jPIC1nEgcWNX63YcZOEzyo1iA"
}
]
}`,
err: "missing key ID in wit-svid entry 0",
},
}

for _, testCase := range testCases {
Expand All @@ -117,3 +132,17 @@ func TestUnmarshal(t *testing.T) {
})
}
}

func TestUnmarshalRoundTripsWITAuthorities(t *testing.T) {
trustDomain := spiffeid.RequireTrustDomainFromString("domain.test")
bundle := spiffebundle.New(trustDomain)
bundle.SetRefreshHint(0)
require.NoError(t, bundle.AddWITAuthority("BAR", testKey.Public()))

marshaled, err := Marshal(bundle)
require.NoError(t, err)

unmarshaled, err := Unmarshal(trustDomain, marshaled)
require.NoError(t, err)
require.Equal(t, bundle, unmarshaled)
}
Loading