Skip to content

Commit

Permalink
Merge pull request #827 from walt-id/98-refactor-openid4vc-library-3
Browse files Browse the repository at this point in the history
issuance JWT-property and well-known URL fixes
  • Loading branch information
severinstampler authored Nov 25, 2024
2 parents 6400c0b + 326b6e6 commit 4d0f11a
Show file tree
Hide file tree
Showing 17 changed files with 111 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class VCUtil {
val jws =
vc.mergingJwtIssue(
issuerKey = key,
issuerDid = issuerDid,
issuerId = issuerDid,
subjectDid = subjectDid,
mappings = JsonObject(emptyMap()),
additionalJwtHeader = emptyMap(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
eyJraWQiOiJkaWQ6a2V5Ono2TWtwN0FWd3ZXeG5zTkR1U1NiZjE5c2dLenJ4MjIzV1k5NUFxWnlBR2lmRlZ5ViIsInR5cCI6IkpXVCIsImFsZyI6IkVkRFNBIn0.eyJpc3MiOiJkaWQ6a2V5Ono2TWtwN0FWd3ZXeG5zTkR1U1NiZjE5c2dLenJ4MjIzV1k5NUFxWnlBR2lmRlZ5ViIsInN1YiI6ImRpZDprZXk6ejZNa2ptMmdhR3NvZEdjaGZHNGs4UDZLd0NIWnNWRVBaaG81VnVFYlk5NHFpQkI5IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3B1cmwuaW1zZ2xvYmFsLm9yZy9zcGVjL29iL3YzcDAvY29udGV4dC5qc29uIl0sImlkIjoidXJuOnV1aWQ6MTIzIiwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIk9wZW5CYWRnZUNyZWRlbnRpYWwiXSwibmFtZSI6IkpGRiB4IHZjLWVkdSBQbHVnRmVzdCAzIEludGVyb3BlcmFiaWxpdHkiLCJpc3N1ZXIiOnsidHlwZSI6WyJQcm9maWxlIl0sImlkIjoiZGlkOmV4YW1wbGU6MTIzIiwibmFtZSI6IkpvYnMgZm9yIHRoZSBGdXR1cmUgKEpGRikiLCJ1cmwiOiJodHRwczovL3d3dy5qZmYub3JnLyIsImltYWdlIjp7ImlkIjoiaHR0cHM6Ly93M2MtY2NnLmdpdGh1Yi5pby92Yy1lZC9wbHVnZmVzdC0xLTIwMjIvaW1hZ2VzL0pGRl9Mb2dvTG9ja3VwLnBuZyIsInR5cGUiOiJJbWFnZSJ9fSwiaXNzdWFuY2VEYXRlIjoiMjAyMy0wNy0yMFQwNzowNTo0NFoiLCJleHBpcmF0aW9uRGF0ZSI6IjIwMzMtMDctMjBUMDc6MDU6NDRaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZXhhbXBsZToxMjMiLCJ0eXBlIjpbIkFjaGlldmVtZW50U3ViamVjdCJdLCJhY2hpZXZlbWVudCI6eyJpZCI6InVybjp1dWlkOmFjMjU0YmQ1LThmYWQtNGJiMS05ZDI5LWVmZDkzODUzNjkyNiIsInR5cGUiOlsiQWNoaWV2ZW1lbnQiXSwibmFtZSI6IkpGRiB4IHZjLWVkdSBQbHVnRmVzdCAzIEludGVyb3BlcmFiaWxpdHkiLCJkZXNjcmlwdGlvbiI6IlRoaXMgd2FsbGV0IHN1cHBvcnRzIHRoZSB1c2Ugb2YgVzNDIFZlcmlmaWFibGUgQ3JlZGVudGlhbHMgYW5kIGhhcyBkZW1vbnN0cmF0ZWQgaW50ZXJvcGVyYWJpbGl0eSBkdXJpbmcgdGhlIHByZXNlbnRhdGlvbiByZXF1ZXN0IHdvcmtmbG93IGR1cmluZyBKRkYgeCBWQy1FRFUgUGx1Z0Zlc3QgMy4iLCJjcml0ZXJpYSI6eyJ0eXBlIjoiQ3JpdGVyaWEiLCJuYXJyYXRpdmUiOiJXYWxsZXQgc29sdXRpb25zIHByb3ZpZGVycyBlYXJuZWQgdGhpcyBiYWRnZSBieSBkZW1vbnN0cmF0aW5nIGludGVyb3BlcmFiaWxpdHkgZHVyaW5nIHRoZSBwcmVzZW50YXRpb24gcmVxdWVzdCB3b3JrZmxvdy4gVGhpcyBpbmNsdWRlcyBzdWNjZXNzZnVsbHkgcmVjZWl2aW5nIGEgcHJlc2VudGF0aW9uIHJlcXVlc3QsIGFsbG93aW5nIHRoZSBob2xkZXIgdG8gc2VsZWN0IGF0IGxlYXN0IHR3byB0eXBlcyBvZiB2ZXJpZmlhYmxlIGNyZWRlbnRpYWxzIHRvIGNyZWF0ZSBhIHZlcmlmaWFibGUgcHJlc2VudGF0aW9uLCByZXR1cm5pbmcgdGhlIHByZXNlbnRhdGlvbiB0byB0aGUgcmVxdWVzdG9yLCBhbmQgcGFzc2luZyB2ZXJpZmljYXRpb24gb2YgdGhlIHByZXNlbnRhdGlvbiBhbmQgdGhlIGluY2x1ZGVkIGNyZWRlbnRpYWxzLiJ9LCJpbWFnZSI6eyJpZCI6Imh0dHBzOi8vdzNjLWNjZy5naXRodWIuaW8vdmMtZWQvcGx1Z2Zlc3QtMy0yMDIzL2ltYWdlcy9KRkYtVkMtRURVLVBMVUdGRVNUMy1iYWRnZS1pbWFnZS5wbmciLCJ0eXBlIjoiSW1hZ2UifX19LCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL3NjaGVtYS9qc29uL29iX3YzcDBfYWNoaWV2ZW1lbnRjcmVkZW50aWFsX3NjaGVtYS5qc29uIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fSwianRpIjoidXJuOnV1aWQ6MTIzIiwiZXhwIjoyMDA1NDU1OTQ0LCJpYXQiOjE2ODk4MzY3NDQsIm5iZiI6MTY4OTgzNjc0NH0.E9Ro9yC7lmY-oVcwA3U8ufbA1XXkrTm4b7YcQWfyvC70MagED3i5NZuGwPIiqvVx8DTg6-hKtJQuHBbZWFKfDw
eyJraWQiOiJkaWQ6a2V5Ono2TWtwN0FWd3ZXeG5zTkR1U1NiZjE5c2dLenJ4MjIzV1k5NUFxWnlBR2lmRlZ5ViN6Nk1rcDdBVnd2V3huc05EdVNTYmYxOXNnS3pyeDIyM1dZOTVBcVp5QUdpZkZWeVYiLCJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSJ9.eyJpc3MiOiJkaWQ6a2V5Ono2TWtwN0FWd3ZXeG5zTkR1U1NiZjE5c2dLenJ4MjIzV1k5NUFxWnlBR2lmRlZ5ViIsInN1YiI6ImRpZDprZXk6ejZNa2ptMmdhR3NvZEdjaGZHNGs4UDZLd0NIWnNWRVBaaG81VnVFYlk5NHFpQkI5IiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiLCJodHRwczovL3B1cmwuaW1zZ2xvYmFsLm9yZy9zcGVjL29iL3YzcDAvY29udGV4dC5qc29uIl0sImlkIjoidXJuOnV1aWQ6MTIzIiwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCIsIk9wZW5CYWRnZUNyZWRlbnRpYWwiXSwibmFtZSI6IkpGRiB4IHZjLWVkdSBQbHVnRmVzdCAzIEludGVyb3BlcmFiaWxpdHkiLCJpc3N1ZXIiOnsidHlwZSI6WyJQcm9maWxlIl0sImlkIjoiZGlkOmV4YW1wbGU6MTIzIiwibmFtZSI6IkpvYnMgZm9yIHRoZSBGdXR1cmUgKEpGRikiLCJ1cmwiOiJodHRwczovL3d3dy5qZmYub3JnLyIsImltYWdlIjp7ImlkIjoiaHR0cHM6Ly93M2MtY2NnLmdpdGh1Yi5pby92Yy1lZC9wbHVnZmVzdC0xLTIwMjIvaW1hZ2VzL0pGRl9Mb2dvTG9ja3VwLnBuZyIsInR5cGUiOiJJbWFnZSJ9fSwiaXNzdWFuY2VEYXRlIjoiMjAyMy0wNy0yMFQwNzowNTo0NFoiLCJleHBpcmF0aW9uRGF0ZSI6IjIwMzMtMDctMjBUMDc6MDU6NDRaIiwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZXhhbXBsZToxMjMiLCJ0eXBlIjpbIkFjaGlldmVtZW50U3ViamVjdCJdLCJhY2hpZXZlbWVudCI6eyJpZCI6InVybjp1dWlkOmFjMjU0YmQ1LThmYWQtNGJiMS05ZDI5LWVmZDkzODUzNjkyNiIsInR5cGUiOlsiQWNoaWV2ZW1lbnQiXSwibmFtZSI6IkpGRiB4IHZjLWVkdSBQbHVnRmVzdCAzIEludGVyb3BlcmFiaWxpdHkiLCJkZXNjcmlwdGlvbiI6IlRoaXMgd2FsbGV0IHN1cHBvcnRzIHRoZSB1c2Ugb2YgVzNDIFZlcmlmaWFibGUgQ3JlZGVudGlhbHMgYW5kIGhhcyBkZW1vbnN0cmF0ZWQgaW50ZXJvcGVyYWJpbGl0eSBkdXJpbmcgdGhlIHByZXNlbnRhdGlvbiByZXF1ZXN0IHdvcmtmbG93IGR1cmluZyBKRkYgeCBWQy1FRFUgUGx1Z0Zlc3QgMy4iLCJjcml0ZXJpYSI6eyJ0eXBlIjoiQ3JpdGVyaWEiLCJuYXJyYXRpdmUiOiJXYWxsZXQgc29sdXRpb25zIHByb3ZpZGVycyBlYXJuZWQgdGhpcyBiYWRnZSBieSBkZW1vbnN0cmF0aW5nIGludGVyb3BlcmFiaWxpdHkgZHVyaW5nIHRoZSBwcmVzZW50YXRpb24gcmVxdWVzdCB3b3JrZmxvdy4gVGhpcyBpbmNsdWRlcyBzdWNjZXNzZnVsbHkgcmVjZWl2aW5nIGEgcHJlc2VudGF0aW9uIHJlcXVlc3QsIGFsbG93aW5nIHRoZSBob2xkZXIgdG8gc2VsZWN0IGF0IGxlYXN0IHR3byB0eXBlcyBvZiB2ZXJpZmlhYmxlIGNyZWRlbnRpYWxzIHRvIGNyZWF0ZSBhIHZlcmlmaWFibGUgcHJlc2VudGF0aW9uLCByZXR1cm5pbmcgdGhlIHByZXNlbnRhdGlvbiB0byB0aGUgcmVxdWVzdG9yLCBhbmQgcGFzc2luZyB2ZXJpZmljYXRpb24gb2YgdGhlIHByZXNlbnRhdGlvbiBhbmQgdGhlIGluY2x1ZGVkIGNyZWRlbnRpYWxzLiJ9LCJpbWFnZSI6eyJpZCI6Imh0dHBzOi8vdzNjLWNjZy5naXRodWIuaW8vdmMtZWQvcGx1Z2Zlc3QtMy0yMDIzL2ltYWdlcy9KRkYtVkMtRURVLVBMVUdGRVNUMy1iYWRnZS1pbWFnZS5wbmciLCJ0eXBlIjoiSW1hZ2UifX19LCJjcmVkZW50aWFsU2NoZW1hIjp7ImlkIjoiaHR0cHM6Ly9wdXJsLmltc2dsb2JhbC5vcmcvc3BlYy9vYi92M3AwL3NjaGVtYS9qc29uL29iX3YzcDBfYWNoaWV2ZW1lbnRjcmVkZW50aWFsX3NjaGVtYS5qc29uIiwidHlwZSI6IkZ1bGxKc29uU2NoZW1hVmFsaWRhdG9yMjAyMSJ9fSwianRpIjoidXJuOnV1aWQ6MTIzIiwiZXhwIjoyMDA1NDU1OTQ0LCJpYXQiOjE2ODk4MzY3NDQsIm5iZiI6MTY4OTgzNjc0NH0.CRBaPc0nV1XUaneM5ZeRRfEifyOSbNa7P2ha8MrWmdXHXHoFXpmovYOjfsvM9GMt9f1anB1PHjlm9Onk3UAoDA
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import id.walt.credentials.utils.W3CVcUtils.update
import id.walt.credentials.vc.vcs.W3CVC
import id.walt.crypto.keys.Key
import id.walt.crypto.utils.JsonUtils.toJsonElement
import id.walt.did.dids.DidUtils
import id.walt.sdjwt.SDMap
import kotlinx.datetime.Instant
import kotlinx.serialization.json.JsonElement
Expand All @@ -33,7 +34,7 @@ object Issuer {
@JsExport.Ignore
suspend fun W3CVC.baseIssue(
key: Key,
did: String,
issuerId: String,
subject: String,

dataOverwrites: Map<String, JsonElement>,
Expand All @@ -47,7 +48,7 @@ object Issuer {

return signJws(
issuerKey = key,
issuerDid = did,
issuerId = issuerId,
subjectDid = subject,
additionalJwtHeader = additionalJwtHeaders,
additionalJwtOptions = additionalJwtOptions
Expand All @@ -60,8 +61,7 @@ object Issuer {
@JsExport.Ignore
suspend fun W3CVC.mergingJwtIssue(
issuerKey: Key,
issuerDid: String?,
issuerKid: String? = null,
issuerId: String,
subjectDid: String,

mappings: JsonObject,
Expand All @@ -71,15 +71,16 @@ object Issuer {

completeJwtWithDefaultCredentialData: Boolean = true,
) = mergingToVc(
issuerDid = issuerDid,
issuerId = issuerId,
subjectDid = subjectDid,
mappings = mappings,
completeJwtWithDefaultCredentialData
).run {
val issuerDid = if(DidUtils.isDidUrl(issuerId)) issuerId else null
w3cVc.signJws(
issuerKey = issuerKey,
issuerDid = issuerDid,
issuerKid = issuerKid,
issuerId = issuerId,
issuerKid = getKidHeader(issuerKey, issuerDid),
subjectDid = subjectDid,
additionalJwtHeader = additionalJwtHeader.toMutableMap().apply {
put("typ", "JWT".toJsonElement())
Expand All @@ -96,7 +97,7 @@ object Issuer {
@JsExport.Ignore
suspend fun W3CVC.mergingSdJwtIssue(
issuerKey: Key,
issuerDid: String?,
issuerId: String,
subjectDid: String,

mappings: JsonObject,
Expand All @@ -107,14 +108,15 @@ object Issuer {
completeJwtWithDefaultCredentialData: Boolean = true,
disclosureMap: SDMap
) = mergingToVc(
issuerDid = issuerDid,
issuerId = issuerId,
subjectDid = subjectDid,
mappings = mappings,
completeJwtWithDefaultCredentialData
).run {
val issuerDid = if(DidUtils.isDidUrl(issuerId)) issuerId else null
w3cVc.signSdJwt(
issuerKey = issuerKey,
issuerKeyId = issuerDid ?: issuerKey.getKeyId(),
issuerKeyId = getKidHeader(issuerKey, issuerDid),
subjectDid = subjectDid,
disclosureMap = disclosureMap,
additionalJwtHeaders = additionalJwtHeaders.toMutableMap().apply {
Expand All @@ -139,15 +141,16 @@ object Issuer {
@JsPromise
@JsExport.Ignore
suspend fun W3CVC.mergingToVc(
issuerDid: String?,
issuerId: String,
subjectDid: String,

mappings: JsonObject,

completeJwtWithDefaultCredentialData: Boolean = true,
): IssuanceInformation {
val context = mapOf(
"issuerDid" to issuerDid,
"issuerId" to issuerId,
"issuerDid" to (if(DidUtils.isDidUrl(issuerId)) issuerId else null),
"subjectDid" to subjectDid
).filterValues { !it.isNullOrEmpty() }.mapValues { JsonPrimitive(it.value) }

Expand Down Expand Up @@ -186,4 +189,17 @@ object Issuer {

return IssuanceInformation(vc, jwtRes)
}

@JvmBlocking
@JvmAsync
@JsPromise
@JsExport.Ignore
suspend fun getKidHeader(issuerKey: Key, issuerDid: String? = null): String {
return if(!issuerDid.isNullOrEmpty()) {
if (issuerDid.startsWith("did:key"))
issuerDid + "#" + issuerDid.removePrefix("did:key:")
else
issuerDid + "#" + issuerKey.getKeyId()
} else issuerKey.getKeyId()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ data class W3CVC(
@JsExport.Ignore
suspend fun signJws(
issuerKey: Key,
issuerDid: String?,
issuerId: String?,
issuerKid: String? = null,
subjectDid: String,
/** Set additional options in the JWT header */
additionalJwtHeader: Map<String, JsonElement> = emptyMap(),
/** Set additional options in the JWT payload */
additionalJwtOptions: Map<String, JsonElement> = emptyMap()
): String {
val kid = issuerKid ?: issuerDid ?: issuerKey.getKeyId()
val kid = issuerKid ?: issuerKey.getKeyId()

return JwsSignatureScheme().sign(
data = this.toJsonObject(),
Expand All @@ -93,7 +93,7 @@ data class W3CVC(
*(additionalJwtHeader.entries.map { it.toPair() }.toTypedArray())
),
jwtOptions = mapOf(
JwsOption.ISSUER to JsonPrimitive(issuerDid),
JwsOption.ISSUER to JsonPrimitive(issuerId),
JwsOption.SUBJECT to JsonPrimitive(subjectDid),
*(additionalJwtOptions.entries.map { it.toPair() }.toTypedArray())
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ private suspend fun testDidMethod(didMethod: String, key: JWKKey) {
// Sign VC with did method (JWS)
val jws = vc.signJws(
issuerKey = key,
issuerDid = did,
issuerId = did,
subjectDid = did
)
assertNotNull(jws)
Expand Down Expand Up @@ -102,7 +102,7 @@ private suspend fun testWeb(key: JWKKey) {
// Sign VC with WEB
val jws = vc.signJws(
issuerKey = key,
issuerDid = didWebResult.did,
issuerId = didWebResult.did,
subjectDid = didWebResult.did
)

Expand Down Expand Up @@ -133,7 +133,7 @@ suspend fun testCheqd(key: JWKKey) {

val jws = vc.signJws(
issuerKey = key,
issuerDid = cheqdid,
issuerId = cheqdid,
subjectDid = cheqdid
)
assertNotNull(jws)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class VcApiTest {
// Sign VC
val jws = vc.signJws(
issuerKey = key,
issuerDid = did,
issuerId = did,
subjectDid = did
)
println(jws)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package id.walt.oid4vc

import cbor.Cbor
import id.walt.credentials.issuance.Issuer.getKidHeader
import id.walt.credentials.issuance.Issuer.mergingJwtIssue
import id.walt.credentials.issuance.Issuer.mergingSdJwtIssue
import id.walt.credentials.issuance.dataFunctions
Expand Down Expand Up @@ -124,9 +125,11 @@ object OpenID4VCI {
appendPathSegments(".well-known", "oauth-authorization-server")
}.buildString()

fun getJWTIssuerProviderMetadataUrl(baseUrl: String) = URLBuilder(baseUrl).apply {
fun getJWTVCIssuerProviderMetadataUrl(issUrl: String) = Url(issUrl).let { URLBuilder(it.protocolWithAuthority).apply {
appendPathSegments(".well-known", "jwt-vc-issuer")
}.buildString()
if(it.fullPath.isNotEmpty())
appendPathSegments(it.fullPath.trim('/'))
}.buildString() }

suspend fun resolveCIProviderMetadata(credOffer: CredentialOffer) = http.get(getCIProviderMetadataUrl(credOffer)).bodyAsText().let {
OpenIDProviderMetadata.fromJSONString(it)
Expand Down Expand Up @@ -384,10 +387,9 @@ object OpenID4VCI {
}

suspend fun generateSdJwtVC(credentialRequest: CredentialRequest,
credentialData: JsonObject, dataMapping: JsonObject?,
selectiveDisclosure: SDMap?, vct: String,
issuerDid: String?, issuerKid: String?, x5Chain: List<String>?,
issuerKey: Key): String {
credentialData: JsonObject, issuerId: String, issuerKey: Key,
selectiveDisclosure: SDMap? = null,
dataMapping: JsonObject? = null, x5Chain: List<String>? = null): String {
val proofHeader = credentialRequest.proof?.jwt?.let { JwtUtils.parseJWTHeader(it) } ?: throw CredentialError(
credentialRequest, CredentialErrorCode.invalid_or_missing_proof, message = "Proof must be JWT proof"
)
Expand All @@ -405,7 +407,6 @@ object OpenID4VCI {
credentialData.mergeSDJwtVCPayloadWithMapping(
mapping = dataMapping ?: JsonObject(emptyMap()),
context = mapOf(
"issuerDid" to issuerDid,
"subjectDid" to holderDid
).filterValues { !it.isNullOrEmpty() }.mapValues { JsonPrimitive(it.value) },
dataFunctions
Expand All @@ -417,13 +418,15 @@ object OpenID4VCI {
?: throw IllegalArgumentException("Either holderKey or holderDid must be given")

val defaultPayloadProperties = defaultPayloadProperties(
issuerDid ?: issuerKid ?: issuerKey.getKeyId(),
cnf, vct, null, null, null, null)
issuerId, cnf, credentialRequest.vct
?: throw CredentialError(credentialRequest, CredentialErrorCode.invalid_request, "VCT must be set on credential request")
)
val undisclosedPayload = sdPayload.undisclosedPayload.plus(defaultPayloadProperties).let { JsonObject(it) }
val fullPayload = sdPayload.fullPayload.plus(defaultPayloadProperties).let { JsonObject(it) }
val issuerDid = if(DidUtils.isDidUrl(issuerId)) issuerId else null

val headers = mapOf(
"kid" to issuerKid,
"kid" to getKidHeader(issuerKey, issuerDid),
"typ" to SD_JWT_VC_TYPE_HEADER
).plus(x5Chain?.let {
mapOf("x5c" to JsonArray(it.map { cert -> cert.toJsonElement() }))
Expand All @@ -437,9 +440,9 @@ object OpenID4VCI {
}

suspend fun generateW3CJwtVC(credentialRequest: CredentialRequest,
credentialData: JsonObject, dataMapping: JsonObject?,
selectiveDisclosure: SDMap?, issuerDid: String?, issuerKid: String?,
x5Chain: List<String>?, issuerKey: Key): String {
credentialData: JsonObject, issuerKey: Key, issuerId: String,
selectiveDisclosure: SDMap? = null,
dataMapping: JsonObject? = null, x5Chain: List<String>? = null): String {
val proofHeader = credentialRequest.proof?.jwt?.let { JwtUtils.parseJWTHeader(it) } ?: throw CredentialError(
credentialRequest, CredentialErrorCode.invalid_or_missing_proof, message = "Proof must be JWT proof"
)
Expand All @@ -451,16 +454,15 @@ object OpenID4VCI {
return W3CVC(credentialData).let { vc -> when(selectiveDisclosure.isNullOrEmpty()) {
true -> vc.mergingJwtIssue(
issuerKey = issuerKey,
issuerDid = issuerDid,
issuerKid = issuerKid,
issuerId = issuerId,
subjectDid = holderDid ?: "",
mappings = dataMapping ?: JsonObject(emptyMap()),
additionalJwtHeader = additionalJwtHeaders,
additionalJwtOptions = emptyMap()
)
else -> vc.mergingSdJwtIssue(
issuerKey = issuerKey,
issuerDid = issuerDid,
issuerId = issuerId,
subjectDid = holderDid ?: "",
mappings = dataMapping ?: JsonObject(emptyMap()),
additionalJwtHeaders = additionalJwtHeaders,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,11 @@ class OpenID4VCI_Test {
ISSUER_DID, WALLET_DID
)
assertTrue(actual = JwtSignaturePolicy().verify(credential, null, mapOf()).isSuccess)

// test jwt-vc-issuer well-known url with URL path segments
val issuerUrl = "http://waltid.enterprise.localhost:3000/v1/waltid.tenant1.issuer1/issuer-service-api/openid4vc/"
val wellKnownVCIssuerUrl = "http://waltid.enterprise.localhost:3000/.well-known/jwt-vc-issuer/v1/waltid.tenant1.issuer1/issuer-service-api/openid4vc"
assertEquals(wellKnownVCIssuerUrl, OpenID4VCI.getJWTVCIssuerProviderMetadataUrl(issuerUrl))
}

// Test case for available authentication methods are: NONE, ID_TOKEN, VP_TOKEN, PRE_AUTHORIZED PWD(Handled by third party authorization server)
Expand Down
1 change: 1 addition & 0 deletions waltid-libraries/sdjwt/waltid-sdjwt/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ kotlin {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0")
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.6.1")
implementation("com.soywiz.korlibs.krypto:krypto:4.0.10")
implementation("io.github.oshai:kotlin-logging:7.0.0")
}
}
val commonTest by getting {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlin.js.JsExport
import io.github.oshai.kotlinlogging.KotlinLogging

private val log = KotlinLogging.logger { }
/**
* Mode for adding decoy digests on SD-JWT issuance
* @property NONE: no decoy digests to be added (or mode is unknown, e.g. when parsing SD-JWTs)
Expand All @@ -26,7 +28,7 @@ enum class DecoyMode {
companion object {
@JsExport.Ignore
fun fromJSON(json: JsonElement): DecoyMode {
println("Parsing DecoyMode from $json")
log.trace {"Parsing DecoyMode from $json" }
return (if (json is JsonObject) {
json.jsonObject["name"]?.jsonPrimitive?.content
} else {
Expand Down
Loading

0 comments on commit 4d0f11a

Please sign in to comment.