Skip to content

Commit 4e20bd0

Browse files
committed
Modularize crypto signing and verification operations.
Signed-off-by: Markus Sabadello <[email protected]>
1 parent 3415c1d commit 4e20bd0

File tree

7 files changed

+235
-170
lines changed

7 files changed

+235
-170
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
package com.danubetech.verifiablecredentials.jwt;
2+
3+
import java.security.interfaces.RSAPrivateKey;
4+
import java.security.interfaces.RSAPublicKey;
5+
6+
import org.bitcoinj.core.ECKey;
7+
8+
import com.nimbusds.jose.JOSEException;
9+
import com.nimbusds.jose.JWSAlgorithm;
10+
import com.nimbusds.jose.JWSHeader;
11+
import com.nimbusds.jose.JWSObject;
12+
import com.nimbusds.jose.JWSSigner;
13+
import com.nimbusds.jose.JWSVerifier;
14+
import com.nimbusds.jose.Payload;
15+
import com.nimbusds.jwt.JWTClaimsSet;
16+
17+
import info.weboftrust.ldsignatures.crypto.ByteSigner;
18+
import info.weboftrust.ldsignatures.crypto.ByteVerifier;
19+
import info.weboftrust.ldsignatures.crypto.adapter.JWSSignerAdapter;
20+
import info.weboftrust.ldsignatures.crypto.adapter.JWSVerifierAdapter;
21+
import info.weboftrust.ldsignatures.crypto.impl.Ed25519_EdDSA_PrivateKeySigner;
22+
import info.weboftrust.ldsignatures.crypto.impl.Ed25519_EdDSA_PublicKeyVerifier;
23+
import info.weboftrust.ldsignatures.crypto.impl.P256K_ES256K_PrivateKeySigner;
24+
import info.weboftrust.ldsignatures.crypto.impl.P256K_ES256K_PublicKeyVerifier;
25+
import info.weboftrust.ldsignatures.crypto.impl.RSA_RS256_PrivateKeySigner;
26+
import info.weboftrust.ldsignatures.crypto.impl.RSA_RS256_PublicKeyVerifier;
27+
28+
abstract class JwtObject <T> {
29+
30+
private final JWTClaimsSet payload;
31+
private final T payloadObject;
32+
33+
private JWSObject jwsObject;
34+
private String compactSerialization;
35+
36+
protected JwtObject(JWTClaimsSet payload, T payloadObject, JWSObject jwsObject, String compactSerialization) {
37+
38+
if (payload == null) throw new NullPointerException();
39+
if (payloadObject == null) throw new NullPointerException();
40+
41+
this.payload = payload;
42+
this.payloadObject = payloadObject;
43+
this.jwsObject = jwsObject;
44+
this.compactSerialization = compactSerialization;
45+
}
46+
47+
/*
48+
* Sign
49+
*/
50+
51+
private String sign(JWSSigner jwsSigner, JWSAlgorithm alg) throws JOSEException {
52+
53+
JWSHeader jwsHeader = new JWSHeader.Builder(alg).build();
54+
JWSObject jwsObject = new EscapedSlashWorkaroundJWSObject(jwsHeader, this.getPayload());
55+
56+
jwsObject.sign(jwsSigner);
57+
58+
this.jwsObject = jwsObject;
59+
this.compactSerialization = jwsObject.serialize();
60+
61+
return this.compactSerialization;
62+
}
63+
64+
public String sign_RSA_RS256(ByteSigner signer) throws JOSEException {
65+
66+
return this.sign(new JWSSignerAdapter(signer, JWSAlgorithm.RS256), JWSAlgorithm.RS256);
67+
}
68+
69+
public String sign_RSA_RS256(RSAPrivateKey privateKey) throws JOSEException {
70+
71+
return this.sign_RSA_RS256(new RSA_RS256_PrivateKeySigner(privateKey));
72+
}
73+
74+
public String sign_RSA_RS256(com.nimbusds.jose.jwk.RSAKey privateKey) throws JOSEException {
75+
76+
return this.sign(new com.nimbusds.jose.crypto.RSASSASigner(privateKey), JWSAlgorithm.RS256);
77+
}
78+
79+
public String sign_Ed25519_EdDSA(ByteSigner signer) throws JOSEException {
80+
81+
return this.sign(new JWSSignerAdapter(signer, JWSAlgorithm.EdDSA), JWSAlgorithm.EdDSA);
82+
}
83+
84+
public String sign_Ed25519_EdDSA(byte[] privateKey) throws JOSEException {
85+
86+
return this.sign_Ed25519_EdDSA(new Ed25519_EdDSA_PrivateKeySigner(privateKey));
87+
}
88+
89+
public String sign_Ed25519_EdDSA(com.nimbusds.jose.jwk.OctetKeyPair privateKey) throws JOSEException {
90+
91+
return this.sign(new com.nimbusds.jose.crypto.Ed25519Signer(privateKey), JWSAlgorithm.EdDSA);
92+
}
93+
94+
public String sign_P256K_ES256K(ByteSigner signer) throws JOSEException {
95+
96+
return this.sign(new JWSSignerAdapter(signer, JWSAlgorithm.ES256K), JWSAlgorithm.ES256K);
97+
}
98+
99+
public String sign_P256K_ES256K(ECKey privateKey) throws JOSEException {
100+
101+
return this.sign_P256K_ES256K(new P256K_ES256K_PrivateKeySigner(privateKey));
102+
}
103+
104+
public String sign_P256K_ES256K(com.nimbusds.jose.jwk.ECKey privateKey) throws JOSEException {
105+
106+
return this.sign(new com.nimbusds.jose.crypto.ECDSASigner(privateKey), JWSAlgorithm.ES256K);
107+
}
108+
109+
/*
110+
* Verify
111+
*/
112+
113+
private boolean verify(JWSVerifier jwsVerifier) throws JOSEException {
114+
115+
return this.jwsObject.verify(jwsVerifier);
116+
}
117+
118+
public boolean verify_RSA_RS256(ByteVerifier verifier) throws JOSEException {
119+
120+
return this.verify(new JWSVerifierAdapter(verifier, JWSAlgorithm.RS256));
121+
}
122+
123+
public boolean verify_RSA_RS256(RSAPublicKey publicKey) throws JOSEException {
124+
125+
return this.verify_RSA_RS256(new RSA_RS256_PublicKeyVerifier(publicKey));
126+
}
127+
128+
public boolean verify_RSA_RS256(com.nimbusds.jose.jwk.RSAKey publicKey) throws JOSEException {
129+
130+
return this.verify(new com.nimbusds.jose.crypto.RSASSAVerifier(publicKey));
131+
}
132+
133+
public boolean verify_Ed25519_EdDSA(ByteVerifier verifier) throws JOSEException {
134+
135+
return this.verify(new JWSVerifierAdapter(verifier, JWSAlgorithm.EdDSA));
136+
}
137+
138+
public boolean verify_Ed25519_EdDSA(byte[] publicKey) throws JOSEException {
139+
140+
return this.verify_Ed25519_EdDSA(new Ed25519_EdDSA_PublicKeyVerifier(publicKey));
141+
}
142+
143+
public boolean verify_Ed25519_EdDSA(com.nimbusds.jose.jwk.OctetKeyPair publicKey) throws JOSEException {
144+
145+
return this.verify(new com.nimbusds.jose.crypto.Ed25519Verifier(publicKey));
146+
}
147+
148+
public boolean verify_P256K_ES256K(ByteVerifier verifier) throws JOSEException {
149+
150+
return this.verify(new JWSVerifierAdapter(verifier, JWSAlgorithm.ES256K));
151+
}
152+
153+
public boolean verify_P256K_ES256K(ECKey publicKey) throws JOSEException {
154+
155+
return this.verify_P256K_ES256K(new P256K_ES256K_PublicKeyVerifier(publicKey));
156+
}
157+
158+
public boolean verify_P256K_ES256K(com.nimbusds.jose.jwk.ECKey publicKey) throws JOSEException {
159+
160+
return this.verify(new com.nimbusds.jose.crypto.ECDSAVerifier(publicKey));
161+
}
162+
163+
/*
164+
* Helper class
165+
*/
166+
167+
private static class EscapedSlashWorkaroundJWSObject extends JWSObject {
168+
169+
public EscapedSlashWorkaroundJWSObject(final JWSHeader header, final JWTClaimsSet claimsSet) {
170+
171+
super(header, new Payload(claimsSet.toJSONObject().toJSONString().replace("\\/", "/")));
172+
}
173+
}
174+
175+
/*
176+
* Getters
177+
*/
178+
179+
public JWTClaimsSet getPayload() {
180+
181+
return this.payload;
182+
}
183+
184+
public T getPayloadObject() {
185+
186+
return this.payloadObject;
187+
}
188+
189+
public JWSObject getJwsObject() {
190+
191+
return this.jwsObject;
192+
}
193+
194+
public String getCompactSerialization() {
195+
196+
return this.compactSerialization;
197+
}
198+
}

