Skip to content

Commit

Permalink
Fix: Support for RSA signature validation during issuance
Browse files Browse the repository at this point in the history
  • Loading branch information
lijogeorgep authored and josmilan committed Jan 10, 2025
1 parent 16f2281 commit cc8209a
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
//package com.ewc.eudi_wallet_oidc_android.models
//
//// Data class representing a JSON Web Key (JWK).
//data class JwkKey(
// val kty: String,
// val kid: String,
// val crv: String,
// val x: String,
// val y: String,
// val use: String
//)
package com.ewc.eudi_wallet_oidc_android.models

// Data class representing a JSON Web Key (JWK).
data class JwkKey(
val kty: String,
val kid: String,
val crv: String,
val x: String,
val y: String,
val crv: String? = null,
val x: String? = null,
val y: String? = null,
val n: String? = null,
val e: String? = null,
val use: String
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import com.nimbusds.jose.jwk.ECKey
import com.nimbusds.jose.JOSEException
import com.nimbusds.jose.JWSAlgorithm
import com.nimbusds.jose.JWSVerifier
import com.nimbusds.jose.crypto.RSASSAVerifier
import com.nimbusds.jose.jwk.JWK
import com.nimbusds.jose.jwk.RSAKey

class SignatureValidator {

Expand Down Expand Up @@ -42,7 +45,12 @@ class SignatureValidator {
var x5cChain: List<String>? = null
x5cChain = X509SanRequestVerifier.instance.extractX5cFromJWT(jwt)
if (x5cChain != null) {
return X509SanRequestVerifier.instance.validateSignatureWithCertificate(jwt, x5cChain, algorithm)
val isSignatureValid = X509SanRequestVerifier.instance.validateSignatureWithCertificate(jwt, x5cChain, algorithm)
if (isSignatureValid){
return true
}else{
throw SignatureException("JWT signature x5c invalid or cannot be validated")
}
}
// If no valid x5cChain, throw exception
throw SignatureException("JWT signature x5c invalid or cannot be validated")
Expand Down Expand Up @@ -108,7 +116,7 @@ class SignatureValidator {
private fun verifyJwtSignature(jwt: String, jwkJson: String): Boolean {
try {
// Parse the JWK (JSON Web Key) from the JSON string
val jwk = ECKey.parse(jwkJson)
val jwk = JWK.parse(jwkJson)

// Parse the JWT string into a JWS object (JSON Web Signature)
val jwsObject = JWSObject.parse(jwt)
Expand All @@ -119,13 +127,58 @@ class SignatureValidator {
// Create the appropriate verifier based on the algorithm used in the JWS header
val verifier: JWSVerifier = when (algorithm) {
// For ES256 (ECDSA using P-256 curve and SHA-256), create an ECDSAVerifier
JWSAlgorithm.ES256 -> ECDSAVerifier(jwk.toECKey())
JWSAlgorithm.ES256 -> {
if (jwk is ECKey) {
ECDSAVerifier(jwk) // Use the ECKey directly
} else {
throw JOSEException("JWK is not ECKey for algorithm $algorithm")
}
}

// For ES384 (ECDSA using P-384 curve and SHA-384), create an ECDSAVerifier
JWSAlgorithm.ES384 -> ECDSAVerifier(jwk.toECKey())
JWSAlgorithm.ES384 -> {
if (jwk is ECKey) {
ECDSAVerifier(jwk) // Use the ECKey directly
} else {
throw JOSEException("JWK is not ECKey for algorithm $algorithm")
}
}

// For ES512 (ECDSA using P-521 curve and SHA-512), create an ECDSAVerifier
JWSAlgorithm.ES512 -> ECDSAVerifier(jwk.toECKey())
JWSAlgorithm.ES512 -> {
if (jwk is ECKey) {
ECDSAVerifier(jwk) // Use the ECKey directly
} else {
throw JOSEException("JWK is not ECKey for algorithm $algorithm")
}
}

// For RS256 (RSA algorithm), create an RSASSAVerifier
JWSAlgorithm.RS256 -> {
if (jwk is RSAKey) {
RSASSAVerifier(jwk) // Use the RSAKey directly
} else {
throw JOSEException("JWK is not RSAKey for algorithm $algorithm")
}
}

// For RS384 (RSA algorithm), create an RSASSAVerifier
JWSAlgorithm.RS384 -> {
if (jwk is RSAKey) {
RSASSAVerifier(jwk) // Use the RSAKey directly
} else {
throw JOSEException("JWK is not RSAKey for algorithm $algorithm")
}
}

// For RS512 (RSA algorithm), create an RSASSAVerifier
JWSAlgorithm.RS512 -> {
if (jwk is RSAKey) {
RSASSAVerifier(jwk) // Use the RSAKey directly
} else {
throw JOSEException("JWK is not RSAKey for algorithm $algorithm")
}
}

// Throw an exception if the algorithm is unsupported
else -> throw JOSEException("Unsupported JWS algorithm $algorithm")
Expand All @@ -142,4 +195,43 @@ class SignatureValidator {
}
}

// @Throws(IllegalArgumentException::class)
// private fun verifyJwtSignature(jwt: String, jwkJson: String): Boolean {
// try {
// // Parse the JWK (JSON Web Key) from the JSON string
// // val jwk = ECKey.parse(jwkJson)
// // Parse the JWK (JSON Web Key) from the JSON string
// val jwk = JWK.parse(jwkJson)
//
// // Parse the JWT string into a JWS object (JSON Web Signature)
// val jwsObject = JWSObject.parse(jwt)
//
// // Get the algorithm specified in the JWS header
// val algorithm = jwsObject.header.algorithm
//
// // Create the appropriate verifier based on the algorithm used in the JWS header
// val verifier: JWSVerifier = when (algorithm) {
// // For ES256 (ECDSA using P-256 curve and SHA-256), create an ECDSAVerifier
// JWSAlgorithm.ES256 -> ECDSAVerifier(jwk.toECKey())
//
// // For ES384 (ECDSA using P-384 curve and SHA-384), create an ECDSAVerifier
// JWSAlgorithm.ES384 -> ECDSAVerifier(jwk.toECKey())
//
// // For ES512 (ECDSA using P-521 curve and SHA-512), create an ECDSAVerifier
// JWSAlgorithm.ES512 -> ECDSAVerifier(jwk.toECKey())
// // Throw an exception if the algorithm is unsupported
// else -> throw JOSEException("Unsupported JWS algorithm $algorithm")
// }
//
// // Verify the signature of the JWS using the appropriate verifier
// return jwsObject.verify(verifier)
// } catch (e: Exception) {
// // Print the stack trace for debugging purposes
// e.printStackTrace()
//
// // Throw an IllegalArgumentException if signature verification fails or any error occurs
// throw IllegalArgumentException("Invalid signature")
// }
// }

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.google.gson.Gson
import com.nimbusds.jose.jwk.Curve
import com.nimbusds.jose.jwk.ECKey
import com.nimbusds.jose.jwk.JWK
import com.nimbusds.jose.jwk.RSAKey
import com.nimbusds.jose.util.Base64URL
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
Expand Down Expand Up @@ -61,19 +62,50 @@ class ProcessJWKFromJwksUri {
* @param jwkKey The JwkKey object.
* @return The JWK object or null if jwkKey is null.
*/
fun convertToJWK(jwkKey: JwkKey?): JWK? {
// fun convertToJWK(jwkKey: JwkKey?): JWK? {
// return jwkKey?.let {
// val curve = when (it.crv) {
// "P-256" -> Curve.P_256
// "P-384" -> Curve.P_384
// "P-521" -> Curve.P_521
// else -> throw IllegalArgumentException("Unsupported curve: ${it.crv}")
// }
//
// ECKey.Builder(curve, Base64URL.from(it.x), Base64URL.from(it.y))
// .keyID(it.kid)
// .build()
// }
// }
private fun convertToJWK(jwkKey: JwkKey?): JWK? {
return jwkKey?.let {
val curve = when (it.crv) {
"P-256" -> Curve.P_256
"P-384" -> Curve.P_384
"P-521" -> Curve.P_521
else -> throw IllegalArgumentException("Unsupported curve: ${it.crv}")
}
when (it.kty) {
"EC" -> {
// Handle Elliptic Curve keys
val curve = when (it.crv) {
"P-256" -> Curve.P_256
"P-384" -> Curve.P_384
"P-521" -> Curve.P_521
else -> throw IllegalArgumentException("Unsupported curve: ${it.crv}")
}

ECKey.Builder(curve, Base64URL.from(it.x), Base64URL.from(it.y))
.keyID(it.kid)
.build()
}
"RSA" -> {
// Handle RSA keys
if (it.n == null || it.e == null) {
throw IllegalArgumentException("RSA keys must have 'n' (modulus) and 'e' (exponent) parameters.")
}

ECKey.Builder(curve, Base64URL.from(it.x), Base64URL.from(it.y))
.keyID(it.kid)
.build()
RSAKey.Builder(Base64URL.from(it.n), Base64URL.from(it.e))
.keyID(it.kid)
.build()
}
else -> throw IllegalArgumentException("Unsupported key type: ${it.kty}")
}
}
}


}

0 comments on commit cc8209a

Please sign in to comment.