libeufin

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

commit bbcbfba4d21f97f3ef5b450f45d01bec6d06ebd1
parent 56c184c2481fddd98144424b7bd43f2ecd41013e
Author: Antoine A <>
Date:   Tue, 12 Nov 2024 16:25:37 +0100

nexus: check bank keys during setup

Diffstat:
Mnexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt | 114++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
1 file changed, 66 insertions(+), 48 deletions(-)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/cli/EbicsSetup.kt @@ -66,61 +66,53 @@ private fun askUserToAcceptKeys(bankKeys: BankPublicKeysFile): Boolean { return userResponse == "yes, accept" } -/** - * Perform an EBICS key management [order] using [client] and update on disk - * keys - */ -suspend fun doKeysRequestAndUpdateState( +/** Perform an EBICS public key management [order] using [client] and update on disk state */ +private suspend fun submitClientKeys( cfg: NexusEbicsConfig, privs: ClientPrivateKeysFile, client: HttpClient, ebicsLogger: EbicsLogger, order: EbicsKeyMng.Order ) { + if (order == HPB) throw IllegalArgumentException("Only INI & HIA are supported for client keys") val resp = keyManagement(cfg, privs, client, ebicsLogger, order) - - when (order) { - INI, HIA -> { - if (resp.technicalCode == EbicsReturnCode.EBICS_INVALID_USER_OR_USER_STATE) { - throw Exception("$order status code ${resp.technicalCode}: either your IDs are incorrect, or you already have keys registered with this bank") - } - } - HPB -> { - if (resp.technicalCode == EbicsReturnCode.EBICS_AUTHENTICATION_FAILED) { - throw Exception("$order status code ${resp.technicalCode}: could not download bank keys, send client keys (and/or related PDF document with --generate-registration-pdf) to the bank") - } - } + if (resp.technicalCode == EbicsReturnCode.EBICS_INVALID_USER_OR_USER_STATE) { + throw Exception("$order status code ${resp.technicalCode}: either your IDs are incorrect, or you already have keys registered with this bank") } - val orderData = resp.okOrFail(order.name) when (order) { INI -> privs.submitted_ini = true HIA -> privs.submitted_hia = true - HPB -> { - val orderData = requireNotNull(orderData) { - "HPB: missing order data" - } - val (authPub, encPub) = EbicsKeyMng.parseHpbOrder(orderData) - val bankKeys = BankPublicKeysFile( - bank_authentication_public_key = authPub, - bank_encryption_public_key = encPub, - accepted = false - ) - try { - persistBankKeys(bankKeys, cfg.bankPublicKeysPath) - } catch (e: Exception) { - throw Exception("Could not update the $order state on disk", e) - } - } + HPB -> {} } - if (order != HPB) { - try { - persistClientKeys(privs, cfg.clientPrivateKeysPath) - } catch (e: Exception) { - throw Exception("Could not update the $order state on disk", e) - } + try { + persistClientKeys(privs, cfg.clientPrivateKeysPath) + } catch (e: Exception) { + throw Exception("Could not update the $order state on disk", e) + } +} + +/** Perform an EBICS private key management HPB using [client] */ +private suspend fun fetchPrivateKeys( + cfg: NexusEbicsConfig, + privs: ClientPrivateKeysFile, + client: HttpClient, + ebicsLogger: EbicsLogger +): BankPublicKeysFile { + val order = HPB + val resp = keyManagement(cfg, privs, client, ebicsLogger, order) + if (resp.technicalCode == EbicsReturnCode.EBICS_AUTHENTICATION_FAILED) { + throw Exception("$order status code ${resp.technicalCode}: could not download bank keys, send client keys (and/or related PDF document with --generate-registration-pdf) to the bank") } - + val orderData = requireNotNull(resp.okOrFail(order.name)) { + "$order: missing order data" + } + val (authPub, encPub) = EbicsKeyMng.parseHpbOrder(orderData) + return BankPublicKeysFile( + bank_authentication_public_key = authPub, + bank_encryption_public_key = encPub, + accepted = false + ) } /** @@ -180,18 +172,44 @@ class EbicsSetup: CliktCommand() { // Privs exist. Upload their pubs val keysNotSub = !clientKeys.submitted_ini - if ((!clientKeys.submitted_ini) || forceKeysResubmission) - doKeysRequestAndUpdateState(cfg.ebics, clientKeys, client, ebicsLogger, INI) + if (!clientKeys.submitted_ini || forceKeysResubmission) + submitClientKeys(cfg.ebics, clientKeys, client, ebicsLogger, INI) // Eject PDF if the keys were submitted for the first time, or the user asked. if (keysNotSub || generateRegistrationPdf) makePdf(clientKeys, cfg.ebics) - if ((!clientKeys.submitted_hia) || forceKeysResubmission) - doKeysRequestAndUpdateState(cfg.ebics, clientKeys, client, ebicsLogger, HIA) + if (!clientKeys.submitted_hia || forceKeysResubmission) + submitClientKeys(cfg.ebics, clientKeys, client, ebicsLogger, HIA) - // Checking if the bank keys exist on disk + val fetchedBankKeys = fetchPrivateKeys(cfg.ebics, clientKeys, client, ebicsLogger) if (bankKeys == null) { - doKeysRequestAndUpdateState(cfg.ebics, clientKeys, client, ebicsLogger, HPB) + // Accept bank keys logger.info("Bank keys stored at ${cfg.ebics.bankPublicKeysPath}") - bankKeys = loadBankKeys(cfg.ebics.bankPublicKeysPath)!! + try { + persistBankKeys(fetchedBankKeys, cfg.ebics.bankPublicKeysPath) + } catch (e: Exception) { + throw Exception("Could not store bank keys on disk", e) + } + bankKeys = fetchedBankKeys + } else { + // Check current bank keys + if (bankKeys.bank_encryption_public_key != fetchedBankKeys.bank_encryption_public_key) { + throw Exception(buildString { + append("On disk bank encryption key stored at ") + append(cfg.ebics.bankPublicKeysPath) + append(" doesn't match server key\nDisk: ") + append(CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_encryption_public_key).encodeUpHex().fmtChunkByTwo()) + append("\nServer: ") + append(CryptoUtil.getEbicsPublicKeyHash(fetchedBankKeys.bank_encryption_public_key).encodeUpHex().fmtChunkByTwo()) + }) + } else if (bankKeys.bank_authentication_public_key != fetchedBankKeys.bank_authentication_public_key) { + throw Exception(buildString { + append("On disk bank authentication key stored at ") + append(cfg.ebics.bankPublicKeysPath) + append(" doesn't match server key\nDisk: ") + append(CryptoUtil.getEbicsPublicKeyHash(bankKeys.bank_authentication_public_key).encodeUpHex().fmtChunkByTwo()) + append("\nServer: ") + append(CryptoUtil.getEbicsPublicKeyHash(fetchedBankKeys.bank_authentication_public_key).encodeUpHex().fmtChunkByTwo()) + }) + } } if (!bankKeys.accepted) {