src/main/java/com/danubetech/verifiablecredentials/jwt/JwtVerifiableCredential.java

Lines changed: 13 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -2,73 +2,36 @@
22

33
import java.io.IOException;
44
import java.security.GeneralSecurityException;
5-
import java.security.PublicKey;
6-
import java.security.interfaces.RSAPublicKey;
75
import java.text.ParseException;
86
import java.util.Date;
97

108
import com.danubetech.verifiablecredentials.VerifiableCredential;
119
import com.fasterxml.jackson.core.JsonParseException;
1210
import com.nimbusds.jose.JOSEException;
13-
import com.nimbusds.jose.JWSAlgorithm;
14-
import com.nimbusds.jose.JWSHeader;
15-
import com.nimbusds.jose.JWSSigner;
16-
import com.nimbusds.jose.JWSVerifier;
17-
import com.nimbusds.jose.crypto.ECDSASigner;
18-
import com.nimbusds.jose.crypto.Ed25519Signer;
19-
import com.nimbusds.jose.crypto.RSASSASigner;
20-
import com.nimbusds.jose.crypto.RSASSAVerifier;
21-
import com.nimbusds.jose.jwk.ECKey;
22-
import com.nimbusds.jose.jwk.OctetKeyPair;
23-
import com.nimbusds.jose.jwk.RSAKey;
11+
import com.nimbusds.jose.JWSObject;
2412
import com.nimbusds.jwt.JWTClaimsSet;
2513
import com.nimbusds.jwt.SignedJWT;
2614

