Updated bouncy castle to a higher version to support ED25529. Pulled in Stack Overflow signature/proof verification.
This commit is contained in:
parent
78456fceb8
commit
c2540377e2
@ -11,10 +11,10 @@
|
|||||||
<groupId>org.1edtech</groupId>
|
<groupId>org.1edtech</groupId>
|
||||||
<artifactId>inspector-core</artifactId>
|
<artifactId>inspector-core</artifactId>
|
||||||
</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>
|
||||||
|
@ -114,9 +114,12 @@ public class OB30Inspector extends VCInspector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//verify proofs TODO @Miles
|
//verify proofs TODO @Miles
|
||||||
probeCount++;
|
//If this credential was not contained in a jwt it must have an internal proof.
|
||||||
accumulator.add(new ProofVerifierProbe().run(crd, ctx));
|
if(isNullOrEmpty(crd.getJwt())){
|
||||||
if(broken(accumulator)) return abort(ctx, accumulator, probeCount);
|
probeCount++;
|
||||||
|
accumulator.add(new ProofVerifierProbe().run(crd, ctx));
|
||||||
|
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++;
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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,7 +94,21 @@ 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
|
||||||
decodedJwt = verifier.verify(jwt);
|
try {
|
||||||
|
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();
|
||||||
|
Loading…
Reference in New Issue
Block a user