commit 7c4f92ff090440b0b595ac8eee05cd5969aec9be
parent e5210b0922265ec026022db60a4e1e8bf3ae46dd
Author: Antoine A <>
Date: Fri, 30 May 2025 17:28:01 +0200
nexus: accept bank keys matching config hashes
Diffstat:
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) {