Repository navigation
feat(bundle): add marshal methods to X509Bundle and JwtBundle - #509
Merged
Merged
Conversation
X509Bundle and JwtBundle could be parsed from PEM certificates and from an RFC 7517 JWKS document, but there was no way to serialize them back. Code that obtains a bundle from an X509Source or a JwtSource and needs to store it, pass it to another process, or serve it as a JWKS had to write the encoding by hand, including the JWK curve lookup for EC keys. go-spiffe exposes the same operation as Bundle.Marshal in its x509bundle and jwtbundle packages. Add X509Bundle.marshal(), which writes each X.509 authority as a PEM CERTIFICATE block wrapped at 64 characters, and JwtBundle.marshal(), which writes the JWT authorities as a JWKS document in UTF-8 JSON with one public JWK per authority, carrying its key ID and ordered by key ID so the output is stable. EC keys on a curve that has a JWK name and RSA keys are supported, matching the key types parse accepts; any other key raises JwtBundleException. An authority that cannot be DER-encoded raises X509BundleException. The output of both methods is read back by the existing parse methods. A bundle without X.509 authorities marshals to an empty array, which X509Bundle.parse rejects as before; this is documented on the method. JwtBundle.parse decoded its input with the platform default charset. JSON is UTF-8, so decode it as UTF-8: on Java 8 to 17 with a non-UTF-8 default charset, non-ASCII key IDs were corrupted and a marshaled bundle would not round-trip. The change only adds methods to final classes, so it is binary compatible. The core README documents the new methods and the changelog lists them under Unreleased. Fixes spiffe#508 Signed-off-by: NopeCharon <115794254+NopeCharon@users.noreply.github.com>
maxlambrecht
force-pushed
the
feat/bundle-marshal
branch
from
November 12, 2026 15:23
f68c3be to
e92b0cf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
marshal()to both bundle types, the reverse of their existingparsemethods:X509Bundle.marshal()returns the X.509 authorities as PEMCERTIFICATEblocks, wrapped at 64 characters.JwtBundle.marshal()returns the JWT authorities as an RFC 7517 JWKS document in UTF-8 JSON. Each authority becomes one public JWK with its key ID. Keys are ordered by key ID, so the same bundle always gives the same output.Details:
JwtBundle.marshal()supports EC keys on a named JWK curve, and RSA keys. These are the key typesparseaccepts. Any other key type or curve throwsJwtBundleException, and the message names the key ID.X509Bundle.marshal()throwsX509BundleExceptionif an authority can't be DER-encoded.parsereads back the output of both methods. One exception: a bundle with no X.509 authorities marshals to an empty array, andX509Bundle.parsestill rejects that. The Javadoc says so.JwtBundle.parsenow decodes its input as UTF-8, not with the platform default charset. JSON is UTF-8. Before this, on Java 8–17 with a non-UTF-8 default charset, non-ASCII key IDs were corrupted and a marshaled bundle didn't round-trip.Fixes #508
Why
A bundle from an
X509SourceorJwtSourcecouldn't be serialized again. To store it, pass it to another process, or serve it as a JWKS, callers had to write the encoding themselves. For JWT bundles that included the Nimbus curve lookup for EC keys. go-spiffe offers the same operation asBundle.Marshal()inx509bundleandjwtbundle.Compatibility: this only adds methods to two
finalclasses.japicmpand the binary-compatibility suite pass.How tested
X509BundleTest:certs.pemround-trips throughmarshal/parseX509BundleExceptionJwtBundleTest:jwks_valid_RSA_EC.jsonfixture round-tripskty/crv{"keys":[]}JwtBundleException./gradlew :java-spiffe-core:build :java-spiffe-provider:build binaryCompatibilityTest javadoc.The non-ASCII key ID test checks the round trip. It can't fail on JDK 18+, where UTF-8 is already the default charset.