Skip to content

Commit

Permalink
Implemented bare-bones wallet server that provides issuing service. (R…
Browse files Browse the repository at this point in the history
…esolves #605)

Signed-off-by: Peter Sorotokin <sorotokin@gmail.com>
  • Loading branch information
sorotokin committed May 15, 2024
1 parent 4dbf1f9 commit bd12690
Show file tree
Hide file tree
Showing 70 changed files with 1,689 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,19 @@ class CborSymbolProcessor(
val declaration = type.declaration
val qualifiedName = declaration.qualifiedName!!.asString()
return when (qualifiedName) {
"kotlin.collections.Map" ->
"kotlin.collections.Map", "kotlin.collections.MutableMap" ->
with(codeBuilder) {
val map = varName("map")
line("val $map = mutableMapOf<${typeArguments(this, type)}>()")
addDeserializedMapValues(this, map, code, type)
map
}

"kotlin.collections.List", "kotlin.collections.Set" ->
"kotlin.collections.List", "kotlin.collections.MutableList",
"kotlin.collections.Set", "kotlin.collections.MutableSet" ->
with(codeBuilder) {
val array = varName("array")
val builder = if (qualifiedName == "kotlin.collections.Set") {
val builder = if (qualifiedName.endsWith("Set")) {
"mutableSetOf"
} else {
"mutableListOf"
Expand Down Expand Up @@ -169,7 +170,7 @@ class CborSymbolProcessor(
val declaration = type.declaration
val qualifiedName = declaration.qualifiedName!!.asString()
when (qualifiedName) {
"kotlin.collections.Map" ->
"kotlin.collections.Map", "kotlin.collections.MutableMap" ->
with(codeBuilder) {
val map = varName("map")
val mapBuilder = varName("mapBuilder")
Expand All @@ -180,7 +181,8 @@ class CborSymbolProcessor(
return map
}

"kotlin.collections.List", "kotlin.collections.Set" ->
"kotlin.collections.List", "kotlin.collections.MutableList",
"kotlin.collections.Set", "kotlin.collections.MutableSet" ->
with(codeBuilder) {
val array = varName("array")
val arrayBuilder = varName("arrayBuilder")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ class FlowSymbolProcessor(
line("flowComplete = true")
}
emptyLine()
block("fun checkFlowNotComplete()") {
block("private fun checkFlowNotComplete()") {
block("if (flowComplete)") {
line("throw IllegalStateException(\"flow is already complete\")")
}
Expand Down Expand Up @@ -360,18 +360,20 @@ class FlowSymbolProcessor(
emptyLine()
block("override suspend fun ${opDeclaration(this, op)}") {
line("checkFlowNotComplete()")
val parameters = op.parameters.map { parameter ->
if (parameter.flowTypeInfo == null) {
CborSymbolProcessor.serializeValue(
this, parameter.name, parameter.type
)
} else {
"${parameter.name}.flowState"
}
}
line("val flowParameters = listOf<DataItem>(")
withIndent {
line("this.flowState,")
op.parameters.forEach { parameter ->
val serialization = if (parameter.flowTypeInfo == null) {
CborSymbolProcessor.serializeValue(
this, parameter.name, parameter.type
)
} else {
"${parameter.name}.flowState"
}
line("$serialization,")
parameters.forEach { parameter ->
line("$parameter,")
}
}
line(")")
Expand Down
6 changes: 6 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
[versions]
compile-sdk = "34"
javax-servlet-api = "4.0.1"
kotlin-reflect = "1.9.23"
min-sdk = "26"
dokka = "1.9.20"
Expand Down Expand Up @@ -52,6 +53,7 @@
ktlint = "12.1.0"
tink = "1.13.0"
kotlin-test = "1.9.20"
ktor = "2.3.10"

[libraries]
androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "core-ktx" }
Expand Down Expand Up @@ -138,6 +140,10 @@

kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin-test"}

ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
javax-servlet-api = { module = "javax.servlet:javax.servlet-api", version.ref = "javax-servlet-api" }

[bundles]
androidx-core = ["androidx-core-ktx", "androidx-appcompat", "androidx-material", "androidx-contraint-layout", "androidx-fragment-ktx", "androidx-legacy-v4", "androidx-preference-ktx", "androidx-work"]
androidx-lifecycle = ["androidx-lifecycle-extensions", "androidx-lifecycle-livedata", "androidx-lifecycle-viewmodel"]
Expand Down
4 changes: 4 additions & 0 deletions identity-doctypes/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ plugins {
alias libs.plugins.dokka
}

kotlin {
jvmToolchain(17)
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
Expand Down
4 changes: 4 additions & 0 deletions identity-sdjwt/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ plugins {
alias libs.plugins.dokka
}

kotlin {
jvmToolchain(17)
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ sealed class EcPublicKey(
return sb.toString()
}

val toDataItem: DataItem
get() {
return toCoseKey().toDataItem
}

companion object {
/**
* Creates an [EcPublicKey] from a PEM encoded string.
Expand Down Expand Up @@ -118,6 +123,9 @@ sealed class EcPublicKey(
}
}

fun fromDataItem(dataItem: DataItem): EcPublicKey {
return CoseKey.fromDataItem(dataItem).ecPublicKey
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ dependencyResolutionManagement {
rootProject.name = 'Identity Credential'

// Libraries
include ':identity', ':identity-doctypes', ':identity-mdoc', ':identity-sdjwt', ':identity-android', ':identity-android-legacy', ':mrtd-reader', ':jpeg2k', ':cbor-processor'
include ':identity', ':identity-doctypes', ':identity-mdoc', ':identity-sdjwt', ':identity-android', ':identity-android-legacy', ':mrtd-reader', ':jpeg2k', ':cbor-processor', ":wallet-issuance"
// Android apps
include ':appholder', ':appverifier', ':secure-area-test-app', ':wwwverifier', ':wallet'
// Server-side apps
include ':wwwverifier'
include ':wwwverifier', ":wallet-server"
// Command-line tool
include ':identityctl'
// Samples
Expand Down
1 change: 1 addition & 0 deletions wallet-issuance/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
25 changes: 25 additions & 0 deletions wallet-issuance/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
plugins {
id 'java-library'
alias libs.plugins.org.jetbrains.kotlin.jvm
alias libs.plugins.dokka
alias libs.plugins.ksp
}

java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

kotlin {
jvmToolchain(17)
}

dependencies {
implementation project(':cbor-processor')
implementation project(':identity')
implementation project(':identity-doctypes')
implementation project(':identity-mdoc')
implementation libs.kotlinx.datetime

ksp project(':cbor-processor')
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.android.identity.issuance

import com.android.identity.cbor.annotation.CborSerializable

/**
* The configuration to use when creating new credentials.
*/
@CborSerializable
data class CredentialConfiguration(
/**
* The challenge to use when creating the device-bound key.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.android.identity.issuance

import com.android.identity.cbor.annotation.CborSerializable
import com.android.identity.crypto.EcPublicKey
import kotlinx.datetime.Instant

/**
* This data structure contains a data for a credential, minted by the issuer.
*/
@CborSerializable
data class CredentialData(
/**
* The secure-area bound key that the credential is for.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package com.android.identity.issuance

import com.android.identity.cbor.annotation.CborSerializable
import com.android.identity.crypto.CertificateChain

/**
* A request for the issuer to mint a credential
*/
@CborSerializable
data class CredentialRequest(
/**
* The requested credential presentation format.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package com.android.identity.issuance

import com.android.identity.cbor.Cbor
import com.android.identity.cbor.CborMap
import com.android.identity.cbor.DataItem
import com.android.identity.cbor.Simple
import com.android.identity.cbor.annotation.CborSerializable
import com.android.identity.document.NameSpacedData

/**
Expand Down Expand Up @@ -47,27 +49,33 @@ data class DocumentConfiguration(
) {
companion object {
fun fromCbor(encodedData: ByteArray): DocumentConfiguration {
val map = Cbor.decode(encodedData)
return fromDataItem(Cbor.decode(encodedData))
}

fun fromDataItem(dataItem: DataItem): DocumentConfiguration {
return DocumentConfiguration(
map["name"].asTstr,
map["cardArt"].asBstr,
map["mdocDocType"].asTstr,
NameSpacedData.fromEncodedCbor(map["staticData"].asBstr),
map.getOrDefault("requireUserAuthenticationToViewDocument", Simple.FALSE).asBoolean
dataItem["name"].asTstr,
dataItem["cardArt"].asBstr,
dataItem["mdocDocType"].asTstr,
NameSpacedData.fromEncodedCbor(dataItem["staticData"].asBstr),
dataItem.getOrDefault("requireUserAuthenticationToViewDocument", Simple.FALSE).asBoolean
)
}

}

fun toCbor(): ByteArray {
return Cbor.encode(
CborMap.builder()
.put("name", displayName)
.put("cardArt", cardArt)
.put("mdocDocType", mdocDocType)
.put("staticData", staticData.encodeAsCbor())
.put("requireUserAuthenticationToViewDocument", requireUserAuthenticationToViewDocument)
.end()
.build())
return Cbor.encode(toDataItem)
}

val toDataItem: DataItem
get() {
return CborMap.builder()
.put("name", displayName)
.put("cardArt", cardArt)
.put("mdocDocType", mdocDocType)
.put("staticData", staticData.encodeAsCbor())
.put("requireUserAuthenticationToViewDocument", requireUserAuthenticationToViewDocument)
.end()
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package com.android.identity.issuance

import com.android.identity.cbor.Cbor
import com.android.identity.cbor.CborMap
import com.android.identity.cbor.DataItem
import kotlinx.datetime.Instant

/**
Expand Down Expand Up @@ -36,24 +37,31 @@ data class DocumentState(
) {
companion object {
fun fromCbor(encodedData: ByteArray): DocumentState {
val map = Cbor.decode(encodedData)
return fromDataItem(Cbor.decode(encodedData))
}

fun fromDataItem(dataItem: DataItem): DocumentState {
return DocumentState(
Instant.fromEpochMilliseconds(map["timestamp"].asNumber),
DocumentCondition.fromInt(map["condition"].asNumber.toInt()),
map["numPendingCredentials"].asNumber.toInt(),
map["numAvailableCredentials"].asNumber.toInt()
Instant.fromEpochMilliseconds(dataItem["timestamp"].asNumber),
DocumentCondition.fromInt(dataItem["condition"].asNumber.toInt()),
dataItem["numPendingCredentials"].asNumber.toInt(),
dataItem["numAvailableCredentials"].asNumber.toInt()
)
}
}

fun toCbor(): ByteArray {
return Cbor.encode(
CborMap.builder()
return Cbor.encode(toDataItem)
}

val toDataItem: DataItem
get() {
return CborMap.builder()
.put("timestamp", timestamp.toEpochMilliseconds())
.put("condition", condition.value)
.put("numPendingCredentials", numPendingCredentials)
.put("numAvailableCredentials", numAvailableCredentials)
.end()
.build())
}
.build()
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.android.identity.issuance

import com.android.identity.cbor.annotation.CborSerializable

/**
* Configuration data for the issuing authority.
*
* This data is static and available to the application before any documents are provisioned.
* It can be used to present a menu of available documents to the user.
*/
@CborSerializable
data class IssuingAuthorityConfiguration(
/**
* Unique identifier for this object
Expand Down

0 comments on commit bd12690

Please sign in to comment.