From ec43b6a5bf4f8064aaad7fc303a10c7f585a110e Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Thu, 1 Sep 2022 22:26:22 +0200 Subject: [PATCH] wallet-core: fix issue with crock encoding of age restrictions --- packages/taler-util/src/talerCrypto.ts | 46 +++++++++++++------ packages/taler-util/src/talerTypes.ts | 38 +++++++-------- .../src/crypto/cryptoImplementation.ts | 6 +-- .../src/operations/withdraw.ts | 10 ++-- .../src/util/coinSelection.ts | 13 ++++-- 5 files changed, 68 insertions(+), 45 deletions(-) diff --git a/packages/taler-util/src/talerCrypto.ts b/packages/taler-util/src/talerCrypto.ts index d7734707a..8d2e41793 100644 --- a/packages/taler-util/src/talerCrypto.ts +++ b/packages/taler-util/src/talerCrypto.ts @@ -857,6 +857,13 @@ export type Edx25519PublicKey = FlavorP; export type Edx25519PrivateKey = FlavorP; export type Edx25519Signature = FlavorP; +export type Edx25519PublicKeyEnc = FlavorP; +export type Edx25519PrivateKeyEnc = FlavorP< + string, + "Edx25519PrivateKeyEnc", + 64 +>; + /** * Convert a big integer to a fixed-size, little-endian array. */ @@ -958,7 +965,7 @@ export interface AgeCommitment { /** * Public keys, one for each age group specified in the age mask. */ - publicKeys: Edx25519PublicKey[]; + publicKeys: Edx25519PublicKeyEnc[]; } export interface AgeProof { @@ -966,7 +973,7 @@ export interface AgeProof { * Private keys. Typically smaller than the number of public keys, * because we drop private keys from age groups that are restricted. */ - privateKeys: Edx25519PrivateKey[]; + privateKeys: Edx25519PrivateKeyEnc[]; } export interface AgeCommitmentProof { @@ -984,7 +991,7 @@ export namespace AgeRestriction { export function hashCommitment(ac: AgeCommitment): HashCodeString { const hc = new nacl.HashState(); for (const pub of ac.publicKeys) { - hc.update(pub); + hc.update(decodeCrock(pub)); } return encodeCrock(hc.finish().subarray(0, 32)); } @@ -1042,10 +1049,10 @@ export namespace AgeRestriction { return { commitment: { mask: ageMask, - publicKeys: pubs, + publicKeys: pubs.map((x) => encodeCrock(x)), }, proof: { - privateKeys: privs, + privateKeys: privs.map((x) => encodeCrock(x)), }, }; } @@ -1062,8 +1069,11 @@ export namespace AgeRestriction { return false; } for (let i = 0; i < c1.publicKeys.length; i++) { - const k1 = c1.publicKeys[i]; - const k2 = await Edx25519.publicKeyDerive(c2.publicKeys[i], salt); + const k1 = decodeCrock(c1.publicKeys[i]); + const k2 = await Edx25519.publicKeyDerive( + decodeCrock(c2.publicKeys[i]), + salt, + ); if (k1 != k2) { return false; } @@ -1079,20 +1089,22 @@ export namespace AgeRestriction { const newPubs: Edx25519PublicKey[] = []; for (const oldPub of commitmentProof.commitment.publicKeys) { - newPubs.push(await Edx25519.publicKeyDerive(oldPub, salt)); + newPubs.push(await Edx25519.publicKeyDerive(decodeCrock(oldPub), salt)); } for (const oldPriv of commitmentProof.proof.privateKeys) { - newPrivs.push(await Edx25519.privateKeyDerive(oldPriv, salt)); + newPrivs.push( + await Edx25519.privateKeyDerive(decodeCrock(oldPriv), salt), + ); } return { commitment: { mask: commitmentProof.commitment.mask, - publicKeys: newPubs, + publicKeys: newPubs.map((x) => encodeCrock(x)), }, proof: { - privateKeys: newPrivs, + privateKeys: newPrivs.map((x) => encodeCrock(x)), }, }; } @@ -1112,7 +1124,11 @@ export namespace AgeRestriction { } const priv = commitmentProof.proof.privateKeys[group - 1]; const pub = commitmentProof.commitment.publicKeys[group - 1]; - const sig = nacl.crypto_edx25519_sign_detached(d, priv, pub); + const sig = nacl.crypto_edx25519_sign_detached( + d, + decodeCrock(priv), + decodeCrock(pub), + ); return sig; } @@ -1131,7 +1147,11 @@ export namespace AgeRestriction { return true; } const pub = commitment.publicKeys[group - 1]; - return nacl.crypto_edx25519_sign_detached_verify(d, decodeCrock(sig), pub); + return nacl.crypto_edx25519_sign_detached_verify( + d, + decodeCrock(sig), + decodeCrock(pub), + ); } } diff --git a/packages/taler-util/src/talerTypes.ts b/packages/taler-util/src/talerTypes.ts index e36236085..014631ad7 100644 --- a/packages/taler-util/src/talerTypes.ts +++ b/packages/taler-util/src/talerTypes.ts @@ -25,29 +25,29 @@ * Imports. */ +import { codecForAmountString } from "./amounts.js"; import { buildCodecForObject, - codecForString, - codecForList, - codecOptional, - codecForAny, - codecForNumber, - codecForBoolean, - codecForMap, - Codec, - codecForConstNumber, buildCodecForUnion, + Codec, + codecForAny, + codecForBoolean, + codecForConstNumber, codecForConstString, + codecForList, + codecForMap, + codecForNumber, + codecForString, + codecOptional, } from "./codec.js"; -import { - codecForTimestamp, - codecForDuration, - TalerProtocolTimestamp, - TalerProtocolDuration, -} from "./time.js"; -import { codecForAmountString } from "./amounts.js"; import { strcmp } from "./helpers.js"; -import { AgeCommitmentProof, Edx25519PublicKey } from "./talerCrypto.js"; +import { AgeCommitmentProof, Edx25519PublicKeyEnc } from "./talerCrypto.js"; +import { + codecForDuration, + codecForTimestamp, + TalerProtocolDuration, + TalerProtocolTimestamp, +} from "./time.js"; /** * Denomination as found in the /keys response from the exchange. @@ -287,7 +287,7 @@ export interface CoinDepositPermission { minimum_age_sig?: EddsaSignatureString; - age_commitment?: Edx25519PublicKey[]; + age_commitment?: Edx25519PublicKeyEnc[]; } /** @@ -1755,7 +1755,7 @@ export interface ExchangeRefreshRevealRequest { * the client MUST provide the original age commitment, i.e. the vector * of public keys. */ - old_age_commitment?: Edx25519PublicKey[]; + old_age_commitment?: Edx25519PublicKeyEnc[]; } export interface DepositSuccess { diff --git a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts index 2f39f7806..f0a5cba2b 100644 --- a/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts +++ b/packages/taler-wallet-core/src/crypto/cryptoImplementation.ts @@ -1084,7 +1084,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { s.age_commitment = depositInfo.ageCommitmentProof?.commitment.publicKeys; } else if (depositInfo.ageCommitmentProof) { - (s as any).h_age_commitment = hAgeCommitment; + (s as any).h_age_commitment = encodeCrock(hAgeCommitment); } return s; @@ -1518,9 +1518,7 @@ export const nativeCryptoR: TalerCryptoInterfaceR = { }); logger.info(`payto URI: ${req.reservePayto}`); - logger.info( - `signing WALLET_PURSE_MERGE over ${encodeCrock(mergeSigBlob)}`, - ); + logger.info(`signing WALLET_PURSE_MERGE over ${encodeCrock(mergeSigBlob)}`); const reserveSigBlob = buildSigPS( TalerSignaturePurpose.WALLET_ACCOUNT_MERGE, diff --git a/packages/taler-wallet-core/src/operations/withdraw.ts b/packages/taler-wallet-core/src/operations/withdraw.ts index 1a73dc01c..9678258f0 100644 --- a/packages/taler-wallet-core/src/operations/withdraw.ts +++ b/packages/taler-wallet-core/src/operations/withdraw.ts @@ -242,7 +242,7 @@ export function selectWithdrawalDenominations( for (const d of denoms) { let count = 0; const cost = Amounts.add(d.value, d.feeWithdraw).amount; - for (; ;) { + for (;;) { if (Amounts.cmp(remaining, cost) < 0) { break; } @@ -903,7 +903,8 @@ export async function updateWithdrawalDenoms( denom.verificationStatus === DenominationVerificationStatus.Unverified ) { logger.trace( - `Validating denomination (${current + 1}/${denominations.length + `Validating denomination (${current + 1}/${ + denominations.length }) signature of ${denom.denomPubHash}`, ); let valid = false; @@ -1030,7 +1031,7 @@ async function queryReserve( if ( resp.status === 404 && result.talerErrorResponse.code === - TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN + TalerErrorCode.EXCHANGE_RESERVES_STATUS_UNKNOWN ) { ws.notify({ type: NotificationType.ReserveNotYetFound, @@ -1336,7 +1337,7 @@ export async function getExchangeWithdrawalInfo( ) { logger.warn( `wallet's support for exchange protocol version ${WALLET_EXCHANGE_PROTOCOL_VERSION} might be outdated ` + - `(exchange has ${exchangeDetails.protocolVersion}), checking for updates`, + `(exchange has ${exchangeDetails.protocolVersion}), checking for updates`, ); } } @@ -1869,6 +1870,7 @@ export async function acceptWithdrawalFromUri( confirmUrl: withdrawInfo.confirmTransferUrl, }, }, + restrictAge: req.restrictAge, forcedDenomSel: req.forcedDenomSel, reserveStatus: ReserveRecordStatus.RegisteringBank, }); diff --git a/packages/taler-wallet-core/src/util/coinSelection.ts b/packages/taler-wallet-core/src/util/coinSelection.ts index b3439067e..97e25abd3 100644 --- a/packages/taler-wallet-core/src/util/coinSelection.ts +++ b/packages/taler-wallet-core/src/util/coinSelection.ts @@ -291,11 +291,14 @@ export function selectPayCoins( aci.denomPub.age_mask, req.requiredMinimumAge, ); - if (!aci.ageCommitmentProof) { - // No age restriction, can't use for this payment - continue; - } - if (aci.ageCommitmentProof.proof.privateKeys.length < index) { + // if (!aci.ageCommitmentProof) { + // // No age restriction, can't use for this payment + // continue; + // } + if ( + aci.ageCommitmentProof && + aci.ageCommitmentProof.proof.privateKeys.length < index + ) { // Available age proofs to low, can't use for this payment continue; }