Skip to content

Add sdJwt presentation #4

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ eudi-document-manager = "0.4.1"
eudi-iso18013-data-transfer = "0.2.0"
eudi-lib-jvm-openid4vci-kt = "dpopNonce-SNAPSHOT"
eudi-lib-jvm-siop-openid4vp-kt = "0.4.2"
eudiLibJvmSdjwtKt = "0.5.1"
gradle-plugin = "7.4.0"
identity-credential = "20231002"
identity-credential-android = "20231002"
Expand All @@ -21,17 +22,23 @@ junit = "4.13.2"
junit-android = "1.1.5"
kotlin = "1.8.10"
ktor = "2.3.5"
#ktorClientSerialization = "2.3.6"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented lines, remove?

mavenPublish = "0.25.3"
mockito-android = "4.0.0"
mockito-inline = "4.0.0"
mockk = "1.13.5"
nimbus-sdk = "11.8"
okhttp = "4.12.0"
retrofit = "2.11.0"
retrofit2KotlinxSerializationConverter = "1.0.0"
securityCrypto = "1.1.0-alpha06"
sonarqube = "4.4.1.3373"
test-core = "1.4.0"
test-rules = "1.4.0"
test-runner = "1.4.0"
upokecenter-cbor = "4.5.2"
kotlin-coroutines-test = "1.3.1"
zkp = "java17-SNAPSHOT"

