Skip to content

Commit fade9c2

Browse files
committed
OID4VP: Add option to lookup decryption keys for pre-registered clients
1 parent 172b411 commit fade9c2

3 files changed

Lines changed: 22 additions & 11 deletions

File tree

vck-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/openid/OpenId4VpHolder.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,14 @@ class OpenId4VpHolder(
106106
private val walletNonceMapStore: MapStore<String, String> = DefaultMapStore(),
107107
/** Source for random bytes, i.e., nonces for encrypted responses. */
108108
private val randomSource: RandomSource = RandomSource.Secure,
109+
/** Callback to load encryption keys for pre-registered clients. */
110+
private val lookupJsonWebKeysForClient: (JsonWebKeyLookupInput) -> JsonWebKeySet? = { null }
109111
) {
110112

113+
data class JsonWebKeyLookupInput(
114+
val clientId: String?
115+
)
116+
111117
private val supportedJwsAlgorithms = supportedAlgorithms
112118
.mapNotNull { it.toJwsAlgorithm().getOrNull()?.identifier }
113119
private val supportedCoseAlgorithms = supportedAlgorithms
@@ -194,7 +200,8 @@ class OpenId4VpHolder(
194200
response = AuthenticationResponse.Error(
195201
error = error.toOAuth2Error(request),
196202
clientMetadata = request.parameters.clientMetadata,
197-
jsonWebKeys = request.parameters.clientMetadata?.loadJsonWebKeySet()?.keys,
203+
jsonWebKeys = request.parameters.clientMetadata?.loadJsonWebKeySet()?.keys
204+
?: lookupJsonWebKeysForClient(JsonWebKeyLookupInput(request.parameters.clientId))?.keys,
198205
)
199206
)
200207
}
@@ -247,7 +254,8 @@ class OpenId4VpHolder(
247254
request = params,
248255
credentialPresentationRequest = params.parameters.loadCredentialRequest(),
249256
clientMetadata = params.parameters.clientMetadata,
250-
jsonWebKeys = params.parameters.clientMetadata?.loadJsonWebKeySet()?.keys,
257+
jsonWebKeys = params.parameters.clientMetadata?.loadJsonWebKeySet()?.keys
258+
?: lookupJsonWebKeysForClient(JsonWebKeyLookupInput(params.parameters.clientId))?.keys,
251259
requestObjectVerified = (params as? RequestParametersFrom.JwsSigned)?.verified,
252260
verifierInfo = params.parameters.verifierInfo
253261
)
@@ -284,6 +292,7 @@ class OpenId4VpHolder(
284292
with(state) {
285293
val audience = request.extractAudience(jsonWebKeys)
286294
val jsonWebKeys = jsonWebKeys?.combine(request.extractLeafCertKey())
295+
?: lookupJsonWebKeysForClient(JsonWebKeyLookupInput(request.parameters.clientId))?.keys
287296
val idToken = presentationFactory.createSignedIdToken(clock, keyMaterial.publicKey, request)
288297
.getOrNull()?.serialize()
289298
val presentation = credentialPresentation ?: credentialPresentationRequest?.toCredentialPresentation()
@@ -407,10 +416,6 @@ class OpenId4VpHolder(
407416
?.let { remoteResourceRetriever(RemoteResourceRetrieverInput(it)) }
408417
?.let { vckJsonSerializer.decodeFromString(it) }
409418

410-
@Suppress("DEPRECATION")
411-
private suspend fun AuthenticationRequestParameters.loadClientMetadata(): RelyingPartyMetadata? =
412-
clientMetadata
413-
414419
}
415420

416421
private fun Collection<JsonWebKey>?.combine(certKey: JsonWebKey?): Collection<JsonWebKey> =

vck-openid/src/commonMain/kotlin/at/asitplus/wallet/lib/openid/OpenId4VpVerifier.kt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import at.asitplus.catchingUnwrapped
66
import at.asitplus.dif.ClaimFormat
77
import at.asitplus.dif.FormatContainerJwt
88
import at.asitplus.dif.FormatContainerSdJwt
9-
import at.asitplus.dif.FormatHolder
109
import at.asitplus.dif.PresentationSubmissionDescriptor
1110
import at.asitplus.iso.DeviceAuthentication
1211
import at.asitplus.iso.DeviceResponse
@@ -364,7 +363,7 @@ class OpenId4VpVerifier(
364363
scope = if (isSiop) buildScope() else null,
365364
nonce = nonceService.provideNonce(),
366365
walletNonce = requestObjectParameters?.walletNonce,
367-
clientMetadata = clientMetadata(this),
366+
clientMetadata = clientMetadata(),
368367
idTokenType = if (isSiop) IdTokenType.SUBJECT_SIGNED.text else null,
369368
responseMode = responseMode,
370369
state = state,
@@ -385,12 +384,12 @@ class OpenId4VpVerifier(
385384
authenticationRequestParameters,
386385
)
387386

388-
private fun clientMetadata(options: RequestOptions): RelyingPartyMetadata? = when (clientIdScheme) {
387+
private fun RequestOptions.clientMetadata(): RelyingPartyMetadata? = when (clientIdScheme) {
389388
is ClientIdScheme.RedirectUri,
390389
is ClientIdScheme.VerifierAttestation,
391390
is ClientIdScheme.CertificateSanDns,
392391
is ClientIdScheme.CertificateHash ->
393-
if (options.encryption || options.responseMode.requiresEncryption) metadataWithEncryption else metadata
392+
if (encryption || responseMode.requiresEncryption) metadataWithEncryption else metadata
394393

395394
else -> null
396395
}

vck-openid/src/commonTest/kotlin/at/asitplus/wallet/lib/openid/PreRegisteredClientTest.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import at.asitplus.openid.AuthenticationRequestParameters
44
import at.asitplus.openid.JarRequestParameters
55
import at.asitplus.openid.OpenIdConstants
66
import at.asitplus.openid.RequestParametersFrom
7+
import at.asitplus.signum.indispensable.josef.JsonWebKeySet
78
import at.asitplus.signum.indispensable.josef.JwsSigned
89
import at.asitplus.signum.indispensable.josef.io.joseCompliantSerializer
910
import at.asitplus.testballoon.invoke
@@ -48,14 +49,16 @@ val PreRegisteredClientTest by testSuite {
4849
lateinit var redirectUrl: String
4950
lateinit var holderKeyMaterial: KeyMaterial
5051
lateinit var verifierKeyMaterial: KeyMaterial
52+
lateinit var decryptionKeyMaterial: KeyMaterial
5153
lateinit var holderAgent: Holder
5254
lateinit var holderOid4vp: OpenId4VpHolder
5355
lateinit var verifierOid4vp: OpenId4VpVerifier
5456
lateinit var defaultRequestOptions: RequestOptions
5557
testConfig = TestConfig.aroundEach {
5658
holderKeyMaterial = EphemeralKeyWithoutCert()
5759
verifierKeyMaterial = EphemeralKeyWithoutCert()
58-
clientId = "PRE-REGISTERED-CLIENT"
60+
decryptionKeyMaterial = EphemeralKeyWithoutCert()
61+
clientId = "PRE-REGISTERED-CLIENT-${uuid4()}"
5962
redirectUrl = "https://example.com/rp/${uuid4()}"
6063
walletUrl = "https://example.com/wallet/${uuid4()}"
6164
holderAgent = HolderAgent(holderKeyMaterial)
@@ -76,10 +79,14 @@ val PreRegisteredClientTest by testSuite {
7679
holderOid4vp = OpenId4VpHolder(
7780
holder = holderAgent,
7881
randomSource = RandomSource.Default,
82+
lookupJsonWebKeysForClient = {
83+
if (it.clientId == clientId) JsonWebKeySet(listOf(decryptionKeyMaterial.jsonWebKey)) else null
84+
}
7985
)
8086
verifierOid4vp = OpenId4VpVerifier(
8187
keyMaterial = verifierKeyMaterial,
8288
clientIdScheme = ClientIdScheme.PreRegistered(clientId, redirectUrl),
89+
decryptionKeyMaterial = decryptionKeyMaterial
8390
)
8491
defaultRequestOptions = RequestOptions(
8592
credentials = setOf(

0 commit comments

Comments
 (0)