diff --git a/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt index 375559f52..2c5508441 100644 --- a/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt +++ b/waltid-libraries/protocols/waltid-openid4vc/src/commonMain/kotlin/id/walt/oid4vc/OpenID4VCI.kt @@ -325,7 +325,16 @@ object OpenID4VCI { return payload } - fun createDefaultProviderMetadata(baseUrl: String, credentialSupported: Map? = null, version: OpenID4VCIVersion, customParameters: Map? = emptyMap()) : OpenIDProviderMetadata { + fun createDefaultProviderMetadata( + baseUrl: String, + credentialSupported: Map? = null, + version: OpenID4VCIVersion, + customParameters: Map? = emptyMap() + ): OpenIDProviderMetadata { + + validateCredentialIssuerUrl(baseUrl) + + credentialSupported?.let { validateCryptographicBindingMethods(it) } return when (version) { OpenID4VCIVersion.DRAFT13 -> OpenIDProviderMetadata.Draft13( @@ -387,6 +396,34 @@ object OpenID4VCI { } } + + fun validateCredentialIssuerUrl(url: String) { + try { + val parsedUrl = Url(url) + + require(parsedUrl.protocol.name == "https" || parsedUrl.protocol.name == "https") { "URL must use HTTPS or HTTP scheme" } + require(parsedUrl.host.isNotEmpty()) { "URL must have a valid host" } + require(parsedUrl.parameters.isEmpty() && !url.contains("#")) { "URL must not contain query or fragment" } + + } catch (e: IllegalArgumentException) { + throw IllegalArgumentException("Invalid Credential Issuer URL: ${e.message}") + } + } + + fun validateCryptographicBindingMethods(credentialSupported: Map) { + credentialSupported.forEach { + + val validFormats = setOf("jwk", "cose_key") + val didPattern = Regex("^did:[a-z0-9]+$") + + it.value.cryptographicBindingMethodsSupported?.forEach { method -> + require(method in validFormats || didPattern.matches(method)) { + "Invalid cryptographic binding method: $method. Expected 'jwk', 'cose_key', or 'did:'" + } + } + } + } + fun getNonceFromProof(proofOfPossession: ProofOfPossession) = when (proofOfPossession.proofType) { ProofType.jwt -> JwtUtils.parseJWTPayload(proofOfPossession.jwt!!)[JWTClaims.Payload.nonce]?.jsonPrimitive?.content ProofType.cwt -> Cbor.decodeFromByteArray(proofOfPossession.cwt!!.base64UrlDecode()).decodePayload()?.let { payload ->