commit 57bae624d26245042ea12b5acadc3638319c5c7f
parent 77552c979f06ad5a169aa7f74c6a34d269c21222
Author: Florian Dold <florian@dold.me>
Date: Sun, 23 Feb 2025 11:34:25 +0100
fix signing of never timestamps, implement support for attributes in AML decision signature
Diffstat:
3 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/packages/taler-util/src/taler-crypto.ts b/packages/taler-util/src/taler-crypto.ts
@@ -1624,18 +1624,23 @@ export function amountToBuffer(amount: AmountLike): Uint8Array {
return u8buf;
}
+const foreverNum = 2n ** 64n - 1n;
+
export function timestampRoundedToBuffer(
ts: TalerProtocolTimestamp,
): Uint8Array {
const b = new ArrayBuffer(8);
const v = new DataView(b);
+ const numVal =
+ ts.t_s === "never" ? foreverNum : BigInt(ts.t_s) * 1000n * 1000n;
// The buffer we sign over represents the timestamp in microseconds.
if (typeof v.setBigUint64 !== "undefined") {
- const s = BigInt(ts.t_s) * BigInt(1000 * 1000);
- v.setBigUint64(0, s);
+ v.setBigUint64(0, numVal);
} else {
const s =
- ts.t_s === "never" ? bigint.zero : bigint(ts.t_s).multiply(1000 * 1000);
+ ts.t_s === "never"
+ ? bigint(foreverNum)
+ : bigint(ts.t_s).multiply(1000 * 1000);
const arr = s.toArray(2 ** 8).value;
let offset = 8 - arr.length;
for (let i = 0; i < arr.length; i++) {
diff --git a/packages/taler-util/src/taler-signatures.ts b/packages/taler-util/src/taler-signatures.ts
@@ -14,7 +14,7 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { canonicalJson } from "./index.js";
+import { canonicalJson, TalerProtocolTimestamp } from "./index.js";
import {
bufferForUint64,
buildSigPS,
@@ -46,6 +46,11 @@ export function signAmlDecision(
const flags: number = decision.keep_investigating ? 1 : 0;
builder.put(timestampRoundedToBuffer(decision.decision_time));
+ builder.put(
+ timestampRoundedToBuffer(
+ decision.attributes_expiration ?? TalerProtocolTimestamp.fromSeconds(0),
+ ),
+ );
builder.put(decodeCrock(decision.h_payto));
builder.put(hash(stringToBytes(decision.justification)));
builder.put(hash(stringToBytes(canonicalJson(decision.properties) + "\0")));
@@ -55,6 +60,11 @@ export function signAmlDecision(
} else {
builder.put(new Uint8Array(64));
}
+ if (decision.attributes != null) {
+ builder.put(hash(stringToBytes(canonicalJson(decision.attributes) + "\0")));
+ } else {
+ builder.put(new Uint8Array(64));
+ }
builder.put(bufferForUint64(flags));
const sigBlob = builder.build();
diff --git a/packages/taler-util/src/types-taler-exchange.ts b/packages/taler-util/src/types-taler-exchange.ts
@@ -1985,12 +1985,26 @@ export interface AmlDecisionRequest {
// New since protocol **v20**.
keep_investigating: boolean;
- // Signature by the AML officer over a TALER_AmlDecisionPS.
- // Must have purpose TALER_SIGNATURE_MASTER_AML_KEY.
+ /**
+ * Signature by the AML officer over a TALER_AmlDecisionPS.
+ * Must have purpose TALER_SIGNATURE_MASTER_AML_KEY.
+ */
officer_sig: EddsaSignatureString;
- // When was the decision made?
+ /**
+ * When was the decision made?
+ */
decision_time: Timestamp;
+
+ /**
+ * When do the attributes expire?
+ */
+ attributes_expiration?: Timestamp;
+
+ /**
+ * Attributes set by the AML officer.
+ */
+ attributes?: Object;
}
export interface KycRule {
@@ -2054,7 +2068,7 @@ export interface KycAttributeCollectionEvent {
// The collected KYC data. NULL if the attribute data could not
// be decrypted (internal error of the exchange, likely the
// attribute key was changed).
- attributes?: Object;
+ attributes?: { [x: string]: unknown };
// Time when the KYC data was collected
collection_time: Timestamp;