Skip to content

Commit

Permalink
chore: add DIDComm test using test vectors for recipient/sender (#1151)
Browse files Browse the repository at this point in the history
* chore: add didcomm interop test based on test vectors in spec

* test(didcomm): fix key encoding before import in test

* chore: use correct trust ping message value in test

---------

Co-authored-by: Mircea Nistor <mirceanis@gmail.com>
  • Loading branch information
nickreynolds and mirceanis authored Mar 24, 2023
1 parent 4a63f40 commit 9948ed6
Show file tree
Hide file tree
Showing 4 changed files with 448 additions and 4 deletions.
357 changes: 357 additions & 0 deletions packages/did-comm/src/__tests__/trust-ping-interop.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,357 @@
import { DIDComm } from '../didcomm.js'
import {
IDIDManager,
IIdentifier,
IKeyManager,
IResolver,
TAgent,
} from '../../../core-types/src'
import { createAgent } from '../../../core/src'
import { DIDManager, MemoryDIDStore } from '../../../did-manager/src'
import { KeyManager, MemoryKeyStore, MemoryPrivateKeyStore } from '../../../key-manager/src'
import { KeyManagementSystem } from '../../../kms-local/src'
import { DIDResolverPlugin } from '../../../did-resolver/src'
import { DIDDocument, Resolver } from 'did-resolver'
import { IDIDComm } from '../types/IDIDComm.js'
import { ExampleDidProvider } from '../../../test-utils/src'
import 'cross-fetch/polyfill'
import { base64ToBytes, bytesToHex } from '@veramo/utils'

import * as u8a from 'uint8arrays'

const aliceDoc = {
"@context":[
"https://www.w3.org/ns/did/v1",
"https://w3id.org/security/suites/jws-2020/v1"
],
"id":"did:example:alice",
"authentication":[
{
"id":"did:example:alice#key-1",
"type":"JsonWebKey2020",
"controller":"did:example:alice",
"publicKeyJwk":{
"kty":"OKP",
"crv":"Ed25519",
"x":"G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww"
}
},
{
"id":"did:example:alice#key-2",
"type":"JsonWebKey2020",
"controller":"did:example:alice",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-256",
"x":"2syLh57B-dGpa0F8p1JrO6JU7UUSF6j7qL-vfk1eOoY",
"y":"BgsGtI7UPsObMRjdElxLOrgAO9JggNMjOcfzEPox18w"
}
},
{
"id":"did:example:alice#key-3",
"type":"JsonWebKey2020",
"controller":"did:example:alice",
"publicKeyJwk":{
"kty":"EC",
"crv":"secp256k1",
"x":"aToW5EaTq5mlAf8C5ECYDSkqsJycrW-e1SQ6_GJcAOk",
"y":"JAGX94caA21WKreXwYUaOCYTBMrqaX4KWIlsQZTHWCk"
}
}
],
"keyAgreement":[
{
"id":"did:example:alice#key-x25519-1",
"type":"JsonWebKey2020",
"controller":"did:example:alice",
"publicKeyJwk":{
"kty":"OKP",
"crv":"X25519",
"x":"avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs"
}
},
{
"id":"did:example:alice#key-p256-1",
"type":"JsonWebKey2020",
"controller":"did:example:alice",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-256",
"x":"L0crjMN1g0Ih4sYAJ_nGoHUck2cloltUpUVQDhF2nHE",
"y":"SxYgE7CmEJYi7IDhgK5jI4ZiajO8jPRZDldVhqFpYoo"
}
},
{
"id":"did:example:alice#key-p521-1",
"type":"JsonWebKey2020",
"controller":"did:example:alice",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-521",
"x":"AHBEVPRhAv-WHDEvxVM9S0px9WxxwHL641Pemgk9sDdxvli9VpKCBdra5gg_4kupBDhz__AlaBgKOC_15J2Byptz",
"y":"AciGcHJCD_yMikQvlmqpkBbVqqbg93mMVcgvXBYAQPP-u9AF7adybwZrNfHWCKAQwGF9ugd0Zhg7mLMEszIONFRk"
}
}
]
}

