Skip to content

Commit e244392

Browse files
committed
Very basic issuance matcher that matches against an allowlist of issuer names
1 parent 43530bb commit e244392

File tree

6 files changed

+168
-53
lines changed

6 files changed

+168
-53
lines changed

app/src/main/assets/provision.wasm

55 KB
Binary file not shown.

app/src/main/java/com/credman/cmwallet/CmWalletApplication.kt

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
package com.credman.cmwallet
22

33
import android.app.Application
4+
import android.graphics.Bitmap
45
import android.util.Log
6+
import androidx.core.graphics.drawable.toBitmap
57
import androidx.credentials.DigitalCredential
68
import androidx.credentials.ExperimentalDigitalCredentialApi
79
import androidx.credentials.provider.CallingAppInfo
810
import androidx.credentials.registry.provider.RegisterCredentialsRequest
911
import androidx.credentials.registry.provider.RegistryManager
1012
import androidx.room.Room
1113
import com.credman.cmwallet.data.repository.CredentialRepository
14+
import com.credman.cmwallet.data.repository.CredentialRepository.Companion.ICON
15+
import com.credman.cmwallet.data.repository.CredentialRepository.Companion.ID
16+
import com.credman.cmwallet.data.repository.CredentialRepository.Companion.LENGTH
17+
import com.credman.cmwallet.data.repository.CredentialRepository.Companion.START
18+
import com.credman.cmwallet.data.repository.CredentialRepository.Companion.SUBTITLE
19+
import com.credman.cmwallet.data.repository.CredentialRepository.Companion.TITLE
20+
import com.credman.cmwallet.data.repository.CredentialRepository.RegistryIcon
1221
import com.credman.cmwallet.data.room.CredentialDatabase
1322
import com.credman.cmwallet.mdoc.MDoc
1423
import com.google.android.gms.identitycredentials.IdentityCredentialClient
@@ -19,8 +28,12 @@ import kotlinx.coroutines.Dispatchers
1928
import kotlinx.coroutines.SupervisorJob
2029
import kotlinx.coroutines.launch
2130
import org.json.JSONObject
31+
import java.io.ByteArrayOutputStream
32+
import java.nio.ByteBuffer
33+
import java.nio.ByteOrder
2234
import kotlin.io.encoding.ExperimentalEncodingApi
2335

