always round timestamps before signature creation/verification

This commit is contained in:
Florian Dold 2020-04-07 14:12:29 +05:30
parent faba5e9db8
commit 34eca9c512
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
2 changed files with 27 additions and 11 deletions

View File

@ -64,7 +64,7 @@ import {
} from "../talerCrypto"; } from "../talerCrypto";
import { randomBytes } from "../primitives/nacl-fast"; import { randomBytes } from "../primitives/nacl-fast";
import { kdf } from "../primitives/kdf"; import { kdf } from "../primitives/kdf";
import { Timestamp, getTimestampNow } from "../../util/time"; import { Timestamp, getTimestampNow, timestampTruncateToSecond } from "../../util/time";
enum SignaturePurpose { enum SignaturePurpose {
RESERVE_WITHDRAW = 1200, RESERVE_WITHDRAW = 1200,
@ -94,13 +94,15 @@ function amountToBuffer(amount: AmountJson): Uint8Array {
return u8buf; return u8buf;
} }
function timestampToBuffer(ts: Timestamp): Uint8Array { function timestampRoundedToBuffer(ts: Timestamp): Uint8Array {
const b = new ArrayBuffer(8); const b = new ArrayBuffer(8);
const v = new DataView(b); const v = new DataView(b);
const s = BigInt(ts.t_ms) * BigInt(1000); const tsRounded = timestampTruncateToSecond(ts);
const s = BigInt(tsRounded.t_ms) * BigInt(1000);
v.setBigUint64(0, s); v.setBigUint64(0, s);
return new Uint8Array(b); return new Uint8Array(b);
} }
class SignaturePurposeBuilder { class SignaturePurposeBuilder {
private chunks: Uint8Array[] = []; private chunks: Uint8Array[] = [];
@ -245,8 +247,8 @@ export class CryptoImplementation {
isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean { isValidWireFee(type: string, wf: WireFee, masterPub: string): boolean {
const p = buildSigPS(SignaturePurpose.MASTER_WIRE_FEES) const p = buildSigPS(SignaturePurpose.MASTER_WIRE_FEES)
.put(hash(stringToBytes(type + "\0"))) .put(hash(stringToBytes(type + "\0")))
.put(timestampToBuffer(wf.startStamp)) .put(timestampRoundedToBuffer(wf.startStamp))
.put(timestampToBuffer(wf.endStamp)) .put(timestampRoundedToBuffer(wf.endStamp))
.put(amountToBuffer(wf.wireFee)) .put(amountToBuffer(wf.wireFee))
.put(amountToBuffer(wf.closingFee)) .put(amountToBuffer(wf.closingFee))
.build(); .build();
@ -261,10 +263,10 @@ export class CryptoImplementation {
isValidDenom(denom: DenominationRecord, masterPub: string): boolean { isValidDenom(denom: DenominationRecord, masterPub: string): boolean {
const p = buildSigPS(SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY) const p = buildSigPS(SignaturePurpose.MASTER_DENOMINATION_KEY_VALIDITY)
.put(decodeCrock(masterPub)) .put(decodeCrock(masterPub))
.put(timestampToBuffer(denom.stampStart)) .put(timestampRoundedToBuffer(denom.stampStart))
.put(timestampToBuffer(denom.stampExpireWithdraw)) .put(timestampRoundedToBuffer(denom.stampExpireWithdraw))
.put(timestampToBuffer(denom.stampExpireDeposit)) .put(timestampRoundedToBuffer(denom.stampExpireDeposit))
.put(timestampToBuffer(denom.stampExpireLegal)) .put(timestampRoundedToBuffer(denom.stampExpireLegal))
.put(amountToBuffer(denom.value)) .put(amountToBuffer(denom.value))
.put(amountToBuffer(denom.feeWithdraw)) .put(amountToBuffer(denom.feeWithdraw))
.put(amountToBuffer(denom.feeDeposit)) .put(amountToBuffer(denom.feeDeposit))
@ -330,8 +332,8 @@ export class CryptoImplementation {
const d = buildSigPS(SignaturePurpose.WALLET_COIN_DEPOSIT) const d = buildSigPS(SignaturePurpose.WALLET_COIN_DEPOSIT)
.put(decodeCrock(depositInfo.contractTermsHash)) .put(decodeCrock(depositInfo.contractTermsHash))
.put(decodeCrock(depositInfo.wireInfoHash)) .put(decodeCrock(depositInfo.wireInfoHash))
.put(timestampToBuffer(depositInfo.timestamp)) .put(timestampRoundedToBuffer(depositInfo.timestamp))
.put(timestampToBuffer(depositInfo.refundDeadline)) .put(timestampRoundedToBuffer(depositInfo.refundDeadline))
.put(amountToBuffer(depositInfo.spendAmount)) .put(amountToBuffer(depositInfo.spendAmount))
.put(amountToBuffer(depositInfo.feeDeposit)) .put(amountToBuffer(depositInfo.feeDeposit))
.put(decodeCrock(depositInfo.merchantPub)) .put(decodeCrock(depositInfo.merchantPub))

View File

@ -49,6 +49,7 @@ export function getTimestampNow(): Timestamp {
export function getDurationRemaining( export function getDurationRemaining(
deadline: Timestamp, deadline: Timestamp,
now = getTimestampNow(), now = getTimestampNow(),
): Duration { ): Duration {
if (deadline.t_ms === "never") { if (deadline.t_ms === "never") {
return { d_ms: "forever" }; return { d_ms: "forever" };
@ -72,6 +73,19 @@ export function timestampMin(t1: Timestamp, t2: Timestamp): Timestamp {
return { t_ms: Math.min(t1.t_ms, t2.t_ms) }; return { t_ms: Math.min(t1.t_ms, t2.t_ms) };
} }
/**
* Truncate a timestamp so that that it represents a multiple
* of seconds. The timestamp is always rounded down.
*/
export function timestampTruncateToSecond(t1: Timestamp): Timestamp {
if (t1.t_ms === "never") {
return { t_ms: "never" };
}
return {
t_ms: Math.floor(t1.t_ms / 1000) * 1000,
};
}
export function durationMin(d1: Duration, d2: Duration): Duration { export function durationMin(d1: Duration, d2: Duration): Duration {
if (d1.d_ms === "forever") { if (d1.d_ms === "forever") {
return { d_ms: d2.d_ms }; return { d_ms: d2.d_ms };