aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/crypto/workers/cryptoApi.ts4
-rw-r--r--src/crypto/workers/cryptoImplementation.ts26
-rw-r--r--src/wallet-impl/exchanges.ts39
3 files changed, 59 insertions, 10 deletions
diff --git a/src/crypto/workers/cryptoApi.ts b/src/crypto/workers/cryptoApi.ts
index 5537bb39f..aa1ff2c42 100644
--- a/src/crypto/workers/cryptoApi.ts
+++ b/src/crypto/workers/cryptoApi.ts
@@ -409,6 +409,10 @@ export class CryptoApi {
return this.doRpc<boolean>("rsaVerify", 4, hm, sig, pk);
}
+ isValidWireAccount(paytoUri: string, sig: string, masterPub: string): Promise<boolean> {
+ return this.doRpc<boolean>("isValidWireAccount", 4, paytoUri, sig, masterPub);
+ }
+
createPaybackRequest(coin: CoinRecord): Promise<PaybackRequest> {
return this.doRpc<PaybackRequest>("createPaybackRequest", 1, coin);
}
diff --git a/src/crypto/workers/cryptoImplementation.ts b/src/crypto/workers/cryptoImplementation.ts
index 00d81ce27..fa5a30d68 100644
--- a/src/crypto/workers/cryptoImplementation.ts
+++ b/src/crypto/workers/cryptoImplementation.ts
@@ -68,15 +68,17 @@ import {
rsaVerify,
} from "../talerCrypto";
import { randomBytes } from "../primitives/nacl-fast";
+import { kdf } from "../primitives/kdf";
enum SignaturePurpose {
RESERVE_WITHDRAW = 1200,
WALLET_COIN_DEPOSIT = 1201,
MASTER_DENOMINATION_KEY_VALIDITY = 1025,
+ MASTER_WIRE_FEES = 1028,
+ MASTER_WIRE_DETAILS = 1030,
WALLET_COIN_MELT = 1202,
TEST = 4242,
MERCHANT_PAYMENT_OK = 1104,
- MASTER_WIRE_FEES = 1028,
WALLET_COIN_PAYBACK = 1203,
WALLET_COIN_LINK = 1204,
}
@@ -157,9 +159,7 @@ export class CryptoImplementation {
* Create a pre-coin of the given denomination to be withdrawn from then given
* reserve.
*/
- createPlanchet(
- req: PlanchetCreationRequest,
- ): PlanchetCreationResult {
+ createPlanchet(req: PlanchetCreationRequest): PlanchetCreationResult {
const reservePub = decodeCrock(req.reservePub);
const reservePriv = decodeCrock(req.reservePriv);
const denomPub = decodeCrock(req.denomPub);
@@ -264,6 +264,7 @@ export class CryptoImplementation {
.put(timestampToBuffer(wf.startStamp))
.put(timestampToBuffer(wf.endStamp))
.put(amountToBuffer(wf.wireFee))
+ .put(amountToBuffer(wf.closingFee))
.build();
const sig = decodeCrock(wf.sig);
const pub = decodeCrock(masterPub);
@@ -292,6 +293,23 @@ export class CryptoImplementation {
return eddsaVerify(p, sig, pub);
}
+ isValidWireAccount(
+ paytoUri: string,
+ sig: string,
+ masterPub: string,
+ ): boolean {
+ const h = kdf(
+ 64,
+ stringToBytes("exchange-wire-signature"),
+ stringToBytes(paytoUri + "\0"),
+ new Uint8Array(0),
+ );
+ const p = buildSigPS(SignaturePurpose.MASTER_WIRE_DETAILS)
+ .put(h)
+ .build();
+ return eddsaVerify(p, decodeCrock(sig), decodeCrock(masterPub));
+ }
+
/**
* Create a new EdDSA key pair.
*/
diff --git a/src/wallet-impl/exchanges.ts b/src/wallet-impl/exchanges.ts
index b89f3f84e..b6a2f1c8a 100644
--- a/src/wallet-impl/exchanges.ts
+++ b/src/wallet-impl/exchanges.ts
@@ -15,10 +15,13 @@
*/
import { InternalWalletState } from "./state";
+import { WALLET_CACHE_BREAKER_CLIENT_VERSION } from "../wallet";
import {
- WALLET_CACHE_BREAKER_CLIENT_VERSION,
-} from "../wallet";
-import { KeysJson, Denomination, ExchangeWireJson } from "../talerTypes";
+ KeysJson,
+ Denomination,
+ ExchangeWireJson,
+ WireFeesJson,
+} from "../talerTypes";
import { getTimestampNow, OperationError } from "../walletTypes";
import {
ExchangeRecord,
@@ -229,8 +232,12 @@ async function updateExchangeWithWireInfo(
if (exchange.updateStatus != ExchangeUpdateStatus.FETCH_WIRE) {
return;
}
+ const details = exchange.details;
+ if (!details) {
+ throw Error("invalid exchange state");
+ }
const reqUrl = new URL("wire", exchangeBaseUrl);
- reqUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION)
+ reqUrl.searchParams.set("cacheBreaker", WALLET_CACHE_BREAKER_CLIENT_VERSION);
const resp = await ws.http.get(reqUrl.href);
@@ -239,6 +246,17 @@ async function updateExchangeWithWireInfo(
throw Error("/wire response malformed");
}
const wireInfo = ExchangeWireJson.checked(wiJson);
+ for (const a of wireInfo.accounts) {
+ console.log("validating exchange acct");
+ const isValid = await ws.cryptoApi.isValidWireAccount(
+ a.url,
+ a.master_sig,
+ details.masterPublicKey,
+ );
+ if (!isValid) {
+ throw Error("exchange acct signature invalid");
+ }
+ }
const feesForType: { [wireMethod: string]: WireFee[] } = {};
for (const wireMethod of Object.keys(wireInfo.fees)) {
const feeList: WireFee[] = [];
@@ -251,13 +269,22 @@ async function updateExchangeWithWireInfo(
if (!endStamp) {
throw Error("wrong date format");
}
- feeList.push({
+ const fee: WireFee = {
closingFee: Amounts.parseOrThrow(x.closing_fee),
endStamp,
sig: x.sig,
startStamp,
wireFee: Amounts.parseOrThrow(x.wire_fee),
- });
+ };
+ const isValid = await ws.cryptoApi.isValidWireFee(
+ wireMethod,
+ fee,
+ details.masterPublicKey,
+ );
+ if (!isValid) {
+ throw Error("exchange wire fee signature invalid");
+ }
+ feeList.push(fee);
}
feesForType[wireMethod] = feeList;
}