JWS with JSON serialisation
The JSON Web Signature (JWS) standard specifies two types of serialisation, a compact one that is URL-safe and intended for tokens, and a JSON serialisation which can carry multiple signatures.
Example general JSON serialisation with two signatures applied to the payload:
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.*;
// Generate two signing keys in JWK format
// 2048-bit RSA signing key for RS256 alg
RSAKey rsaJWK = new RSAKeyGenerator(2048)
.algorithm(JWSAlgorithm.RS256)
.keyUse(KeyUse.SIGNATURE)
.keyID("1")
.generate();
// EC signing key with P-256 curve for ES256 alg
ECKey ecJWK = new ECKeyGenerator(Curve.P_256)
.algorithm(JWSAlgorithm.ES256)
.keyUse(KeyUse.SIGNATURE)
.keyID("2")
.generate();
// The payload to sign
Payload payload = new Payload("Hello, world!");
// Create the JWS secured object for JSON serialisation
JWSObjectJSON jwsObjectJSON = new JWSObjectJSON(payload);
// Apply the first signature using the RSA key
jwsObjectJSON.sign(
new JWSHeader.Builder((JWSAlgorithm) rsaJWK.getAlgorithm())
.keyID(rsaJWK.getKeyID())
.build(),
new RSASSASigner(rsaJWK)
);
// Apply the second signature using the EC key
jwsObjectJSON.sign(
new JWSHeader.Builder((JWSAlgorithm) ecJWK.getAlgorithm())
.keyID(ecJWK.getKeyID())
.build(),
new ECDSASigner(ecJWK)
);
// Serialise to JSON
String json = jwsObjectJSON.serializeGeneral();
// Get the public keys to allow recipients to verify the signatures
RSAKey rsaPublicJWK = rsaJWK.toPublicJWK();
ECKey ecPublicJWK = ecJWK.toPublicJWK();
Example output:
{
"payload" : "SGVsbG8sIHdvcmxkIQ",
"signatures" : [
{
"protected" : "eyJraWQiOiIxIiwiYWxnIjoiUlMyNTYifQ",
"signature" : "XAwNAgj-Dw5CBeWG4_6LwQyJrQaAGVJmtqkl21QcIxedNV8Ft0he02eU8Ih60jjNe5FbQxrgfA84JA0isb7NkdczEW_kfX9Fknh-tdypyymrPTsP9bhLKUYfQ7nglWgVf1tukFqkAVZOLdfV7ri9we_bqZblM0pD5ysbu6hjhkLbXSSe_ZD0QfKmJFDaIHWBlB2Z0BeqSmyGQTbO6ZpmxXzICz0ANqTsCrJe6TU2CE6i1mDm0arL12VdcqO9JjD7iQkWppfD3kmRCGsSk3jdJpyWUDCYSKlPVaJJElaffwYjIBevCgfMHFO8ALwpUJc_cFcwBsyalo25JzUSzBNaXg"
},
{
"protected" : "eyJraWQiOiIyIiwiYWxnIjoiRVMyNTYifQ",
"signature" : "ckfVpM4ECSrhDGitxe5smT-z65t3C238JyrHkJw3kiOAunPTRYzHD50wzvNGXG45nUlwl7Ybg8GPlOCNyJeonw"
}
]
}
How to verify a JWS secured object with multiple signatures:
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.*;
// Parse the JWS JSON
JWSObjectJSON jwsObjectJSON = JWSObjectJSON.parse(json);
// Verify the signatures with the available public JWKSs
for (JWSObjectJSON.Signature sig: jwsObjectJSON.getSignatures()) {
// The JWS kid header parameter is used to identify the signing key
if (rsaPublicJWK.getKeyID().equals(sig.getHeader().getKeyID())) {
if (! sig.verify(new RSASSAVerifier(rsaPublicJWK))) {
System.out.println("Invalid RSA signature for key " + rsaPublicJWK.getKeyID());
}
}
if (ecPublicJWK.getKeyID().equals(sig.getHeader().getKeyID())) {
if (! sig.verify(new ECDSAVerifier(ecPublicJWK))) {
System.out.println("Invalid EC signature for key " + ecJWK.getKeyID());
}
}
}
if (JWSObjectJSON.State.VERIFIED.equals(jwsObjectJSON.getState())) {
System.out.println("JWS JSON verified");
} else {
System.out.println("JWS JSON invalid");
}
These examples are based on version 9.16-preview.1 (2021-10-09).