Skip to content

Commit 90acccf

Browse files
leoScytalessraptis-scy
authored andcommitted
Migrate to multipaz 0.95 KeyUnlockDataProvider API
- Update multipaz dependency to 0.95 - Add KeyUnlockDataProviderExtensions for wrapping KeyUnlockData - Update ProcessedDCPAPIRequest for response generation - Update OpenId4VpUtils for coroutine context handling - Update SecureAreaWalletKeyManager for API changes - Update MsoMdocParser for multipaz 0.95 compatibility
1 parent 14df574 commit 90acccf

6 files changed

Lines changed: 92 additions & 25 deletions

File tree

gradle/libs.versions.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ dependencycheck = "12.1.3"
1010
dokka = "1.9.20"
1111
espresso-contrib = "3.6.1"
1212
espresso-core = "3.6.1"
13-
eudi-document-manager = "0.13.0"
14-
eudi-iso18013-data-transfer = "0.10.0"
13+
eudi-document-manager = "0.14.0-SNAPSHOT"
14+
eudi-iso18013-data-transfer = "0.11.0-SNAPSHOT"
1515
eudi-lib-jvm-openid4vci-kt = "0.9.1"
1616
eudi-lib-jvm-siop-openid4vp-kt = "0.12.0"
1717
eudi-lib-jvm-sdjwt-kt = "0.10.0"
@@ -30,7 +30,7 @@ mockito-android = "5.18.0"
3030
mockito-inline = "5.2.0"
3131
mockito-kotlin = "5.4.0"
3232
mockk = "1.14.4"
33-
multipaz = "0.94.0"
33+
multipaz = "0.95.0"
3434
nimbus-sdk = "11.20.1"
3535
play-services-identity-credentials = "16.0.0-alpha05"
3636
robolectric = "4.15.1"

wallet-core/src/main/java/eu/europa/ec/eudi/wallet/dcapi/ProcessedDCPAPIRequest.kt

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ import eu.europa.ec.eudi.iso18013.transfer.response.device.ProcessedDeviceReques
3434
import eu.europa.ec.eudi.wallet.internal.d
3535
import eu.europa.ec.eudi.wallet.internal.e
3636
import eu.europa.ec.eudi.wallet.logging.Logger
37+
import kotlinx.coroutines.runBlocking
3738
import org.bouncycastle.util.encoders.Hex
3839
import org.json.JSONObject
3940
import org.multipaz.cbor.Cbor
4041
import org.multipaz.crypto.Algorithm
4142
import org.multipaz.util.fromBase64Url
42-
import org.multipaz.crypto.Crypto
43-
import org.multipaz.crypto.EcPublicKeyDoubleCoordinate
43+
import org.multipaz.crypto.Hpke
4444

4545
/**
4646
* Processes a DCAPI request by generating a response based on the provided device request and credential options.
@@ -100,19 +100,24 @@ class ProcessedDCPAPIRequest(
100100
)
101101

102102
// Encrypt the device response using HPKE
103-
val (cipherText, encapsulatedPublicKey) = Crypto.hpkeEncrypt(
104-
cipherSuite = Algorithm.HPKE_BASE_P256_SHA256_AES128GCM,
105-
receiverPublicKey = recipientPublicKey,
106-
plainText = deviceResponse.deviceResponseBytes,
107-
aad = deviceResponse.sessionTranscriptBytes
108-
)
103+
val (cipherText, encapsulatedPublicKey) = runBlocking {
104+
val encrypter = Hpke.getEncrypter(
105+
cipherSuite = Hpke.CipherSuite.DHKEM_P256_HKDF_SHA256_HKDF_SHA256_AES_128_GCM,
106+
receiverPublicKey = recipientPublicKey,
107+
info = deviceResponse.sessionTranscriptBytes
108+
)
109+
val cipherText = encrypter.encrypt(
110+
plaintext = deviceResponse.deviceResponseBytes,
111+
aad = ByteArray(0)
112+
)
113+
val encapsulatedPublicKey = encrypter.encapsulatedKey.toByteArray()
114+
Pair(cipherText, encapsulatedPublicKey)
115+
}
109116

110-
val enc =
111-
(encapsulatedPublicKey as EcPublicKeyDoubleCoordinate).asUncompressedPointEncoding
112117
val encryptedResponse = CBORObject.NewArray().apply {
113118
Add(DCAPI)
114119
Add(CBORObject.NewMap().apply {
115-
Add(ENC, enc)
120+
Add(ENC, encapsulatedPublicKey)
116121
Add(CIPHER_TEXT, cipherText)
117122
})
118123
}.EncodeToBytes()
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2024-2025 European Commission
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package eu.europa.ec.eudi.wallet.internal
18+
19+
import org.multipaz.securearea.KeyLockedException
20+
import org.multipaz.securearea.KeyUnlockData
21+
import org.multipaz.securearea.KeyUnlockDataProvider
22+
import org.multipaz.securearea.SecureArea
23+
import org.multipaz.securearea.UnlockReason
24+
25+
/**
26+
* Extension function to convert a nullable [KeyUnlockData] to a [KeyUnlockDataProvider].
27+
*
28+
* This allows the existing API that accepts [KeyUnlockData] to work with the new
29+
* multipaz 0.95 API that requires [KeyUnlockDataProvider] in coroutine context.
30+
*
31+
* @return A [KeyUnlockDataProvider] that returns the [KeyUnlockData] when requested,
32+
* or throws [KeyLockedException] if the data is null.
33+
*/
34+
internal fun KeyUnlockData?.asProvider(): KeyUnlockDataProvider {
35+
val data = this
36+
return object : KeyUnlockDataProvider {
37+
override suspend fun getKeyUnlockData(
38+
secureArea: SecureArea,
39+
alias: String,
40+
unlockReason: UnlockReason
41+
): KeyUnlockData {
42+
return data ?: throw KeyLockedException("No unlock data provided")
43+
}
44+
}
45+
}