36+
2437
class CmWalletApplication : Application() {
2538
companion object {
2639
lateinit var database: CredentialDatabase
@@ -119,7 +132,7 @@ class CmWalletApplication : Application() {
119132

120133
identityCredentialClient.registerCreationOptions(
121134
RegisterCreationOptionsRequest(
122-
createOptions = ByteArray(0),
135+
createOptions = buildIssuanceData(),
123136
matcher = loadIssuanceMatcher(),
124137
type = DigitalCredential.TYPE_DIGITAL_CREDENTIAL,
125138
id = "openid4vci",
@@ -157,8 +170,23 @@ class CmWalletApplication : Application() {
157170
return readAsset("openid4vp1_0.wasm")
158171
}
159172

173+
private fun buildIssuanceData(): ByteArray {
174+
val walletIcon = resources.getDrawable(R.mipmap.ic_launcher, theme).toBitmap()
175+
val iconBuffer = ByteArrayOutputStream()
176+
walletIcon.compress(Bitmap.CompressFormat.PNG, 100, iconBuffer)
177+
178+
val data = CredentialRepository.IssuanceRegistryData(
179+
icon = iconBuffer.toByteArray(),
180+
title = resources.getString(R.string.app_name),
181+
subtitle = "Save your document to CMWallet",
182+
issuerAllowlist = listOf("https://digital-credentials.dev", "http://localhost:8080")
183+
)
184+
185+
return data.toRegistryDatabase()
186+
}
187+
160188
private fun loadIssuanceMatcher(): ByteArray {
161-
return readAsset("provision_hardcoded.wasm")
189+
return readAsset("provision.wasm")
162190
}
163191

164192
private fun loadPhoneNumberMatcher(): ByteArray {

app/src/main/java/com/credman/cmwallet/data/repository/CredentialRepository.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.credman.cmwallet.data.repository
22

3+
import android.graphics.Bitmap
34
import android.os.Build
45
import android.util.Log
6+
import androidx.core.graphics.drawable.toBitmap
57
import androidx.credentials.DigitalCredential
68
import androidx.credentials.ExperimentalDigitalCredentialApi
79
import androidx.credentials.registry.provider.RegisterCredentialsRequest
810
import androidx.credentials.registry.provider.RegistryManager
11+
import com.credman.cmwallet.R
912
import com.credman.cmwallet.data.model.CredentialDisplayData
1013
import com.credman.cmwallet.data.model.CredentialItem
1114
import com.credman.cmwallet.data.model.CredentialKeySoftware
@@ -112,6 +115,46 @@ class CredentialRepository {
112115

113116
}
114117

118+
class IssuanceRegistryData(
119+
val icon: ByteArray, // Entry icon for display
120+
val title: String, // Entry subtitle for display
121+
val subtitle: String?, // Entry subtitle for display
122+
val issuerAllowlist: List<String>,
123+
) {
124+
fun toRegistryDatabase(): ByteArray {
125+
val out = ByteArrayOutputStream()
126+
127+
// Write the offset to the json
128+
val jsonOffset = 4 + icon.size
129+
val buffer = ByteBuffer.allocate(4)
130+
buffer.order(ByteOrder.LITTLE_ENDIAN)
131+
buffer.putInt(jsonOffset)
132+
out.write(buffer.array())
133+
134+
// Write the icons, currently write just one, being the wallet logo
135+
out.write(icon)
136+
137+
val json = JSONObject().apply {
138+
put("display", JSONObject().apply {
139+
put(TITLE, title)
140+
putOpt(SUBTITLE, subtitle)
141+
val iconJson = JSONObject().apply {
142+
put(START, 4)
143+
put(LENGTH, icon.size)
144+
} // Hardcoded for now
145+
put(ICON, iconJson)
146+
})
147+
val capabilities = JSONObject()
148+
for (iss in issuerAllowlist) {
149+
capabilities.put(iss, JSONObject())
150+
}
151+
put("capabilities", capabilities)
152+
}
153+
out.write(json.toString().toByteArray())
154+
return out.toByteArray()
155+
}
156+
}
157+
115158
class RegistryIcon(
116159
val iconValue: ByteArray,
117160
var iconOffset: Int = 0

app/src/main/java/com/credman/cmwallet/pnv/PnvTokenRegistry.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ data class PnvTokenRegistry(
5151
val providerConsent: String?,
5252
val subscriptionHint: Int,
5353
val carrierHint: String,
54+
val androidCarrierHint: Int,
5455
val phoneNumberHint: String?,
5556
val iss: String,
5657
val icon: String? = null,
@@ -65,6 +66,7 @@ data class PnvTokenRegistry(
6566
listOf(
6667
RegistryClaim("subscription_hint", null, subscriptionHint),
6768
RegistryClaim("carrier_hint", null, carrierHint),
69+
RegistryClaim("android_carrier_hint", null, androidCarrierHint),
6870
RegistryClaim("phone_number_hint", null, phoneNumberHint),
6971
),
7072
displayData = ItemDisplayData(title = title, subtitle = subtitle, description = providerConsent),
@@ -94,6 +96,7 @@ data class PnvTokenRegistry(
9496
providerConsent = "CMWallet will enable your carrier (Terrific Telecom) to share your phone number",
9597
subscriptionHint = 1,
9698
carrierHint = "310250",
99+
androidCarrierHint = 3,
97100
phoneNumberHint = "+16502154321",
98101
iss = "https://example.terrific-telecom.dev",
99102
icon = "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAWCAYAAADwza0nAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACBSURBVHgB7ZTBDUVQEEXvff8VoITfC0YZatABHWiH6IUOaICHBCuReXbEWd1kcmZmMRmGIinhSpABFBDoJpqccSKtA/7wY7C71FQ1NUaUyKIg4Ba8MbiJ3YPnqvcnfuI7xAfdqr0qXjU9FTXTGUnca//NIYGdoflla1BbDsPIqZgBHcEomi+uUHMAAAAASUVORK5CYII=",
@@ -110,6 +113,7 @@ data class PnvTokenRegistry(
110113
providerConsent = "CMWallet will enable your carrier (Timely Telecom) to share your phone number",
111114
subscriptionHint = 2,
112115
carrierHint = "380250",
116+
androidCarrierHint = 3,
113117
phoneNumberHint = "+16502157890",
114118
iss = "https://example.timely-telecom.dev",
115119
icon = "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAWCAYAAADwza0nAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAACBSURBVHgB7ZTBDUVQEEXvff8VoITfC0YZatABHWiH6IUOaICHBCuReXbEWd1kcmZmMRmGIinhSpABFBDoJpqccSKtA/7wY7C71FQ1NUaUyKIg4Ba8MbiJ3YPnqvcnfuI7xAfdqr0qXjU9FTXTGUnca//NIYGdoflla1BbDsPIqZgBHcEomi+uUHMAAAAASUVORK5CYII=",

matcher/issuance/provision.c

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <sys/stat.h>
5+
#include <stdint.h>
6+
#include <unistd.h>
7+
#include "../cJSON/cJSON.h"
8+
#include "../credentialmanager.h"
9+
10+
#include "launcher_icon.h"
11+
12+
#define PROTOCOL_OPENID4VCI "openid4vci1.0"
13+
14+
cJSON* GetDCRequestJson() {
15+
uint32_t request_size;
16+
GetRequestSize(&request_size);
17+
char* request_json = malloc(request_size);
18+
GetRequestBuffer(request_json);
19+
return cJSON_Parse(request_json);
20+
}
21+
22+
cJSON* GetCredsJson() {
23+
uint32_t credentials_size;
24+
GetCredentialsSize(&credentials_size);
25+
char* creds_json = malloc(credentials_size);
26+
ReadCredentialsBuffer(creds_json, 0, credentials_size);
27+
return cJSON_Parse(creds_json);
28+
}
29+
30+
int main() {uint32_t credentials_size;
31+
GetCredentialsSize(&credentials_size);
32+
33+
char* creds_blob = malloc(credentials_size);
34+
ReadCredentialsBuffer(creds_blob, 0, credentials_size);
35+
36+
int json_offset = *((int*)creds_blob);
37+
printf("Creds JSON offset %d\n", json_offset);
38+
39+
cJSON* creds = cJSON_Parse(creds_blob + json_offset);
40+
printf("Creds JSON %s\n", cJSON_Print(creds));
41+
/*
42+
{
43+
"display": {
44+
"icon": {...},
45+
"title": "...",
46+
"subtitle": "..."
47+
},
48+
capability: {
49+
"issuer1": {},
50+
"issuer2": {}
51+
}
52+
}
53+
*/
54+
55+
cJSON* dc_request = GetDCRequestJson();
56+
printf("Request JSON %s\n", cJSON_Print(dc_request));
57+
58+
cJSON* requests = cJSON_GetObjectItem(dc_request, "requests");
59+
int requests_size = cJSON_GetArraySize(requests);
60+
for(int i=0; i<requests_size; i++) {
61+
cJSON* request = cJSON_GetArrayItem(requests, i);
62+
char* protocol = cJSON_GetStringValue(cJSON_GetObjectItem(request, "protocol"));
63+
if (strcmp(protocol, PROTOCOL_OPENID4VCI) == 0) {
64+
// We have an OpenID4VCI request
65+
cJSON* cred_offer = cJSON_GetObjectItem(request, "data");
66+
cJSON* credential_issuer = cJSON_GetObjectItem(cred_offer, "credential_issuer");
67+
68+
cJSON* capabilities = cJSON_GetObjectItem(creds, "capabilities");
69+
if(cJSON_HasObjectItem(capabilities, cJSON_GetStringValue(credential_issuer))) {
70+
cJSON* display = cJSON_GetObjectItem(creds, "display");
71+
cJSON* icon = cJSON_GetObjectItem(display, "icon");
72+
int icon_start_int = 0;
73+
int icon_len = 0;
74+
if (icon != NULL) {
75+
cJSON* start = cJSON_GetObjectItem(icon, "start");
76+
cJSON* length = cJSON_GetObjectItem(icon, "length");
77+
if (start != NULL && length != NULL) {
78+
double icon_start = (cJSON_GetNumberValue(start));
79+
icon_start_int = icon_start;
80+
icon_len = (int)(cJSON_GetNumberValue(length));
81+
}
82+
}
83+
cJSON* title = cJSON_GetObjectItem(display, "title");
84+
cJSON* subtitle = cJSON_GetObjectItem(display, "subtitle");
85+
86+
AddStringIdEntry("0", creds_blob + icon_start_int, icon_len, cJSON_GetStringValue(title), cJSON_GetStringValue(subtitle), NULL, NULL);
87+
}
88+
}
89+
}
90+
return 0;
91+
}

matcher/issuance/provision_hardcoded.c

Lines changed: 0 additions & 51 deletions
This file was deleted.

0 commit comments

Comments
 (0)