const bobDoc = {
"@context":[
"https://www.w3.org/ns/did/v2"
],
"id":"did:example:bob",
"keyAgreement":[
{
"id":"did:example:bob#key-x25519-1",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"OKP",
"crv":"X25519",
"x":"GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E"
}
},
{
"id":"did:example:bob#key-x25519-2",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"OKP",
"crv":"X25519",
"x":"UT9S3F5ep16KSNBBShU2wh3qSfqYjlasZimn0mB8_VM"
}
},
{
"id":"did:example:bob#key-x25519-3",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"OKP",
"crv":"X25519",
"x":"82k2BTUiywKv49fKLZa-WwDi8RBf0tB0M8bvSAUQ3yY"
}
},
{
"id":"did:example:bob#key-p256-1",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-256",
"x":"FQVaTOksf-XsCUrt4J1L2UGvtWaDwpboVlqbKBY2AIo",
"y":"6XFB9PYo7dyC5ViJSO9uXNYkxTJWn0d_mqJ__ZYhcNY"
}
},
{
"id":"did:example:bob#key-p256-2",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-256",
"x":"n0yBsGrwGZup9ywKhzD4KoORGicilzIUyfcXb1CSwe0",
"y":"ov0buZJ8GHzV128jmCw1CaFbajZoFFmiJDbMrceCXIw"
}
},
{
"id":"did:example:bob#key-p384-1",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-384",
"x":"MvnE_OwKoTcJVfHyTX-DLSRhhNwlu5LNoQ5UWD9Jmgtdxp_kpjsMuTTBnxg5RF_Y",
"y":"X_3HJBcKFQEG35PZbEOBn8u9_z8V1F9V1Kv-Vh0aSzmH-y9aOuDJUE3D4Hvmi5l7"
}
},
{
"id":"did:example:bob#key-p384-2",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-384",
"x":"2x3HOTvR8e-Tu6U4UqMd1wUWsNXMD0RgIunZTMcZsS-zWOwDgsrhYVHmv3k_DjV3",
"y":"W9LLaBjlWYcXUxOf6ECSfcXKaC3-K9z4hCoP0PS87Q_4ExMgIwxVCXUEB6nf0GDd"
}
},
{
"id":"did:example:bob#key-p521-1",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-521",
"x":"Af9O5THFENlqQbh2Ehipt1Yf4gAd9RCa3QzPktfcgUIFADMc4kAaYVViTaDOuvVS2vMS1KZe0D5kXedSXPQ3QbHi",
"y":"ATZVigRQ7UdGsQ9j-omyff6JIeeUv3CBWYsZ0l6x3C_SYqhqVV7dEG-TafCCNiIxs8qeUiXQ8cHWVclqkH4Lo1qH"
}
},
{
"id":"did:example:bob#key-p521-2",
"type":"JsonWebKey2020",
"controller":"did:example:bob",
"publicKeyJwk":{
"kty":"EC",
"crv":"P-521",
"x":"ATp_WxCfIK_SriBoStmA0QrJc2pUR1djpen0VdpmogtnKxJbitiPq-HJXYXDKriXfVnkrl2i952MsIOMfD2j0Ots",
"y":"AEJipR0Dc-aBZYDqN51SKHYSWs9hM58SmRY1MxgXANgZrPaq1EeGMGOjkbLMEJtBThdjXhkS5VlXMkF0cYhZELiH"
}
}
]
}

const trustPingMessage = {
type: 'https://didcomm.org/trust-ping/2.0/ping',
from: 'did:example:alice',
to: 'did:example:bob',
id: 'trust-ping-test',
body: {
responseRequested: true
}
}