2715
import net.minidev.json.JSONObject;
2816

29-
public class JwtVerifiableCredential {
17+
public class JwtVerifiableCredential extends JwtObject<VerifiableCredential> {
3018

3119
public static final String JWT_CLAIM_VC = "vc";
3220

33-
private final JWTClaimsSet payload;
34-
private final VerifiableCredential payloadVerifiableCredential;
21+
private JwtVerifiableCredential(JWTClaimsSet payload, VerifiableCredential payloadObject, JWSObject jwsObject, String compactSerialization) {
3522

36-
private String compactSerialization;
37-
38-
private JwtVerifiableCredential(JWTClaimsSet payload, VerifiableCredential payloadVerifiableCredential, String compactSerialization) {
39-
40-
if (payload == null) throw new NullPointerException();
41-
if (payloadVerifiableCredential == null) throw new NullPointerException();
42-
43-
this.payload = payload;
44-
this.payloadVerifiableCredential = payloadVerifiableCredential;
45-
this.compactSerialization = compactSerialization;
23+
super(payload, payloadObject, jwsObject, compactSerialization);
4624
}
4725

48-
public static JwtVerifiableCredential fromJwt(String jwt, String algorithm, PublicKey publicKey, boolean doValidate) throws GeneralSecurityException, ParseException, JOSEException, JsonParseException, IOException {
49-
50-
boolean validate;
51-
52-
SignedJWT signedJWT = SignedJWT.parse(jwt);
26+
public static JwtVerifiableCredential fromCompactSerialization(String compactSerialization) throws GeneralSecurityException, ParseException, JOSEException, JsonParseException, IOException {
5327

54-
if (doValidate) {
28+
SignedJWT signedJWT = SignedJWT.parse(compactSerialization);
5529

56-
JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
57-
validate = signedJWT.verify(verifier);
58-
59-
if (! validate) throw new GeneralSecurityException("Invalid signature: " + jwt);
60-
}
61-
62-
JWTClaimsSet jwtPayload = signedJWT.getJWTClaimsSet();
63-
JSONObject jsonLdObject = (JSONObject) jwtPayload.getClaims().get(JWT_CLAIM_VC);
30+
JWTClaimsSet payload = signedJWT.getJWTClaimsSet();
31+
JSONObject jsonLdObject = (JSONObject) payload.getClaims().get(JWT_CLAIM_VC);
6432
VerifiableCredential payloadVerifiableCredential = VerifiableCredential.fromJsonString(jsonLdObject.toJSONString(), false);
6533

66-
return new JwtVerifiableCredential(jwtPayload, payloadVerifiableCredential, jwt);
67-
}
68-
69-
public static JwtVerifiableCredential fromJwt(String jwt, String algorithm, PublicKey publicKey) throws GeneralSecurityException, ParseException, JOSEException, JsonParseException, IOException {
70-
71-
return fromJwt(jwt, algorithm, publicKey, true);
34+
return new JwtVerifiableCredential(payload, payloadVerifiableCredential, signedJWT, compactSerialization);
7235
}
7336

7437
public static JwtVerifiableCredential fromVerifiableCredential(VerifiableCredential verifiableCredential, String aud) {
@@ -122,75 +85,23 @@ public static JwtVerifiableCredential fromVerifiableCredential(VerifiableCredent
12285

12386
payloadBuilder.claim(JWT_CLAIM_VC, payloadVerifiableCredential.getJsonLdObject());
12487

125-
return new JwtVerifiableCredential(payloadBuilder.build(), payloadVerifiableCredential, null);
88+
JWTClaimsSet payload = payloadBuilder.build();
89+
90+
return new JwtVerifiableCredential(payload, payloadVerifiableCredential, null, null);
12691
}
12792

12893
public static JwtVerifiableCredential fromVerifiableCredential(VerifiableCredential verifiableCredential) {
12994

13095
return fromVerifiableCredential(verifiableCredential, null);
13196
}
13297

133-
public JWTClaimsSet getPayload() {
134-
135-
return this.payload;
136-
}
137-
138-
public VerifiableCredential getPayloadVerifiableCredential() {
139-
140-
return this.payloadVerifiableCredential;
141-
}
142-
143-
public String getCompactSerialization() {
144-
145-
return this.compactSerialization;
146-
}
147-
148-
public String toJwt(RSAKey rsaKey) throws JOSEException {
149-
150-
JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.RS256).build();
151-
SignedJWT signedJWT = new SignedJWT(jwsHeader, this.getPayload());
152-
153-
JWSSigner signer = new RSASSASigner(rsaKey);
154-
155-
signedJWT.sign(signer);
156-
157-
this.compactSerialization = signedJWT.serialize();
158-
return compactSerialization;
159-
}
160-
161-
public String toJwt(OctetKeyPair octetKeyPair) throws JOSEException {
162-
163-
JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.EdDSA).build();
164-
SignedJWT signedJWT = new SignedJWT(jwsHeader, this.getPayload());
165-
166-
JWSSigner signer = new Ed25519Signer(octetKeyPair);
167-
168-
signedJWT.sign(signer);
169-
170-
this.compactSerialization = signedJWT.serialize();
171-
return compactSerialization;
172-
}
173-
174-
public String toJwt(ECKey ecKey) throws JOSEException {
175-
176-
JWSHeader jwsHeader = new JWSHeader.Builder(JWSAlgorithm.ES256K).build();
177-
SignedJWT signedJWT = new SignedJWT(jwsHeader, this.getPayload());
178-
179-
JWSSigner signer = new ECDSASigner(ecKey);
180-
181-
signedJWT.sign(signer);
182-
183-
this.compactSerialization = signedJWT.serialize();
184-
return compactSerialization;
185-
}
186-
18798
public VerifiableCredential toVerifiableCredential() {
18899

189100
VerifiableCredential verifiableCredential;
190101

191102
try {
192103

193-
verifiableCredential = VerifiableCredential.fromJsonString(this.getPayloadVerifiableCredential().toJsonString(), false);
104+
verifiableCredential = VerifiableCredential.fromJsonString(this.getPayloadObject().toJsonString(), false);
194105
} catch (IOException ex) {
195106

196107
throw new RuntimeException(ex.getMessage(), ex);

0 commit comments

Comments
 (0)