-
Notifications
You must be signed in to change notification settings - Fork 0
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
Changes from 7 commits
b2774ed
f355664
500c785
8f8f73e
df11201
8676c49
c9d2e6f
143dea7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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" | ||
|
@@ -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" | ||
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" } | ||
|
@@ -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" } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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" } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,6 +149,7 @@ dependencies { | |
|
||
// Ktor Android Engine | ||
runtimeOnly libs.ktor.client.android | ||
// implementation libs.ktor.client.serialization | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Commented lines, remove? |
||
implementation libs.ktor.client.logging | ||
|
||
// Bouncy Castle | ||
|
@@ -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 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -68,7 +70,7 @@ import java.util.concurrent.Executor | |
* | ||
*/ | ||
@SuppressLint("StaticFieldLeak") | ||
object EudiWallet { | ||
object EudiWallet : KeyGenerator by KeyGeneratorImpl { | ||
|
||
@Volatile | ||
private lateinit var context: Context | ||
|
@@ -88,6 +90,7 @@ object EudiWallet { | |
fun init(context: Context, config: EudiWalletConfig) { | ||
this.context = context.applicationContext | ||
this._config = config | ||
DocumentManagerSdJwt.init(context, config.userAuthenticationRequired) | ||
} | ||
|
||
/** | ||
|
@@ -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) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kurze Frage: There was a problem hiding this comment. Choose a reason for hiding this commentThe 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] | ||
|
@@ -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 | ||
|
@@ -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"))) | ||
|
@@ -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"))) | ||
|
@@ -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"))) | ||
|
@@ -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( | ||
|
@@ -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 | ||
) | ||
) | ||
} | ||
|
||
/** | ||
|
@@ -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) | ||
|
@@ -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) | ||
|
@@ -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 { | ||
|
@@ -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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 | ||
|
@@ -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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Uncommented code, remove? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still uncommented. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? | ||
|
@@ -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" | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented lines, remove?