libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit 7c4f92ff090440b0b595ac8eee05cd5969aec9be
parent e5210b0922265ec026022db60a4e1e8bf3ae46dd
Author: Antoine A <>
Date:   Fri, 30 May 2025 17:28:01 +0200

nexus: accept bank keys matching config hashes

Diffstat:
Mcommon/src/main/kotlin/TalerConfig.kt | 6++++++
Mcontrib/nexus.conf | 7+++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/Config.kt | 7+++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt | 31++++++++++++++++++++++++-------
Mtestbench/src/main/kotlin/Main.kt | 2+-
5 files changed, 45 insertions(+), 8 deletions(-)

diff --git a/common/src/main/kotlin/TalerConfig.kt b/common/src/main/kotlin/TalerConfig.kt @@ -461,6 +461,11 @@ class TalerConfigSection internal constructor( /** Access [option] as Regex */ fun regex(option: String) = option(option, "regex") { Regex(it) } + /** Access [option] as hexadecimal bytes */ + fun hex(option: String) = option(option, "hex") { + it.replace("\\s".toRegex(), "").decodeUpHex() + } + /** Access [option] as BaseURL */ fun baseURL(option: String) = option(option, "baseURL") { BaseURL.parse(it) } @@ -569,6 +574,7 @@ class TalerConfigSection internal constructor( companion object { private val TIME_AMOUNT_PATTERN = Regex("([0-9]+) ?([a-z'\"]+)") private val TEMPORAL_PATTERN = Regex(" *([0-9]+ ?[a-z'\"]+ *)+") + private val WHITESPACE_PATTERN = Regex("\\s") private fun <T> fmtEntriesChoice(mapper: Map<String, T>): String { return buildString { diff --git a/contrib/nexus.conf b/contrib/nexus.conf @@ -46,6 +46,13 @@ BANK_DIALECT = postfinance # Exchange accounts bounce invalid incoming Taler transactions. ACCOUNT_TYPE = exchange +[nexus-setup] +# Bank encryption public key hash +# BANK_ENCRYPTION_PUB_KEY_HASH = + +# Bank authentication public key hash +# BANK_AUTHENTICATION_PUB_KEY_HASH = + [libeufin-nexusdb-postgres] # Where are the SQL files to setup our tables? SQL_DIR = $DATADIR/sql/ diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Config.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Config.kt @@ -60,6 +60,12 @@ class NexusSubmitConfig(config: TalerConfig) { val frequencyRaw = section.string("frequency").require() } +class NexusSetupConfig(config: TalerConfig) { + private val section = config.section("nexus-setup") + val bankAuthPubKey = section.hex("bank_authentication_pub_key_hash").orNull() + val bankEncPubKey = section.hex("bank_encryption_pub_key_hash").orNull() +} + class NexusHostConfig(sect: TalerConfigSection) { /** The bank base URL */ val baseUrl = sect.string("host_base_url").require() @@ -120,6 +126,7 @@ class NexusConfig internal constructor (val cfg: TalerConfig) { val fetch by lazy { NexusFetchConfig(cfg, currency) } val submit by lazy { NexusSubmitConfig(cfg) } val ebics by lazy { NexusEbicsConfig(sect) } + val setup by lazy { NexusSetupConfig(cfg) } val ingest get() = NexusIngestConfig( accountType, diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt @@ -1,6 +1,6 @@ /* * This file is part of LibEuFin. - * Copyright (C) 2023-2024 Taler Systems S.A. + * Copyright (C) 2023-2025 Taler Systems S.A. * LibEuFin is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -55,12 +55,28 @@ private fun loadOrGenerateClientKeys(path: Path): ClientPrivateKeysFile { * @param bankKeys bank public keys, in format stored on disk. * @return true if the user accepted, false otherwise. */ -private fun askUserToAcceptKeys(bankKeys: BankPublicKeysFile): Boolean { - val encHash = CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_encryption_public_key).encodeUpHex() - val authHash = CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_authentication_public_key).encodeUpHex() +private fun askUserToAcceptKeys(bankKeys: BankPublicKeysFile, cfg: NexusSetupConfig): Boolean { + val encHash = CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_encryption_public_key) + val authHash = CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_authentication_public_key) + if (cfg.bankAuthPubKey != null && cfg.bankEncPubKey != null) { + if (encHash.contentEquals(cfg.bankEncPubKey) && authHash.contentEquals(cfg.bankAuthPubKey)) { + logger.info("Accepting bank keys matching config hashes") + return true + } + throw Exception(buildString { + append("Bank keys does not match config hashes\nBank encryption key: ") + append(encHash.encodeUpHex().fmtChunkByTwo()) + append("\nConfig encryption key: ") + append(cfg.bankEncPubKey.encodeUpHex().fmtChunkByTwo()) + append("\nBank authentication key: ") + append(authHash.encodeUpHex().fmtChunkByTwo()) + append("\nConfig authentication key: ") + append(cfg.bankAuthPubKey.encodeUpHex().fmtChunkByTwo()) + }) + } println("The bank has the following keys:") - println("Encryption key: ${encHash.fmtChunkByTwo()}") - println("Authentication key: ${authHash.fmtChunkByTwo()}") + println("Encryption key: ${encHash.encodeUpHex().fmtChunkByTwo()}") + println("Authentication key: ${authHash.encodeUpHex().fmtChunkByTwo()}") print("type 'yes, accept' to accept them: ") val userResponse: String? = readlnOrNull() return userResponse == "yes, accept" @@ -156,6 +172,7 @@ class EbicsSetup: CliktCommand() { */ override fun run() = cliCmd(logger, common.log) { val cfg = nexusConfig(common.config) + val setupCfg = cfg.setup val client = httpClient() val ebicsLogger = EbicsLogger(ebicsLog) @@ -215,7 +232,7 @@ class EbicsSetup: CliktCommand() { if (!bankKeys.accepted) { // Finishing the setup by accepting the bank keys. if (autoAcceptKeys) bankKeys.accepted = true - else bankKeys.accepted = askUserToAcceptKeys(bankKeys) + else bankKeys.accepted = askUserToAcceptKeys(bankKeys, setupCfg) if (!bankKeys.accepted) { throw Exception("Cannot successfully finish the setup without accepting the bank keys") diff --git a/testbench/src/main/kotlin/Main.kt b/testbench/src/main/kotlin/Main.kt @@ -277,7 +277,7 @@ class Cli : CliktCommand() { throw Exception("Clients keys are required to run netzbon tests") } else if (clientKeys == null || !clientKeys.submitted_ini || !clientKeys.submitted_hia || bankKeys == null || !bankKeys.accepted) { step("Run EBICS setup") - if (!nexusCmd.run("ebics-setup --auto-accept-keys $debugFlags")) { + if (!nexusCmd.run("ebics-setup $debugFlags")) { clientKeys = loadClientKeys(clientKeysPath) if (kind.test) { if (clientKeys == null || !clientKeys.submitted_ini || !clientKeys.submitted_hia) {