Updated bouncy castle to a higher version to support ED25529. Pulled in Stack Overflow signature/proof verification.

This commit is contained in:
Miles Lyon 2022-06-24 15:45:27 -04:00
parent 78456fceb8
commit c2540377e2
4 changed files with 57 additions and 9 deletions

View File

@ -13,8 +13,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.bouncycastle</groupId> <groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId> <artifactId>bcprov-jdk15to18</artifactId>
<version>1.58</version> <version>1.65</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.auth0</groupId> <groupId>com.auth0</groupId>

View File

@ -114,9 +114,12 @@ public class OB30Inspector extends VCInspector {
} }
//verify proofs TODO @Miles //verify proofs TODO @Miles
//If this credential was not contained in a jwt it must have an internal proof.
if(isNullOrEmpty(crd.getJwt())){
probeCount++; probeCount++;
accumulator.add(new ProofVerifierProbe().run(crd, ctx)); accumulator.add(new ProofVerifierProbe().run(crd, ctx));
if(broken(accumulator)) return abort(ctx, accumulator, probeCount); if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
}
//check refresh service if we are not already refreshed //check refresh service if we are not already refreshed
probeCount++; probeCount++;

View File

@ -1,5 +1,15 @@
package org.oneedtech.inspect.vc.probe; package org.oneedtech.inspect.vc.probe;
import java.security.KeyFactory;
import java.security.Security;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.oneedtech.inspect.core.probe.Probe; import org.oneedtech.inspect.core.probe.Probe;
import org.oneedtech.inspect.core.probe.RunContext; import org.oneedtech.inspect.core.probe.RunContext;
import org.oneedtech.inspect.core.report.ReportItems; import org.oneedtech.inspect.core.report.ReportItems;
@ -23,5 +33,22 @@ public class ProofVerifierProbe extends Probe<Credential> {
return success(ctx); return success(ctx);
} }
public boolean validate(String pubkey, String signature, String timestamp, String message) throws Exception {
//TODO: continue this implementation.
//Pulled in bouncy castle library and made sure this sample compiled only.
final var provider = new BouncyCastleProvider();
Security.addProvider(provider);
final var byteKey = Hex.decode(pubkey);
final var pki = new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), byteKey);
final var pkSpec = new X509EncodedKeySpec(pki.getEncoded());
final var kf = KeyFactory.getInstance("ed25519", provider);
final var publicKey = kf.generatePublic(pkSpec);
final var signedData = Signature.getInstance("ed25519", provider);
signedData.initVerify(publicKey);
signedData.update(timestamp.getBytes());
signedData.update(message.getBytes());
return signedData.verify(Hex.decode(signature));
}
public static final String ID = ProofVerifierProbe.class.getSimpleName(); public static final String ID = ProofVerifierProbe.class.getSimpleName();
} }

View File

@ -21,6 +21,10 @@ import org.springframework.util.Base64Utils;
import com.auth0.jwt.JWT; import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.InvalidClaimException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@ -39,7 +43,7 @@ public class SignatureVerifierProbe extends Probe<Credential> {
@Override @Override
public ReportItems run(Credential crd, RunContext ctx) throws Exception { public ReportItems run(Credential crd, RunContext ctx) throws Exception {
try { try {
testingSignatureValidationCode(crd); verifySignature(crd);
} catch (Exception e) { } catch (Exception e) {
return fatal("Error verifying jwt signature: " + e.getMessage(), ctx); return fatal("Error verifying jwt signature: " + e.getMessage(), ctx);
} }
@ -47,7 +51,7 @@ public class SignatureVerifierProbe extends Probe<Credential> {
return success(ctx); return success(ctx);
} }
private void testingSignatureValidationCode(Credential crd) throws Exception { private void verifySignature(Credential crd) throws Exception {
DecodedJWT decodedJwt = null; DecodedJWT decodedJwt = null;
String jwt = crd.getJwt(); String jwt = crd.getJwt();
if(isNullOrEmpty(jwt)) throw new IllegalArgumentException("invalid jwt"); if(isNullOrEmpty(jwt)) throw new IllegalArgumentException("invalid jwt");
@ -90,8 +94,22 @@ public class SignatureVerifierProbe extends Probe<Credential> {
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey)pub, null); Algorithm algorithm = Algorithm.RSA256((RSAPublicKey)pub, null);
JWTVerifier verifier = JWT.require(algorithm) JWTVerifier verifier = JWT.require(algorithm)
.build(); //Reusable verifier instance .build(); //Reusable verifier instance
try {
decodedJwt = verifier.verify(jwt); decodedJwt = verifier.verify(jwt);
} }
catch(SignatureVerificationException ex){
throw new Exception("JWT Invalid signature", ex);
}
catch(AlgorithmMismatchException ex){
throw new Exception("JWT Algorithm mismatch", ex);
}
catch(TokenExpiredException ex){
throw new Exception("JWT Token expired", ex);
}
catch(InvalidClaimException ex){
throw new Exception("JWT, one or more claims are invalid", ex);
}
}
public static final String ID = SignatureVerifierProbe.class.getSimpleName(); public static final String ID = SignatureVerifierProbe.class.getSimpleName();