Skip to content

Commit fd7cc00

Browse files
authored
feat: add new openid4vp session transcript methods (#82)
Signed-off-by: Timo Glastra <timo@animo.id>
1 parent 153111e commit fd7cc00

File tree

6 files changed

+93
-4
lines changed

6 files changed

+93
-4
lines changed

.changeset/good-starfishes-chew.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"@animo-id/mdoc": minor
3+
---
4+
5+
feat: add new openid4vp session transcript calculation methods.
6+
7+
NOTE that this introduces breaking chnages since `calculateSessionTranscriptBytesForOid4VpDcApi` has been renamed to `calculateSessionTranscriptBytesForOid4VpDcApiDraft24`. The `calculateSessionTranscriptBytesForOid4VpDcApi` method is now used for the latest (draft29/1.0) session transcript structure.
8+
9+
In addtion, `calculateSessionTranscriptBytesForOid4Vp` has been renamed to `calculateSessionTranscriptBytesForOid4VpDraft18`. The `calculateSessionTranscriptBytesForOid4Vp` method is now used for the latest (draft29/1.0) session transcript structure.

src/mdoc/models/session-transcript.ts

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export class SessionTranscript extends CborStructure {
4343
]
4444
}
4545

46-
public static async calculateSessionTranscriptBytesForOid4VpDcApi(
46+
public static async calculateSessionTranscriptBytesForOid4VpDcApiDraft24(
4747
options: { clientId: string; origin: string; verifierGeneratedNonce: string },
4848
ctx: Pick<MdocContext, 'crypto'>
4949
) {
@@ -62,7 +62,54 @@ export class SessionTranscript extends CborStructure {
6262
)
6363
}
6464

65+
public static async calculateSessionTranscriptBytesForOid4VpDcApi(
66+
options: { origin: string; verifierGeneratedNonce: string; jwkThumbprint?: Uint8Array },
67+
ctx: Pick<MdocContext, 'crypto'>
68+
) {
69+
return cborEncode(
70+
DataItem.fromData([
71+
null,
72+
null,
73+
[
74+
'OpenID4VPDCAPIHandover',
75+
await ctx.crypto.digest({
76+
digestAlgorithm: 'SHA-256',
77+
bytes: cborEncode([options.origin, options.verifierGeneratedNonce, options.jwkThumbprint ?? null]),
78+
}),
79+
],
80+
])
81+
)
82+
}
83+
6584
public static async calculateSessionTranscriptBytesForOid4Vp(
85+
options: { clientId: string; verifierGeneratedNonce: string; jwkThumbprint?: Uint8Array; responseUri: string },
86+
ctx: Pick<MdocContext, 'crypto'>
87+
) {
88+
return cborEncode(
89+
DataItem.fromData([
90+
null,
91+
null,
92+
[
93+
'OpenID4VPHandover',
94+
await ctx.crypto.digest({
95+
digestAlgorithm: 'SHA-256',
96+
bytes: cborEncode([
97+
options.clientId,
98+
options.verifierGeneratedNonce,
99+
options.jwkThumbprint ?? null,
100+
options.responseUri,
101+
]),
102+
}),
103+
],
104+
])
105+
)
106+
}
107+
108+
/**
109+
* Calculate the session transcript bytes as defined in 18013-7 first edition, based
110+
* on OpenID4VP draft 18.
111+
*/
112+
public static async calculateSessionTranscriptBytesForOid4VpDraft18(
66113
options: { clientId: string; responseUri: string; verifierGeneratedNonce: string; mdocGeneratedNonce: string },
67114
ctx: Pick<MdocContext, 'crypto'>
68115
) {

tests/examples/france/verify.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ describe('French playground mdoc implementation', () => {
2121
await DeviceResponse.decode(deviceResponse).validate(
2222
{
2323
trustedCertificates: [new Uint8Array(issuerCertificate.rawData)],
24-
sessionTranscript: await SessionTranscript.calculateSessionTranscriptBytesForOid4Vp(
24+
sessionTranscript: await SessionTranscript.calculateSessionTranscriptBytesForOid4VpDraft18(
2525
{
2626
clientId,
2727
responseUri,

tests/examples/google/verify.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ describe('Google CM Wallet mdoc implementation', () => {
2626
// to trust the signing certificate for now
2727
new Uint8Array(signingCertificate.rawData),
2828
],
29-
sessionTranscript: await SessionTranscript.calculateSessionTranscriptBytesForOid4VpDcApi(
29+
sessionTranscript: await SessionTranscript.calculateSessionTranscriptBytesForOid4VpDcApiDraft24(
3030
{
3131
origin,
3232
clientId,

tests/examples/ubique/verify.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ describe('Ubique mdoc implementation', () => {
2121
await DeviceResponse.decode(deviceResponse).validate(
2222
{
2323
trustedCertificates: [new Uint8Array(issuerCertificate.rawData)],
24-
sessionTranscript: await SessionTranscript.calculateSessionTranscriptBytesForOid4Vp(
24+
sessionTranscript: await SessionTranscript.calculateSessionTranscriptBytesForOid4VpDraft18(
2525
{
2626
clientId,
2727
responseUri,

tests/models/session-transcript.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { describe, expect, test } from 'vitest'
2+
import { cborDecode, cborEncode } from '../../src'
23
import { DeviceEngagement } from '../../src/mdoc/models/device-engagement'
34
import { EReaderKey } from '../../src/mdoc/models/e-reader-key'
45
import { NfcHandover } from '../../src/mdoc/models/nfc-handover'
56
import { SessionTranscript } from '../../src/mdoc/models/session-transcript'
67
import { hex } from '../../src/utils'
8+
import { mdocContext } from '../context'
79

810
const cbor =
911
'd81859024183d8185858a20063312e30018201d818584ba4010220012158205a88d182bce5f42efa59943f33359d2e8a968ff289d93e5fa444b624343167fe225820b16e8cf858ddc7690407ba61d4c338237a8cfcf3de6aa672fc60a557aa32fc67d818584ba40102200121582060e3392385041f51403051f2415531cb56dd3f999c71687013aac6768bc8187e225820e58deb8fdbe907f7dd5368245551a34796f7d2215c440c339bb0f7b67beccdfa8258c391020f487315d10209616301013001046d646f631a200c016170706c69636174696f6e2f766e642e626c7565746f6f74682e6c652e6f6f6230081b28128b37282801021c015c1e580469736f2e6f72673a31383031333a646576696365656e676167656d656e746d646f63a20063312e30018201d818584ba4010220012158205a88d182bce5f42efa59943f33359d2e8a968ff289d93e5fa444b624343167fe225820b16e8cf858ddc7690407ba61d4c338237a8cfcf3de6aa672fc60a557aa32fc6758cd91022548721591020263720102110204616301013000110206616301036e6663005102046163010157001a201e016170706c69636174696f6e2f766e642e626c7565746f6f74682e6c652e6f6f6230081b28078080bf2801021c021107c832fff6d26fa0beb34dfcd555d4823a1c11010369736f2e6f72673a31383031333a6e66636e6663015a172b016170706c69636174696f6e2f766e642e7766612e6e616e57030101032302001324fec9a70b97ac9684a4e326176ef5b981c5e8533e5f00298cfccbc35e700a6b020414'
@@ -21,4 +23,35 @@ describe('session transcript', () => {
2123
expect(nh.selectMessage).toBeDefined()
2224
expect(nh.requestMessage).toBeDefined()
2325
})
26+
27+
test('calculateSessionTranscriptBytesForOid4VpDcApi against OpenID4VP test vector', async () => {
28+
const sessionTranscript = await SessionTranscript.calculateSessionTranscriptBytesForOid4VpDcApi(
29+
{
30+
origin: 'https://example.com',
31+
verifierGeneratedNonce: 'exc7gBkxjx1rdc9udRrveKvSsJIq80avlXeLHhGwqtA',
32+
jwkThumbprint: Buffer.from('4283ec927ae0f208daaa2d026a814f2b22dca52cf85ffa8f3f8626c6bd669047', 'hex'),
33+
},
34+
mdocContext
35+
)
36+
37+
expect(Buffer.from(cborEncode(cborDecode(sessionTranscript))).toString('hex')).toEqual(
38+
'83f6f682764f70656e4944345650444341504948616e646f7665725820fbece366f4212f9762c74cfdbf83b8c69e371d5d68cea09cb4c48ca6daab761a'
39+
)
40+
})
41+
42+
test('calculateSessionTranscriptBytesForOid4Vp against OpenID4VP test vector', async () => {
43+
const sessionTranscript = await SessionTranscript.calculateSessionTranscriptBytesForOid4Vp(
44+
{
45+
clientId: 'x509_san_dns:example.com',
46+
verifierGeneratedNonce: 'exc7gBkxjx1rdc9udRrveKvSsJIq80avlXeLHhGwqtA',
47+
jwkThumbprint: Buffer.from('4283ec927ae0f208daaa2d026a814f2b22dca52cf85ffa8f3f8626c6bd669047', 'hex'),
48+
responseUri: 'https://example.com/response',
49+
},
50+
mdocContext
51+
)
52+
53+
expect(Buffer.from(cborEncode(cborDecode(sessionTranscript))).toString('hex')).toEqual(
54+
'83f6f682714f70656e494434565048616e646f7665725820048bc053c00442af9b8eed494cefdd9d95240d254b046b11b68013722aad38ac'
55+
)
56+
})
2457
})

0 commit comments

Comments
 (0)