describe('trust-ping-interop', () => {
let sender: IIdentifier
let recipient: IIdentifier
let agent: TAgent<IResolver & IKeyManager & IDIDManager & IDIDComm>

beforeAll(async () => {
agent = createAgent<IResolver & IKeyManager & IDIDManager & IDIDComm>({
plugins: [
new KeyManager({
store: new MemoryKeyStore(),
kms: {
local: new KeyManagementSystem(new MemoryPrivateKeyStore()),
},
}),
new DIDManager({
providers: {
'did:example': new ExampleDidProvider(),
},
store: new MemoryDIDStore(),
defaultProvider: 'did:example',
}),
new DIDResolverPlugin({
resolver: new Resolver({
'example': async (did: string) => {
let doc: DIDDocument
if (did === "did:example:alice") {
doc = aliceDoc
} else if (did === "did:example:bob") {
doc = bobDoc
} else {
throw new Error("Bad didUrl for fake resolver: " + did)
}

// DIDResolutionResult
return {
didResolutionMetadata: {},
didDocument: doc,
didDocumentMetadata: {}
}
}
})
}),
new DIDComm()
],
})


// https://identity.foundation/didcomm-messaging/spec/#a1-sender-secrets
const senderSecretEd25519X = 'G-boxFB6vOZBu-wXkm-9Lh79I8nf9Z50cILaOgKKGww'
const senderSecretEd25519D = 'pFRUKkyzx4kHdJtFSnlPA9WzqkDT1HWV0xZ5OYZd2SY'

const senderSecretX25519X = 'avH0O2Y4tqLAq8y9zpianr8ajii5m4F_mICrzNlatXs'
const senderSecretX25519D = 'r-jK2cO3taR8LQnJB1_ikLBTAnOtShJOsHXRUWT-aZA'

sender = await agent.didManagerImport({
did: 'did:example:alice',
keys: [
{
type: 'Ed25519',
kid: 'did:example:alice#key-1',
publicKeyHex: bytesToHex(base64ToBytes(senderSecretEd25519X)),
// we use stablelib/nacl for ed25519, and the preferred encoding for the privateKey there is a 64 byte
// string, where the second half is the precomputed 32 byte encoding of the publicKey. This seems to be the
// preferred encoding in other related libraries too, as the pre-computation speeds up the signing by a few
// milliseconds.
// https://github.com/StableLib/stablelib/blob/a89a438fcbf855de6b2e9faa2630f03c3f3b3a54/packages/ed25519/ed25519.ts#L669
// https://crypto.stackexchange.com/a/54367
// https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#ed25519
privateKeyHex:
bytesToHex(u8a.concat([base64ToBytes(senderSecretEd25519D), base64ToBytes(senderSecretEd25519X)])),
kms: 'local',
},
{
type: 'X25519',
kid: 'did:example:alice#key-x25519-1',
publicKeyHex: bytesToHex(base64ToBytes(senderSecretX25519X)),
privateKeyHex:
bytesToHex(base64ToBytes(senderSecretX25519D)),
kms: 'local',
},
],
provider: 'did:example',
alias: 'alice',
})

recipient = await agent.didManagerImport({
did: 'did:example:bob',
keys: [
{
type: 'X25519',
kid: 'did:example:bob#key-x25519-1',
publicKeyHex: bytesToHex(base64ToBytes('GDTrI66K0pFfO54tlCSvfjjNapIs44dzpneBgyx0S3E')),
privateKeyHex:
bytesToHex(base64ToBytes('b9NnuOCB0hm7YGNvaE9DMhwH_wjZA1-gWD6dA0JWdL0')),
kms: 'local',
},
{
type: 'X25519',
kid: 'did:example:bob#key-x25519-2',
publicKeyHex: bytesToHex(base64ToBytes('UT9S3F5ep16KSNBBShU2wh3qSfqYjlasZimn0mB8_VM')),
privateKeyHex:
bytesToHex(base64ToBytes('p-vteoF1gopny1HXywt76xz_uC83UUmrgszsI-ThBKk')),
kms: 'local',
},
{
type: 'X25519',
kid: 'did:example:bob#key-x25519-3',
publicKeyHex: bytesToHex(base64ToBytes('82k2BTUiywKv49fKLZa-WwDi8RBf0tB0M8bvSAUQ3yY')),
privateKeyHex:
bytesToHex(base64ToBytes('f9WJeuQXEItkGM8shN4dqFr5fLQLBasHnWZ-8dPaSo0')),
kms: 'local',
},
],
provider: 'did:example',
alias: 'bob',
})
})

it('should pack and unpack trust ping message with authcrypt packing', async () => {
const packedMessage = await agent.packDIDCommMessage({ message: trustPingMessage, packing: 'authcrypt' })
const unpackedMessage = await agent.unpackDIDCommMessage(packedMessage)
expect(unpackedMessage.message.id).toEqual(trustPingMessage.id)
})

it('should unpack encrypted message from test vector', async () => {
const unpackedMessage = await agent.unpackDIDCommMessage({
message: '{"protected":"eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLWVuY3J5cHRlZCtqc29uIiwic2tpZCI6ImRpZDpleGFtcGxlOmFsaWNlI2tleS14MjU1MTktMSIsImVuYyI6IlhDMjBQIn0","iv":"VfXAqOwRdCqkCOXtCZmM7xRY6b2cTT5K","ciphertext":"_urtE_Pqw8rGEVkR4iKZiR9qs7U7CCiY5T5sujlSwJnI9V6l4MqXAkfQ_EmSS0bKqrpvB1kXT0vgQQUEfwUeqkXBGiNqd-lBopM1zbaUFIr8x7AobjiVlhDkoA0KVQqICuTUhmt3po5h3wTfNZtB1wiQPF3cYeXg9y6sUVAQ7DyAJdItFcYKiboB3b15nIIP1ld6Bb9r50KD3Gm_DQ","tag":"oq6URRWgtmXePhwQXLeZow","recipients":[{"encrypted_key":"iI92IB_c6z-z9OKbK6GMS54uPJrGefJ9BY5papAvc00","header":{"alg":"ECDH-1PU+XC20PKW","iv":"04K4bQO4q0-x3oiSwvx1vjfIo7DEggyl","tag":"q5DzsirJ4Qrnqr0zosx-sg","epk":{"kty":"OKP","crv":"X25519","x":"KqNpwX_5bvCFMpMwB-ww1z8mJB7jq8Sy1jSbQPHqHxA"},"kid":"did:example:bob#key-x25519-1"}},{"encrypted_key":"Z8mGUR1Q-UIOts1LxIhZNIzbcyp5vj_8ZTWuJ6CxWJE","header":{"alg":"ECDH-1PU+XC20PKW","iv":"g1LwvctMeKDtEcJKQGepuevJnho9WdnX","tag":"up_m3F6B-8RAWvlNEhD4Cg","epk":{"kty":"OKP","crv":"X25519","x":"11cPGXIykWfZBVyCIcn7CisnxXgIS988MtHYD9d3HlM"},"kid":"did:example:bob#key-x25519-2"}},{"encrypted_key":"CsnDZ8TEfeIa5Tu7XqYdxx3r5SnzQDssvhTcmkvzA8g","header":{"alg":"ECDH-1PU+XC20PKW","iv":"-2i2CV7T5ylzk7TLK81lKO1xlvRefIMW","tag":"RtaehpY4C6HxXSuy-PSd6w","epk":{"kty":"OKP","crv":"X25519","x":"nH9Pdu9RCm8znYmhCtGp9hPR_VuS6kcf5zJndTYBVzI"},"kid":"did:example:bob#key-x25519-3"}}]}'
})
expect(unpackedMessage.message.id).toEqual(trustPingMessage.id)
})

it('should pack and unpack trust ping message with anoncrypt packing', async () => {
const packedMessage = await agent.packDIDCommMessage({ message: trustPingMessage, packing: 'authcrypt' })
const unpackedMessage = await agent.unpackDIDCommMessage(packedMessage)
expect(unpackedMessage.message.id).toEqual(trustPingMessage.id)
})

it('should unpack encrypted message from test vector', async () => {
const unpackedMessage = await agent.unpackDIDCommMessage({
message: '{"protected":"eyJ0eXAiOiJhcHBsaWNhdGlvbi9kaWRjb21tLWVuY3J5cHRlZCtqc29uIiwic2tpZCI6ImRpZDpleGFtcGxlOmFsaWNlI2tleS14MjU1MTktMSIsImVuYyI6IlhDMjBQIn0","iv":"8e7Q16uLi4YL7VCEw2E2B9vlC9O7IVn4","ciphertext":"aE0DnTMiiPVxo0WaUNqma4qXnTzPojXnJOkv2vvJ36hoXc5gf5kyCXV8JGVmuR0ib62bZt8RhZCzt-2dmyJc9qot2oz7VesSfrxNOFb1-LB4Tfp2d1KVi96wCeQ_Ca5gr5RPRiQIBuoHHQsuZ2P1_9o49txTlt1AlCS4GwY4QCTnLVNyQTfDweQLwp-OJTMlDoKKgHzBljfovHv4yQ","tag":"ZeItOIGZS3-NvGMbDDKu3w","recipients":[{"encrypted_key":"wDMR_DerdPHrua7edijfseiVsTXKkHXou-U3y_XH2VE","header":{"alg":"ECDH-1PU+XC20PKW","iv":"K8twVbKqWnmISiiwnrCK8308vy0g0By9","tag":"fcgKH3VwAjpSnz-T0UP4bw","epk":{"kty":"OKP","crv":"X25519","x":"zN8qTfSPmxA_OwTnK-JOmVrpwvPTlhFuOXm9qlFsozc"},"kid":"did:example:bob#key-x25519-1"}},{"encrypted_key":"eEJ62Naux0w2xUz-5u2aA-Bt4mcxyeZDOUJS16PxUj8","header":{"alg":"ECDH-1PU+XC20PKW","iv":"uvkmZEbeJ-ThAYTcZHIdSW1O4diVWgTM","tag":"PKxx4DWaPAzWBW_pizYckw","epk":{"kty":"OKP","crv":"X25519","x":"90TtJUXASLgYRUctFByDBUNULqsB47W0-QisRdiDOhg"},"kid":"did:example:bob#key-x25519-2"}},{"encrypted_key":"GEYY8xb9e07x7mmJGrPAJssoZayTBUgDrF9RO2FWHEE","header":{"alg":"ECDH-1PU+XC20PKW","iv":"rp9Oi7vEkD0gJjPe3LMU_IR1Yq5_2umv","tag":"zvFBqklSbyRP4Lsp_eyQEg","epk":{"kty":"OKP","crv":"X25519","x":"R9AkOBdF4nN489pQgqI_NstsdrSpnNsGGEgjgNhdeE8"},"kid":"did:example:bob#key-x25519-3"}}]}'
})
expect(unpackedMessage.message.id).toEqual(trustPingMessage.id)
})
})
6 changes: 2 additions & 4 deletions packages/did-comm/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@ import * as u8a from 'uint8arrays'

import Debug from 'debug'
import {
_ExtendedIKey,
_ExtendedVerificationMethod,
_NormalizedVerificationMethod,
decodeJoseBlob,
extractPublicKeyHex,
isDefined,
mapIdentifierKeysToDoc,
resolveDidOrThrow,
extractPublicKeyHex,
} from '@veramo/utils'

const debug = Debug('veramo:did-comm:action-handler')
Expand Down Expand Up @@ -41,7 +39,7 @@ export async function extractSenderEncryptionKey(
didUrl: protectedHeader.skid,
section: 'keyAgreement',
})) as _ExtendedVerificationMethod
if (!['Ed25519VerificationKey2018', 'X25519KeyAgreementKey2019'].includes(sKey.type)) {
if (!['Ed25519VerificationKey2018', 'X25519KeyAgreementKey2019', 'JsonWebKey2020'].includes(sKey.type)) {
throw new Error(`not_supported: sender key of type ${sKey.type} is not supported`)
}
let publicKeyHex = extractPublicKeyHex(sKey, true)
Expand Down
Loading

0 comments on commit 9948ed6

Please sign in to comment.