wallet-core/src/main/java/eu/europa/ec/eudi/wallet/internal/OpenId4VpUtils.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,11 @@ import eu.europa.ec.eudi.wallet.transfer.openId4vp.OpenId4VpConfig
7676
import eu.europa.ec.eudi.wallet.transfer.openId4vp.OpenId4VpReaderTrust
7777
import eu.europa.ec.eudi.wallet.transfer.openId4vp.SdJwtVcItem
7878
import kotlinx.coroutines.runBlocking
79+
import kotlinx.coroutines.withContext
7980
import org.multipaz.credential.SecureAreaBoundCredential
8081
import org.multipaz.crypto.Algorithm
8182
import org.multipaz.securearea.KeyUnlockData
83+
import org.multipaz.securearea.UnlockReason
8284
import java.security.MessageDigest
8385
import java.security.SecureRandom
8486
import java.util.Base64
@@ -331,17 +333,20 @@ internal suspend fun SdJwt<JwtAndClaims>.serializeWithKeyBinding(
331333
): String {
332334
val algorithm = JWSAlgorithm.parse((signatureAlgorithm).joseAlgorithmIdentifier)
333335
val publicKey = credential.secureArea.getKeyInfo(credential.alias).publicKey
336+
val provider = keyUnlockData.asProvider()
334337
val buildKbJwt = NimbusSdJwtOps.kbJwtIssuer(
335338
signer = object : JWSSigner {
336339
override fun getJCAContext(): JCAContext = JCAContext()
337340
override fun supportedJWSAlgorithms(): Set<JWSAlgorithm> = setOf(algorithm)
338341
override fun sign(header: JWSHeader, signingInput: ByteArray): Base64URL {
339342
val signature = runBlocking {
340-
credential.secureArea.sign(
341-
alias = credential.alias,
342-
dataToSign = signingInput,
343-
keyUnlockData = keyUnlockData
344-
)
343+
withContext(provider) {
344+
credential.secureArea.sign(
345+
alias = credential.alias,
346+
dataToSign = signingInput,
347+
unlockReason = UnlockReason.Unspecified
348+
)
349+
}
345350
}
346351
return Base64URL.encode(signature.toJoseEncoded(algorithm))
347352
}

wallet-core/src/main/java/eu/europa/ec/eudi/wallet/provider/SecureAreaWalletKeyManager.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616

1717
package eu.europa.ec.eudi.wallet.provider
1818

19+
import eu.europa.ec.eudi.wallet.internal.asProvider
20+
import kotlinx.coroutines.withContext
1921
import org.multipaz.crypto.Algorithm
2022
import org.multipaz.securearea.CreateKeySettings
2123
import org.multipaz.securearea.KeyInfo
2224
import org.multipaz.securearea.KeyUnlockData
2325
import org.multipaz.securearea.SecureArea
26+
import org.multipaz.securearea.UnlockReason
2427
import java.security.MessageDigest
2528

2629
/**
@@ -72,7 +75,10 @@ open class SecureAreaWalletKeyManager(
7275
}
7376
WalletAttestationKey(keyInfo) { data ->
7477
val keyUnlockData = keyUnlockDataProvider(keyAlias, secureArea)
75-
secureArea.sign(keyAlias, data, keyUnlockData).toDerEncoded()
78+
val provider = keyUnlockData.asProvider()
79+
withContext(provider) {
80+
secureArea.sign(keyAlias, data, UnlockReason.Unspecified).toDerEncoded()
81+
}
7682
}
7783
}
7884

@@ -82,7 +88,10 @@ open class SecureAreaWalletKeyManager(
8288
}.map { keyInfo ->
8389
WalletAttestationKey(keyInfo) { data ->
8490
val keyUnlockData = keyUnlockDataProvider(keyAlias, secureArea)
85-
secureArea.sign(keyAlias, data, keyUnlockData).toDerEncoded()
91+
val provider = keyUnlockData.asProvider()
92+
withContext(provider) {
93+
secureArea.sign(keyAlias, data, UnlockReason.Unspecified).toDerEncoded()
94+
}
8695
}
8796
}.getOrNull()
8897
}

wallet-core/src/main/java/eu/europa/ec/eudi/wallet/transactionLogging/presentation/parsing/MsoMdocParser.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import eu.europa.ec.eudi.wallet.transactionLogging.TransactionLog
2222
import eu.europa.ec.eudi.wallet.transactionLogging.presentation.PresentedClaim
2323
import eu.europa.ec.eudi.wallet.transactionLogging.presentation.PresentedDocument
2424
import eu.europa.ec.eudi.wallet.util.CBOR
25+
import kotlinx.coroutines.runBlocking
2526
import org.multipaz.mdoc.response.DeviceResponseParser
2627

2728
/**
@@ -38,10 +39,12 @@ fun parseMsoMdoc(
3839
metadata: List<String>
3940
): List<PresentedDocument> {
4041
// Parse the raw response using the DeviceResponseParser
41-
val parsed = DeviceResponseParser(
42-
rawResponse,
43-
sessionTranscript ?: byteArrayOf(0)
44-
).parse()
42+
val parsed = runBlocking {
43+
DeviceResponseParser(
44+
rawResponse,
45+
sessionTranscript ?: byteArrayOf(0)
46+
).parse()
47+
}
4548

4649
val parsedMetadata = metadata.map { TransactionLog.Metadata.fromJson(it) }
4750

0 commit comments

Comments
 (0)