[libraries]
android-identity-credential = { module = "com.android.identity:identity-credential-android", version.ref = "identity-credential-android" }
Expand All @@ -48,24 +55,31 @@ espresso-intents = { module = "androidx.test.espresso:espresso-intents", version
eudi-document-manager = { module = "eu.europa.ec.eudi:eudi-lib-android-wallet-document-manager", version.ref = "eudi-document-manager" }
eudi-iso18013-data-transfer = { module = "eu.europa.ec.eudi:eudi-lib-android-iso18013-data-transfer", version.ref = "eudi-iso18013-data-transfer" }
eudi-lib-jvm-openid4vci-kt = { module = "com.github.TICESoftware:eudi-lib-jvm-openid4vci-kt", version.ref = "eudi-lib-jvm-openid4vci-kt" }
eudi-lib-jvm-sdjwt-kt = { module = "eu.europa.ec.eudi:eudi-lib-jvm-sdjwt-kt", version.ref = "eudiLibJvmSdjwtKt" }
eudi-lib-jvm-siop-openid4vp-kt = { module = "eu.europa.ec.eudi:eudi-lib-jvm-siop-openid4vp-kt", version.ref = "eudi-lib-jvm-siop-openid4vp-kt" }
identity-credential = { module = "com.android.identity:identity-credential", version.ref = "identity-credential" }
json = { module = "org.json:json", version.ref = "json" }
junit = { module = "junit:junit", version.ref = "junit" }
junit-jupiter-params = { module = "org.junit.jupiter:junit-jupiter-params", version.ref = "junit" }
ktor-client-android = { module = "io.ktor:ktor-client-android", version.ref = "ktor" }
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
#ktor-client-serialization = { module = "io.ktor:ktor-client-serialization", version.ref = "ktorClientSerialization" }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented lines, remove?

mockito-android = { module = "org.mockito:mockito-android", version.ref = "mockito-android" }
mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito-inline" }
mockito-kotlin = { module = "org.mockito.kotlin:mockito-kotlin", version.ref = "mockito-inline" }
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
nimbus-oauth2-oidc-sdk = { module = "com.nimbusds:oauth2-oidc-sdk", version.ref = "nimbus-sdk" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "retrofit2KotlinxSerializationConverter" }
security-crypto = { module = "androidx.security:security-crypto", version.ref = "securityCrypto" }
test-core = { module = "androidx.test:core", version.ref = "test-core" }
test-coreKtx = { module = "androidx.test:core-ktx", version.ref = "test-core" }
test-rules = { module = "androidx.test:rules", version.ref = "test-rules" }
test-runner = { module = "androidx.test:runner", version.ref = "test-runner" }
kotlin-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlin-coroutines-test" }
upokecenter-cbor = { module = "com.upokecenter:cbor", version.ref = "upokecenter-cbor" }
zkp = { module = "com.github.TICESoftware:ZKP", version.ref = "zkp" }

[plugins]
android-library = { id = "com.android.library", version.ref = "gradle-plugin" }
Expand Down
13 changes: 13 additions & 0 deletions wallet-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ dependencies {

// Ktor Android Engine
runtimeOnly libs.ktor.client.android
// implementation libs.ktor.client.serialization

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented lines, remove?

implementation libs.ktor.client.logging

// Bouncy Castle
Expand All @@ -158,6 +159,18 @@ dependencies {
api libs.upokecenter.cbor
api libs.cose.java

// sdjwt
api libs.eudi.lib.jvm.sdjwt.kt
implementation libs.security.crypto

// zkp
api(libs.zkp) {
exclude group: "org.bouncycastle"
}
implementation(libs.retrofit2.kotlinx.serialization.converter)
implementation(libs.retrofit)
implementation(libs.okhttp)

testImplementation libs.junit
testImplementation libs.junit.jupiter.params
testImplementation libs.json
Expand Down
124 changes: 97 additions & 27 deletions wallet-core/src/main/java/eu/europa/ec/eudi/wallet/EudiWallet.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ import eu.europa.ec.eudi.wallet.document.sample.SampleDocumentManager
import eu.europa.ec.eudi.wallet.internal.getCertificate
import eu.europa.ec.eudi.wallet.internal.mainExecutor
import eu.europa.ec.eudi.wallet.issue.openid4vci.*
import eu.europa.ec.eudi.wallet.keystore.KeyGenerator
import eu.europa.ec.eudi.wallet.keystore.KeyGeneratorImpl
import eu.europa.ec.eudi.wallet.transfer.openid4vp.OpenId4VpCBORResponse
import eu.europa.ec.eudi.wallet.transfer.openid4vp.OpenId4VpCBORResponseGeneratorImpl
import eu.europa.ec.eudi.wallet.transfer.openid4vp.OpenId4vpManager
import eu.europa.ec.eudi.wallet.transfer.openid4vp.responseGenerator.OpenId4VpResponseGeneratorDelegator
import eu.europa.ec.eudi.wallet.util.DefaultNfcEngagementService
import java.security.cert.X509Certificate
import java.util.concurrent.Executor
Expand Down Expand Up @@ -68,7 +70,7 @@ import java.util.concurrent.Executor
*
*/
@SuppressLint("StaticFieldLeak")
object EudiWallet {
object EudiWallet : KeyGenerator by KeyGeneratorImpl {

@Volatile
private lateinit var context: Context
Expand All @@ -88,6 +90,7 @@ object EudiWallet {
fun init(context: Context, config: EudiWalletConfig) {
this.context = context.applicationContext
this._config = config
DocumentManagerSdJwt.init(context, config.userAuthenticationRequired)
}

/**
Expand Down Expand Up @@ -197,7 +200,9 @@ object EudiWallet {
* @throws IllegalStateException if [EudiWallet] is not firstly initialized via the [init] method
*/
fun deleteDocumentById(documentId: DocumentId): DeleteDocumentResult =
documentManager.deleteDocumentById(documentId)
documentManager.deleteDocumentById(documentId).apply {
if (this is DeleteDocumentResult.Success) DocumentManagerSdJwt.deleteDocument(documentId)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kurze Frage:
Waren unsere ID's jetzt gesynced, so dass das funktionieren kann?
(Oder nicht und wir müssen das noch einmal anpassen?)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Die Id´s sind nicht synced, aber wir gehen davon aus, dass wir nur ein SdJwt haben können und löschen das wenn irgendein Mdoc gelöscht wird. Das ist good enough würde ich sagen. Wir sollten in die Lib noch einen Check einbauen, dass man nicht mehr als ein Pid haben kann, damit hier nichts kaputt gehen kann

}

/**
* Create an [UnsignedDocument] for the given [docType]
Expand All @@ -224,7 +229,10 @@ object EudiWallet {
* @return [StoreDocumentResult]
* @throws IllegalStateException if [EudiWallet] is not firstly initialized via the [init] method
*/
fun storeIssuedDocument(unsignedDocument: UnsignedDocument, data: ByteArray): StoreDocumentResult =
fun storeIssuedDocument(
unsignedDocument: UnsignedDocument,
data: ByteArray
): StoreDocumentResult =
documentManager.storeIssuedDocument(unsignedDocument, data)

private var openId4VciManager: OpenId4VciManager? = null
Expand Down Expand Up @@ -280,7 +288,15 @@ object EudiWallet {
config(config)
logger = this@EudiWallet.logger
ktorHttpClientFactory = _config.ktorHttpClientFactory
}.also { it.issueDocumentByDocType(docType, txCode, executor, authorizationHandler, onEvent) }
}.also {
it.issueDocumentByDocType(
docType,
txCode,
executor,
authorizationHandler,
onEvent
)
}
} ?: run {
(executor ?: context.mainExecutor()).execute {
onEvent(IssueEvent.failure(IllegalStateException("OpenId4Vci config is not set in configuration")))
Expand Down Expand Up @@ -316,7 +332,15 @@ object EudiWallet {
config(config)
logger = this@EudiWallet.logger
ktorHttpClientFactory = _config.ktorHttpClientFactory
}.also { it.issueDocumentByOffer(offer, txCode, executor, authorizationHandler, onEvent) }
}.also {
it.issueDocumentByOffer(
offer,
txCode,
executor,
authorizationHandler,
onEvent
)
}
} ?: run {
(executor ?: context.mainExecutor()).execute {
onEvent(IssueEvent.failure(IllegalStateException("OpenId4Vci config is not set in configuration")))
Expand Down Expand Up @@ -351,7 +375,15 @@ object EudiWallet {
config(config)
logger = this@EudiWallet.logger
ktorHttpClientFactory = _config.ktorHttpClientFactory
}.also { it.issueDocumentByOfferUri(offerUri, txCode, executor, authorizationHandler, onEvent) }
}.also {
it.issueDocumentByOfferUri(
offerUri,
txCode,
executor,
authorizationHandler,
onEvent
)
}
} ?: run {
(executor ?: context.mainExecutor()).execute {
onEvent(IssueEvent.failure(IllegalStateException("OpenId4Vci config is not set in configuration")))
Expand Down Expand Up @@ -383,7 +415,12 @@ object EudiWallet {
ktorHttpClientFactory = _config.ktorHttpClientFactory
}.also {
when (val document = documentManager.getDocumentById(documentId)) {
is DeferredDocument -> it.issueDeferredDocument(document, executor, onResult)
is DeferredDocument -> it.issueDeferredDocument(
document,
executor,
onResult
)

else -> (executor ?: context.mainExecutor()).execute {
onResult(
DeferredIssueResult.DocumentFailed(
Expand Down Expand Up @@ -474,8 +511,16 @@ object EudiWallet {
* @return [EudiWallet]
*/
fun setTrustedReaderCertificates(trustedReaderCertificates: List<X509Certificate>) = apply {
deviceResponseGenerator.setReaderTrustStore(ReaderTrustStore.getDefault(trustedReaderCertificates))
openId4VpCBORResponseGenerator.setReaderTrustStore(ReaderTrustStore.getDefault(trustedReaderCertificates))
deviceResponseGenerator.setReaderTrustStore(
ReaderTrustStore.getDefault(
trustedReaderCertificates
)
)
openId4VpCBORResponseGenerator.setReaderTrustStore(
ReaderTrustStore.getDefault(
trustedReaderCertificates
)
)
}

/**
Expand Down Expand Up @@ -630,9 +675,10 @@ object EudiWallet {
// create response
val responseResult = when (transferMode) {
TransferMode.OPENID4VP ->
openId4vpManager?.responseGenerator?.createResponse(disclosedDocuments) ?: ResponseResult.Failure(
Throwable("Openid4vpManager has not been initialized properly")
)
openId4vpManager?.responseGenerator?.createResponse(disclosedDocuments)
?: ResponseResult.Failure(
Throwable("Openid4vpManager has not been initialized properly")
)

TransferMode.ISO_18013_5, TransferMode.REST_API ->
transferManager.responseGenerator.createResponse(disclosedDocuments)
Expand All @@ -645,7 +691,13 @@ object EudiWallet {
is ResponseResult.Success -> {
when (transferMode) {
TransferMode.OPENID4VP ->
openId4vpManager?.sendResponse((responseResult.response as OpenId4VpCBORResponse).deviceResponseBytes)
openId4vpManager?.sendResponse(
when (val result = responseResult.response) {
is OpenId4VpCBORResponse -> result.deviceResponseBytes
is DeviceResponse -> result.deviceResponseBytes
else -> throw Exception()
}
)

TransferMode.ISO_18013_5, TransferMode.REST_API ->
transferManager.sendResponse((responseResult.response as DeviceResponse).deviceResponseBytes)
Expand Down Expand Up @@ -695,18 +747,36 @@ object EudiWallet {

private val transferManagerDocumentsResolver: DocumentsResolver
get() = DocumentsResolver { req ->
documentManager.getDocuments(Document.State.ISSUED)
.filterIsInstance<IssuedDocument>()
.filter { doc -> doc.docType == req.docType }
.map { doc ->
RequestDocument(
documentId = doc.id,
docType = doc.docType,
docName = doc.name,
userAuthentication = doc.requiresUserAuth,
docRequest = req
)

return@DocumentsResolver when (OpenId4VpResponseGeneratorDelegator.formatState) {
is OpenId4VpResponseGeneratorDelegator.FormatState.SdJwt -> {
DocumentManagerSdJwt
.getAllDocuments()
.map { doc ->
RequestDocument(
documentId = doc.id,
docType = doc.vct,
docName = doc.docName,
userAuthentication = doc.requiresUserAuth,
docRequest = req
)
}
}

is OpenId4VpResponseGeneratorDelegator.FormatState.Cbor -> {
documentManager.getDocuments(Document.State.ISSUED)
.filterIsInstance<IssuedDocument>()
.map { doc ->
RequestDocument(
documentId = doc.id,
docType = doc.docType,
docName = doc.name,
userAuthentication = doc.requiresUserAuth,
docRequest = req
)
}
}
}
}

private val deviceResponseGenerator: ResponseGenerator<DeviceRequest> by lazy {
Expand All @@ -721,9 +791,9 @@ object EudiWallet {
}
}

private val openId4VpCBORResponseGenerator: OpenId4VpCBORResponseGeneratorImpl by lazy {
private val openId4VpCBORResponseGenerator: OpenId4VpResponseGeneratorDelegator by lazy {
requireInit {
OpenId4VpCBORResponseGeneratorImpl.Builder(context)
OpenId4VpResponseGeneratorDelegator.Builder(context)
.apply {
_config.trustedReaderCertificates?.let {
readerTrustStore = ReaderTrustStore.getDefault(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import eu.europa.ec.eudi.openid4vci.*
*/
internal data class DefaultOffer(
@JvmSynthetic val credentialOffer: CredentialOffer,
@JvmSynthetic val credentialConfigurationFilter: CredentialConfigurationFilter = CredentialConfigurationFilter.MsoMdocFormatFilter,
@JvmSynthetic val credentialConfigurationFilter: CredentialConfigurationFilter = CredentialConfigurationFilter.SdJwtOrMsoMdocFormatFilter,
) : Offer {

private val issuerMetadata: CredentialIssuerMetadata
Expand All @@ -41,8 +41,9 @@ internal data class DefaultOffer(

override val offeredDocuments: List<Offer.OfferedDocument>
get() = issuerMetadata.credentialConfigurationsSupported
.filterKeys { it in credentialOffer.credentialConfigurationIdentifiers }
.filterValues { credentialConfigurationFilter(it) }
// TODO temporarily removed to make it work
//.filterKeys { it in credentialOffer.credentialConfigurationIdentifiers }
//.filterValues { credentialConfigurationFilter(it) }
Comment on lines +45 to +46

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uncommented code, remove?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still uncommented.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hab einen Kommentar drüber damit man weiß, dass das wieder rein muss

.map { (id, conf) -> DefaultOfferedDocument(id, conf) }

override val txCodeSpec: Offer.TxCodeSpec?
Expand Down Expand Up @@ -92,7 +93,7 @@ internal val CredentialConfiguration.name: String
internal val CredentialConfiguration.docType: String
@JvmSynthetic get() = when (this) {
is MsoMdocCredential -> docType
is SdJwtVcCredential -> "eu.europa.ec.eudi.pid_jwt_vc_json"
is SdJwtVcCredential -> "eu.europa.ec.eudi.pid.1"
else -> "unknown"
}

Expand Down
Loading
Loading