From b7fec43701637996ca6e198a38f0330b1111d74d Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Mon, 9 Dec 2024 15:48:46 +0100 Subject: [PATCH 1/2] `encrypt/decryptMessage`: throw if `context` input provided without signing/verification keys Sanity check to catch mistakes in case library users wrongly consider the `context` to be applied thorugh e.g. the AEAD associated data instead of the signature. --- lib/message/decrypt.js | 6 ++++++ lib/message/encrypt.js | 6 ++++++ test/message/context.spec.ts | 23 +++++++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/lib/message/decrypt.js b/lib/message/decrypt.js index 1073bb25..a7757679 100644 --- a/lib/message/decrypt.js +++ b/lib/message/decrypt.js @@ -12,6 +12,12 @@ export default async function decryptMessage({ config = {}, ...options }) { + if (context && !options.verificationKeys?.length) { + // sanity check to catch mistakes in case library users wrongly consider the `context` to be + // applied into e.g. the AEAD associated data + throw new Error('Unexpected `context` input without any `verificationKeys` provided'); + } + const sanitizedOptions = { ...options, date, diff --git a/lib/message/encrypt.js b/lib/message/encrypt.js index f7f86471..1db5ea27 100644 --- a/lib/message/encrypt.js +++ b/lib/message/encrypt.js @@ -14,6 +14,12 @@ export default async function encryptMessage({ detached = false, ...options }) { + if (context && !options.signingKeys?.length) { + // sanity check to catch mistakes in case library users wrongly consider the `context` to be + // applied into e.g. the AEAD associated data + throw new Error('Unexpected `context` input without any `signingKeys` provided'); + } + const sanitizedOptions = { ...options, signatureNotations: context ? getNotationForContext(context.value, context.critical) : undefined, // only applied if signingKeys are given diff --git a/test/message/context.spec.ts b/test/message/context.spec.ts index 60e3516a..d093073a 100644 --- a/test/message/context.spec.ts +++ b/test/message/context.spec.ts @@ -206,6 +206,29 @@ describe('context', () => { expect(decryptionMissingContext.verificationErrors![0]).to.match(/Unknown critical notation: context@proton/); }); + it.only('encryptMessage/decryptMessage - it throws if context is provided without signingKeys or verificationKeys', async () => { + // missing signing keys + await expect(encryptMessage({ + textData: 'message with context', + sessionKey: { algorithm: 'aes128', data: new Uint8Array(16) }, // unused + context: { value: 'test-context', critical: true } + })).to.be.rejectedWith(/Unexpected `context` input without any `signingKeys` provided/); + + // missing verification keys + await expect(decryptMessage({ + message: await readMessage({ armoredMessage: `-----BEGIN PGP MESSAGE----- + +wV4D+XE4B6yFCrUSAQdAur2W1bvOByAj6fDqTNLLCED/QO9StAS5MKr0ud6l +0hswcvpQaq/Bup46mgO2n2f1hgv9wwlKq7hYYyHJWJ631Ai4yifFZy+rnAv/ +kGXdMLE/1EcBCQEMWzWe+L8qO3Vq0Yr7aLeW93PCFLxl+J9wQMIqnl4EiOYh +sJFJxllC0j4wHCOS9uiSYsZ/pWCqxX/3sFh4VBFOpr0HAA== +=S5ns +-----END PGP MESSAGE-----` }), + sessionKeys: { algorithm: 'aes128', data: new Uint8Array(16) }, // unused + context: { value: 'test-context', required: true } + })).to.be.rejectedWith(/Unexpected `context` input without any `verificationKeys` provided/); + }); + it('does not verify a message without context', async () => { const { privateKey, publicKey } = await generateKey({ userIDs: [{ name: 'name', email: 'email@test.com' }], From 491d0b23907c375b5a8ad2746dbf7f0f6bf0b5ea Mon Sep 17 00:00:00 2001 From: larabr <7375870+larabr@users.noreply.github.com> Date: Mon, 9 Dec 2024 16:07:05 +0100 Subject: [PATCH 2/2] `encrypt/decrypt/sign/verifyMessage`: rename `context` option into `signatureContext` To clarify usage --- lib/message/context.ts | 4 +-- lib/message/decrypt.js | 10 +++--- lib/message/encrypt.js | 10 +++--- lib/message/sign.js | 6 ++-- lib/message/verify.d.ts | 4 +-- lib/message/verify.js | 16 ++++----- lib/pmcrypto.d.ts | 8 ++--- lib/pmcrypto.js | 2 +- test/message/context.spec.ts | 66 ++++++++++++++++++------------------ 9 files changed, 65 insertions(+), 61 deletions(-) diff --git a/lib/message/context.ts b/lib/message/context.ts index 17d026cd..a7e8f1c0 100644 --- a/lib/message/context.ts +++ b/lib/message/context.ts @@ -89,10 +89,10 @@ export const getConfigForContextVerification = (config: PartialConfig) => ({ * Context verification error. * Thrown if e.g. context information is not present in the signature, or it does not match the expected context. */ -export class ContextError extends Error { +export class SignatureContextError extends Error { constructor(message: string) { super(message); - this.name = 'ContextError'; + this.name = 'SignatureContextError'; } } diff --git a/lib/message/decrypt.js b/lib/message/decrypt.js index a7757679..7e4635d8 100644 --- a/lib/message/decrypt.js +++ b/lib/message/decrypt.js @@ -8,20 +8,20 @@ import { DEFAULT_SIGNATURE_VERIFICATION_OFFSET } from '../constants'; export default async function decryptMessage({ date = new Date(+serverTime() + DEFAULT_SIGNATURE_VERIFICATION_OFFSET), encryptedSignature, - context, + signatureContext, config = {}, ...options }) { - if (context && !options.verificationKeys?.length) { + if (signatureContext && (options.verificationKeys === undefined || options.verificationKeys.length === 0)) { // sanity check to catch mistakes in case library users wrongly consider the `context` to be // applied into e.g. the AEAD associated data - throw new Error('Unexpected `context` input without any `verificationKeys` provided'); + throw new Error('Unexpected `signatureContext` input without any `verificationKeys` provided'); } const sanitizedOptions = { ...options, date, - config: context ? getConfigForContextVerification(config) : config + config: signatureContext ? getConfigForContextVerification(config) : config }; try { @@ -36,7 +36,7 @@ export default async function decryptMessage({ } const decryptionResult = await decrypt(sanitizedOptions); - const verificationResult = handleVerificationResult(decryptionResult, context, options.expectSigned); + const verificationResult = handleVerificationResult(decryptionResult, signatureContext, options.expectSigned); let verified = verificationResult.then((result) => result.verified); let verifiedSignatures = verificationResult.then((result) => result.signatures); diff --git a/lib/message/encrypt.js b/lib/message/encrypt.js index 1db5ea27..906f1f7a 100644 --- a/lib/message/encrypt.js +++ b/lib/message/encrypt.js @@ -8,21 +8,23 @@ export default async function encryptMessage({ textData, binaryData, stripTrailingSpaces, - context, + signatureContext, format = 'armored', date = serverTime(), detached = false, ...options }) { - if (context && !options.signingKeys?.length) { + if (signatureContext && (options.signingKeys === undefined || options.signingKeys.length === 0)) { // sanity check to catch mistakes in case library users wrongly consider the `context` to be // applied into e.g. the AEAD associated data - throw new Error('Unexpected `context` input without any `signingKeys` provided'); + throw new Error('Unexpected `signatureContext` input without any `signingKeys` provided'); } const sanitizedOptions = { ...options, - signatureNotations: context ? getNotationForContext(context.value, context.critical) : undefined, // only applied if signingKeys are given + signatureNotations: signatureContext ? + getNotationForContext(signatureContext.value, signatureContext.critical) : + undefined, date, format }; diff --git a/lib/message/sign.js b/lib/message/sign.js index d02cad46..421e67d8 100644 --- a/lib/message/sign.js +++ b/lib/message/sign.js @@ -17,7 +17,7 @@ export default async function signMessage({ textData, binaryData, stripTrailingSpaces, - context, + signatureContext, date = serverTime(), format = 'armored', ...options @@ -29,7 +29,9 @@ export default async function signMessage({ date, format, message: await createMessage({ [dataType]: data, date }), - signatureNotations: context ? getNotationForContext(context.value, context.critical) : undefined + signatureNotations: signatureContext ? + getNotationForContext(signatureContext.value, signatureContext.critical) : + undefined }; return sign(sanitizedOptions).catch((err) => { diff --git a/lib/message/verify.d.ts b/lib/message/verify.d.ts index d3cb9015..863e6fc2 100644 --- a/lib/message/verify.d.ts +++ b/lib/message/verify.d.ts @@ -14,7 +14,7 @@ export interface VerifyOptionsPmcrypto extends Omit { @@ -35,7 +35,7 @@ export function verifyMessage; export function handleVerificationResult( verificationResult: openpgp_VerifyMessageResult, - context?: ContextVerificationOptions, + signatureContext?: ContextVerificationOptions, expectSigned?: boolean ): Promise>; diff --git a/lib/message/verify.js b/lib/message/verify.js index 1f120dfd..978ccdcc 100644 --- a/lib/message/verify.js +++ b/lib/message/verify.js @@ -2,7 +2,7 @@ import { createMessage, verify, CleartextMessage } from '../openpgp'; import { DEFAULT_SIGNATURE_VERIFICATION_OFFSET, VERIFICATION_STATUS } from '../constants'; import { serverTime } from '../serverTime'; import { removeTrailingSpaces } from './utils'; -import { ContextError, getConfigForContextVerification, isValidSignatureContext } from './context'; +import { SignatureContextError, getConfigForContextVerification, isValidSignatureContext } from './context'; const { NOT_SIGNED, SIGNED_AND_VALID, SIGNED_AND_INVALID } = VERIFICATION_STATUS; @@ -17,7 +17,7 @@ const { NOT_SIGNED, SIGNED_AND_VALID, SIGNED_AND_INVALID } = VERIFICATION_STATUS * verified: Promise, * signature: Promise * } - * @param {Object} context - context verification options + * @param {Object} contesignatureContextxt - signature context verification options * @param {Boolean} expectSigned - whether a valid signature is expected; it causes the function to throw otherwise * @returns {{ * data: Uint8Array|string|ReadableStream|NodeStream - message data, @@ -27,7 +27,7 @@ const { NOT_SIGNED, SIGNED_AND_VALID, SIGNED_AND_INVALID } = VERIFICATION_STATUS * errors: Error[]|undefined - verification errors if all signatures are invalid * }} */ -export async function handleVerificationResult(verificationResult, context, expectSigned) { +export async function handleVerificationResult(verificationResult, signatureContext, expectSigned) { const { data, signatures: sigsInfo } = verificationResult; const signatures = []; const errors = []; @@ -50,10 +50,10 @@ export async function handleVerificationResult(verificationResult, context, expe // signature. const verifiedSigPacket = signature.packets[0]; - if (!context || isValidSignatureContext(context, verifiedSigPacket)) { + if (!signatureContext || isValidSignatureContext(signatureContext, verifiedSigPacket)) { verificationStatus = SIGNED_AND_VALID; } else { - errors.push(new ContextError('context verification error')); + errors.push(new SignatureContextError('context verification error')); } if (!signatureTimestamp) { @@ -97,7 +97,7 @@ export async function verifyMessage({ textData, binaryData, stripTrailingSpaces, - context, + signatureContext, config = {}, date = new Date(+serverTime() + DEFAULT_SIGNATURE_VERIFICATION_OFFSET), ...options @@ -108,11 +108,11 @@ export async function verifyMessage({ ...options, date, message: await createMessage({ [dataType]: dataToVerify, date }), - config: context ? getConfigForContextVerification(config) : config + config: signatureContext ? getConfigForContextVerification(config) : config }; const verificationResult = await verify(sanitizedOptions); - return handleVerificationResult(verificationResult, context, options.expectSigned); + return handleVerificationResult(verificationResult, signatureContext, options.expectSigned); } /** diff --git a/lib/pmcrypto.d.ts b/lib/pmcrypto.d.ts index a0ba714e..7f5d2b49 100644 --- a/lib/pmcrypto.d.ts +++ b/lib/pmcrypto.d.ts @@ -27,7 +27,7 @@ import type { ContextSigningOptions, ContextVerificationOptions } from './messag export function init(): void; export { VERIFICATION_STATUS, SIGNATURE_TYPES, type PartialConfig }; -export { ContextError } from './message/context'; +export { SignatureContextError } from './message/context'; export type OpenPGPKey = Key; export type OpenPGPMessage = Message; // TODO missing streaming support @@ -70,7 +70,7 @@ export function decryptSessionKey(options: DecryptSessionKeyOptionsPmcrypto): Pr export interface DecryptOptionsPmcrypto> extends DecryptOptions { message: Message; encryptedSignature?: Message>; - context?: ContextVerificationOptions + signatureContext?: ContextVerificationOptions } export interface DecryptResultPmcrypto> { @@ -104,7 +104,7 @@ export interface EncryptOptionsPmcrypto> extends binaryData?: T extends MaybeWebStream ? T : never; stripTrailingSpaces?: T extends MaybeWebStream ? boolean : never; detached?: boolean; - context?: ContextSigningOptions; + signatureContext?: ContextSigningOptions; } // No reuse from OpenPGP's equivalent @@ -153,7 +153,7 @@ export interface SignOptionsPmcrypto> extends Omi textData?: T extends MaybeWebStream ? T : never; binaryData?: T extends MaybeWebStream ? T : never; stripTrailingSpaces?: T extends MaybeWebStream ? boolean : never; - context?: ContextSigningOptions; + signatureContext?: ContextSigningOptions; } export function signMessage< diff --git a/lib/pmcrypto.js b/lib/pmcrypto.js index de7b72e6..27b444ef 100644 --- a/lib/pmcrypto.js +++ b/lib/pmcrypto.js @@ -62,4 +62,4 @@ export { checkKeyStrength, checkKeyCompatibility } from './key/check'; export * from './constants'; -export { ContextError } from './message/context'; +export { SignatureContextError } from './message/context'; diff --git a/test/message/context.spec.ts b/test/message/context.spec.ts index d093073a..82bc559d 100644 --- a/test/message/context.spec.ts +++ b/test/message/context.spec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { verifyMessage, signMessage, generateKey, readSignature, readMessage, decryptMessage, encryptMessage, readKey, ContextError, serverTime } from '../../lib'; +import { verifyMessage, signMessage, generateKey, readSignature, readMessage, decryptMessage, encryptMessage, readKey, SignatureContextError, serverTime } from '../../lib'; import { VERIFICATION_STATUS } from '../../lib/constants'; // verification without passing context should fail @@ -16,7 +16,7 @@ describe('context', () => { const armoredSignature = await signMessage({ textData, signingKeys: [privateKey], - context: { value: 'test-context', critical: true }, + signatureContext: { value: 'test-context', critical: true }, detached: true }); @@ -24,14 +24,14 @@ describe('context', () => { textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'test-context', required: true } + signatureContext: { value: 'test-context', required: true } }); const verificationWrongContext = await verifyMessage({ textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'unexpected-context', required: true } + signatureContext: { value: 'unexpected-context', required: true } }); // verificationWrongContext with `expectSigned` @@ -39,9 +39,9 @@ describe('context', () => { textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'unexpected-context', required: true }, + signatureContext: { value: 'unexpected-context', required: true }, expectSigned: true - })).to.be.rejectedWith(ContextError); + })).to.be.rejectedWith(SignatureContextError); const verificationMissingContext = await verifyMessage({ textData, @@ -55,7 +55,7 @@ describe('context', () => { // check errors expect(verificationValidContext.errors).to.be.undefined; expect(verificationWrongContext.errors).to.have.length(1); - expect(verificationWrongContext.errors![0]).to.be.instanceOf(ContextError); + expect(verificationWrongContext.errors![0]).to.be.instanceOf(SignatureContextError); expect(verificationMissingContext.errors).to.have.length(1); expect(verificationMissingContext.errors![0]).to.match(/Unknown critical notation: context@proton/); }); @@ -70,7 +70,7 @@ describe('context', () => { const armoredSignature = await signMessage({ textData, signingKeys: [privateKey], - context: { value: 'test-context', critical: false }, + signatureContext: { value: 'test-context', critical: false }, detached: true }); @@ -78,21 +78,21 @@ describe('context', () => { textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'test-context', required: true } + signatureContext: { value: 'test-context', required: true } }); const verificationWrongContext = await verifyMessage({ textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'unexpected-context', required: true } + signatureContext: { value: 'unexpected-context', required: true } }); const verificationWrongContextNotRequired = await verifyMessage({ textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'unexpected-context', required: false } // should still fail to verify + signatureContext: { value: 'unexpected-context', required: false } // should still fail to verify }); const verificationMissingContext = await verifyMessage({ @@ -108,9 +108,9 @@ describe('context', () => { // check errors expect(verificationValidContext.errors).to.be.undefined; expect(verificationWrongContext.errors).to.have.length(1); - expect(verificationWrongContext.errors![0]).to.be.instanceOf(ContextError); + expect(verificationWrongContext.errors![0]).to.be.instanceOf(SignatureContextError); expect(verificationWrongContextNotRequired.errors).to.have.length(1); - expect(verificationWrongContextNotRequired.errors![0]).to.be.instanceOf(ContextError); + expect(verificationWrongContextNotRequired.errors![0]).to.be.instanceOf(SignatureContextError); expect(verificationMissingContext.errors).to.be.undefined; }); @@ -124,21 +124,21 @@ describe('context', () => { textData: 'message with context', encryptionKeys: publicKey, signingKeys: privateKey, - context: { value: 'test-context', critical: true } + signatureContext: { value: 'test-context', critical: true } }); const decryptionValidContext = await decryptMessage({ message: await readMessage({ armoredMessage }), decryptionKeys: privateKey, verificationKeys: publicKey, - context: { value: 'test-context', required: true } + signatureContext: { value: 'test-context', required: true } }); const decryptionWrongContext = await decryptMessage({ message: await readMessage({ armoredMessage }), decryptionKeys: privateKey, verificationKeys: publicKey, - context: { value: 'unexpected-context', required: true } + signatureContext: { value: 'unexpected-context', required: true } }); const decryptionMissingContext = await await decryptMessage({ @@ -153,7 +153,7 @@ describe('context', () => { // check errors expect(decryptionValidContext.verificationErrors).to.be.undefined; expect(decryptionWrongContext.verificationErrors).to.have.length(1); - expect(decryptionWrongContext.verificationErrors![0]).to.be.instanceOf(ContextError); + expect(decryptionWrongContext.verificationErrors![0]).to.be.instanceOf(SignatureContextError); expect(decryptionMissingContext.verificationErrors).to.have.length(1); expect(decryptionMissingContext.verificationErrors![0]).to.match(/Unknown critical notation: context@proton/); }); @@ -168,7 +168,7 @@ describe('context', () => { textData: 'message with context', encryptionKeys: publicKey, signingKeys: privateKey, - context: { value: 'test-context', critical: true }, + signatureContext: { value: 'test-context', critical: true }, detached: true }); @@ -177,7 +177,7 @@ describe('context', () => { encryptedSignature: await readMessage({ armoredMessage: encryptedSignature }), decryptionKeys: privateKey, verificationKeys: publicKey, - context: { value: 'test-context', required: true } + signatureContext: { value: 'test-context', required: true } }); const decryptionWrongContext = await decryptMessage({ @@ -185,7 +185,7 @@ describe('context', () => { encryptedSignature: await readMessage({ armoredMessage: encryptedSignature }), decryptionKeys: privateKey, verificationKeys: publicKey, - context: { value: 'unexpected-context', required: true } + signatureContext: { value: 'unexpected-context', required: true } }); const decryptionMissingContext = await await decryptMessage({ @@ -201,18 +201,18 @@ describe('context', () => { // check errors expect(decryptionValidContext.verificationErrors).to.be.undefined; expect(decryptionWrongContext.verificationErrors).to.have.length(1); - expect(decryptionWrongContext.verificationErrors![0]).to.be.instanceOf(ContextError); + expect(decryptionWrongContext.verificationErrors![0]).to.be.instanceOf(SignatureContextError); expect(decryptionMissingContext.verificationErrors).to.have.length(1); expect(decryptionMissingContext.verificationErrors![0]).to.match(/Unknown critical notation: context@proton/); }); - it.only('encryptMessage/decryptMessage - it throws if context is provided without signingKeys or verificationKeys', async () => { + it('encryptMessage/decryptMessage - it throws if `signatureContext` is provided without `signingKeys` or `verificationKeys`', async () => { // missing signing keys await expect(encryptMessage({ textData: 'message with context', sessionKey: { algorithm: 'aes128', data: new Uint8Array(16) }, // unused - context: { value: 'test-context', critical: true } - })).to.be.rejectedWith(/Unexpected `context` input without any `signingKeys` provided/); + signatureContext: { value: 'test-context', critical: true } + })).to.be.rejectedWith(/Unexpected `signatureContext` input without any `signingKeys` provided/); // missing verification keys await expect(decryptMessage({ @@ -225,8 +225,8 @@ sJFJxllC0j4wHCOS9uiSYsZ/pWCqxX/3sFh4VBFOpr0HAA== =S5ns -----END PGP MESSAGE-----` }), sessionKeys: { algorithm: 'aes128', data: new Uint8Array(16) }, // unused - context: { value: 'test-context', required: true } - })).to.be.rejectedWith(/Unexpected `context` input without any `verificationKeys` provided/); + signatureContext: { value: 'test-context', required: true } + })).to.be.rejectedWith(/Unexpected `signatureContext` input without any `verificationKeys` provided/); }); it('does not verify a message without context', async () => { @@ -246,14 +246,14 @@ sJFJxllC0j4wHCOS9uiSYsZ/pWCqxX/3sFh4VBFOpr0HAA== textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'test-context', required: true } + signatureContext: { value: 'test-context', required: true } }); const verificationNoExpectedContext = await verifyMessage({ textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'test-context', required: false } + signatureContext: { value: 'test-context', required: false } }); expect(verificationExpectedContext.verified).to.equal(VERIFICATION_STATUS.SIGNED_AND_INVALID); @@ -261,7 +261,7 @@ sJFJxllC0j4wHCOS9uiSYsZ/pWCqxX/3sFh4VBFOpr0HAA== expect(verificationNoExpectedContext.errors).to.be.undefined; expect(verificationExpectedContext.errors).to.have.length(1); - expect(verificationExpectedContext.errors![0]).to.be.instanceOf(ContextError); + expect(verificationExpectedContext.errors![0]).to.be.instanceOf(SignatureContextError); }); it('does not verify a message without context based on cutoff date (`expectFrom`)', async () => { @@ -285,14 +285,14 @@ sJFJxllC0j4wHCOS9uiSYsZ/pWCqxX/3sFh4VBFOpr0HAA== textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'test-context', requiredAfter: now } + signatureContext: { value: 'test-context', requiredAfter: now } }); const verificationNoExpectedContext = await verifyMessage({ textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'test-context', requiredAfter: nextHour } + signatureContext: { value: 'test-context', requiredAfter: nextHour } }); expect(verificationExpectedContext.verified).to.equal(VERIFICATION_STATUS.SIGNED_AND_INVALID); @@ -300,7 +300,7 @@ sJFJxllC0j4wHCOS9uiSYsZ/pWCqxX/3sFh4VBFOpr0HAA== expect(verificationNoExpectedContext.errors).to.be.undefined; expect(verificationExpectedContext.errors).to.have.length(1); - expect(verificationExpectedContext.errors![0]).to.be.instanceOf(ContextError); + expect(verificationExpectedContext.errors![0]).to.be.instanceOf(SignatureContextError); }); it('does not verify signature with unsigned notation data', async () => { @@ -333,7 +333,7 @@ sj39B18qvvnS11F+AAB7igEAqwmlDXMzeNNLc3skdyQWZoP0fPyI/ol7pMa+ textData, signature: await readSignature({ armoredSignature }), verificationKeys: [publicKey], - context: { value: 'test-context-unsigned', required: true } + signatureContext: { value: 'test-context-unsigned', required: true } }); // no context expected, so unsigned notation data should be simply ignored