diff options
author | Antoine A <> | 2024-03-08 17:58:26 +0100 |
---|---|---|
committer | Antoine A <> | 2024-03-08 17:58:26 +0100 |
commit | 298557c74a4fa8112cb4c8b0be644496d77e74a1 (patch) | |
tree | 1c124c5e2d259864219b89bc02446a11c2628218 /nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt | |
parent | 8b0ca3dbd7359a402b1671a7cb0fa37b92543d1e (diff) | |
download | libeufin-298557c74a4fa8112cb4c8b0be644496d77e74a1.tar.gz libeufin-298557c74a4fa8112cb4c8b0be644496d77e74a1.tar.bz2 libeufin-298557c74a4fa8112cb4c8b0be644496d77e74a1.zip |
More simplification & refactoring
Diffstat (limited to 'nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt')
-rw-r--r-- | nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt | 346 |
1 files changed, 143 insertions, 203 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt index 9f2d2afd..bee41525 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt @@ -23,8 +23,6 @@ package tech.libeufin.nexus.ebics -import org.slf4j.Logger -import org.slf4j.LoggerFactory import org.w3c.dom.Document import tech.libeufin.common.crypto.CryptoUtil import tech.libeufin.common.* @@ -39,237 +37,179 @@ import java.util.* import javax.xml.datatype.DatatypeFactory import java.security.interfaces.* -private val logger: Logger = LoggerFactory.getLogger("libeufin-nexus-ebics2") - -/** - * Parses the raw XML that came from the bank into the Nexus representation. - * - * @param clientEncryptionKey client private encryption key, used to decrypt - * the transaction key. - * @param xml the bank raw XML response - * @return the internal representation of the XML response, or null if the parsing or the decryption failed. - * Note: it _is_ possible to successfully return the internal repr. of this response, where - * the payload is null. That's however still useful, because the returned type provides bank - * and EBICS return codes. - */ -fun parseKeysMgmtResponse( - clientEncryptionKey: RSAPrivateCrtKey, - xml: Document -): EbicsKeyManagementResponseContent { - return XmlDestructor.fromDoc(xml, "ebicsKeyManagementResponse") { - lateinit var technicalReturnCode: EbicsReturnCode - lateinit var bankReturnCode: EbicsReturnCode - lateinit var reportText: String - var payload: ByteArray? = null - one("header") { - one("mutable") { - technicalReturnCode = EbicsReturnCode.lookup(one("ReturnCode").text()) - reportText = one("ReportText").text() +/** Ebics 3 protocol for */ +class Ebics3KeyMng( + private val cfg: EbicsSetupConfig, + private val clientKeys: ClientPrivateKeysFile +) { + fun INI(): ByteArray { + val inner = XMLOrderData(cfg, "ns2:SignaturePubKeyOrderData", "http://www.ebics.org/S001") { + el("ns2:SignaturePubKeyInfo") { + RSAKeyXml(clientKeys.signature_private_key) + el("ns2:SignatureVersion", "A006") } } - one("body") { - bankReturnCode = EbicsReturnCode.lookup(one("ReturnCode").text()) - payload = opt("DataTransfer") { - val descriptionInfo = one("DataEncryptionInfo") { - DataEncryptionInfo( - one("TransactionKey").text().decodeBase64(), - one("EncryptionPubKeyDigest").text().decodeBase64() - ) + val doc = XmlBuilder.toDom("ebicsUnsecuredRequest", "urn:org:ebics:H004") { + attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H004") + attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") + attr("Version", "H004") + attr("Revision", "1") + el("header") { + attr("authenticate", "true") + el("static") { + el("HostID", cfg.ebicsHostId) + el("PartnerID", cfg.ebicsPartnerId) + el("UserID", cfg.ebicsUserId) + el("OrderDetails") { + el("OrderType", "INI") + el("OrderAttribute", "DZNNN") + } + el("SecurityMedium", "0200") } - decryptAndDecompressPayload( - clientEncryptionKey, - descriptionInfo, - listOf(one("OrderData").text()) - ).readBytes() + el("mutable") } + el("body/DataTransfer/OrderData", inner) } - EbicsKeyManagementResponseContent(technicalReturnCode, bankReturnCode, payload) + return XMLUtil.convertDomToBytes(doc) } -} -private fun XmlBuilder.RSAKeyXml(key: RSAPrivateCrtKey) { - el("ns2:PubKeyValue") { - el("ds:RSAKeyValue") { - el("ds:Modulus", key.modulus.encodeBase64()) - el("ds:Exponent", key.publicExponent.encodeBase64()) - } - } -} - -private fun XMLOrderData(cfg: EbicsSetupConfig, name: String, schema: String, build: XmlBuilder.() -> Unit): String { - return XmlBuilder.toBytes(name) { - attr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") - attr("xmlns:ns2", schema) - build() - el("ns2:PartnerID", cfg.ebicsPartnerId) - el("ns2:UserID", cfg.ebicsUserId) - }.inputStream().deflate().encodeBase64() -} - -/** - * Generates the INI message to upload the signature key. - * - * @param cfg handle to the configuration. - * @param clientKeys set of all the client keys. - * @return the raw EBICS INI message. - */ -fun generateIniMessage(cfg: EbicsSetupConfig, clientKeys: ClientPrivateKeysFile): ByteArray { - val inner = XMLOrderData(cfg, "ns2:SignaturePubKeyOrderData", "http://www.ebics.org/S001") { - el("ns2:SignaturePubKeyInfo") { - RSAKeyXml(clientKeys.signature_private_key) - el("ns2:SignatureVersion", "A006") + fun HIA(): ByteArray { + val inner = XMLOrderData(cfg, "ns2:HIARequestOrderData", "urn:org:ebics:H004") { + el("ns2:AuthenticationPubKeyInfo") { + RSAKeyXml(clientKeys.authentication_private_key) + el("ns2:AuthenticationVersion", "X002") + } + el("ns2:EncryptionPubKeyInfo") { + RSAKeyXml(clientKeys.encryption_private_key) + el("ns2:EncryptionVersion", "E002") + } } - } - val doc = XmlBuilder.toDom("ebicsUnsecuredRequest", "urn:org:ebics:H004") { - attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H004") - attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") - attr("Version", "H004") - attr("Revision", "1") - el("header") { - attr("authenticate", "true") - el("static") { - el("HostID", cfg.ebicsHostId) - el("PartnerID", cfg.ebicsPartnerId) - el("UserID", cfg.ebicsUserId) - el("OrderDetails") { - el("OrderType", "INI") - el("OrderAttribute", "DZNNN") + val doc = XmlBuilder.toDom("ebicsUnsecuredRequest", "urn:org:ebics:H004") { + attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H004") + attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") + attr("Version", "H004") + attr("Revision", "1") + el("header") { + attr("authenticate", "true") + el("static") { + el("HostID", cfg.ebicsHostId) + el("PartnerID", cfg.ebicsPartnerId) + el("UserID", cfg.ebicsUserId) + el("OrderDetails") { + el("OrderType", "HIA") + el("OrderAttribute", "DZNNN") + } + el("SecurityMedium", "0200") } - el("SecurityMedium", "0200") + el("mutable") } - el("mutable") + el("body/DataTransfer/OrderData", inner) } - el("body/DataTransfer/OrderData", inner) + return XMLUtil.convertDomToBytes(doc) } - return XMLUtil.convertDomToBytes(doc) -} -/** - * Generates the HIA message: uploads the authentication and - * encryption keys. - * - * @param cfg handle to the configuration. - * @param clientKeys set of all the client keys. - * @return the raw EBICS HIA message. - */ -fun generateHiaMessage(cfg: EbicsSetupConfig, clientKeys: ClientPrivateKeysFile): ByteArray { - val inner = XMLOrderData(cfg, "ns2:HIARequestOrderData", "urn:org:ebics:H004") { - el("ns2:AuthenticationPubKeyInfo") { - RSAKeyXml(clientKeys.authentication_private_key) - el("ns2:AuthenticationVersion", "X002") - } - el("ns2:EncryptionPubKeyInfo") { - RSAKeyXml(clientKeys.encryption_private_key) - el("ns2:EncryptionVersion", "E002") - } - } - val doc = XmlBuilder.toDom("ebicsUnsecuredRequest", "urn:org:ebics:H004") { - attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H004") - attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") - attr("Version", "H004") - attr("Revision", "1") - el("header") { - attr("authenticate", "true") - el("static") { - el("HostID", cfg.ebicsHostId) - el("PartnerID", cfg.ebicsPartnerId) - el("UserID", cfg.ebicsUserId) - el("OrderDetails") { - el("OrderType", "HIA") - el("OrderAttribute", "DZNNN") + fun HPB(): ByteArray { + val nonce = getNonce(128) + val doc = XmlBuilder.toDom("ebicsNoPubKeyDigestsRequest", "urn:org:ebics:H004") { + attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H004") + attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") + attr("Version", "H004") + attr("Revision", "1") + el("header") { + attr("authenticate", "true") + el("static") { + el("HostID", cfg.ebicsHostId) + el("Nonce", nonce.encodeUpHex()) + el("Timestamp", Instant.now().xmlDateTime()) + el("PartnerID", cfg.ebicsPartnerId) + el("UserID", cfg.ebicsUserId) + el("OrderDetails") { + el("OrderType", "HPB") + el("OrderAttribute", "DZHNN") + } + el("SecurityMedium", "0000") } - el("SecurityMedium", "0200") + el("mutable") } - el("mutable") + el("AuthSignature") + el("body") } - el("body/DataTransfer/OrderData", inner) + XMLUtil.signEbicsDocument(doc, clientKeys.authentication_private_key) + return XMLUtil.convertDomToBytes(doc) } - return XMLUtil.convertDomToBytes(doc) -} -/** - * Generates the HPB message: downloads the bank keys. - * - * @param cfg handle to the configuration. - * @param clientKeys set of all the client keys. - * @return the raw EBICS HPB message. - */ -fun generateHpbMessage(cfg: EbicsSetupConfig, clientKeys: ClientPrivateKeysFile): ByteArray { - val nonce = getNonce(128) - val doc = XmlBuilder.toDom("ebicsNoPubKeyDigestsRequest", "urn:org:ebics:H004") { - attr("http://www.w3.org/2000/xmlns/", "xmlns", "urn:org:ebics:H004") - attr("http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") - attr("Version", "H004") - attr("Revision", "1") - el("header") { - attr("authenticate", "true") - el("static") { - el("HostID", cfg.ebicsHostId) - el("Nonce", nonce.encodeUpHex()) - el("Timestamp", Instant.now().xmlDateTime()) - el("PartnerID", cfg.ebicsPartnerId) - el("UserID", cfg.ebicsUserId) - el("OrderDetails") { - el("OrderType", "HPB") - el("OrderAttribute", "DZHNN") - } - el("SecurityMedium", "0000") + /* ----- Helpers ----- */ + + private fun XmlBuilder.RSAKeyXml(key: RSAPrivateCrtKey) { + el("ns2:PubKeyValue") { + el("ds:RSAKeyValue") { + el("ds:Modulus", key.modulus.encodeBase64()) + el("ds:Exponent", key.publicExponent.encodeBase64()) } - el("mutable") } - el("AuthSignature") - el("body") } - XMLUtil.signEbicsDocument(doc, clientKeys.authentication_private_key) - return XMLUtil.convertDomToBytes(doc) -} + + private fun XMLOrderData(cfg: EbicsSetupConfig, name: String, schema: String, build: XmlBuilder.() -> Unit): String { + return XmlBuilder.toBytes(name) { + attr("xmlns:ds", "http://www.w3.org/2000/09/xmldsig#") + attr("xmlns:ns2", schema) + build() + el("ns2:PartnerID", cfg.ebicsPartnerId) + el("ns2:UserID", cfg.ebicsUserId) + }.inputStream().deflate().encodeBase64() + } -class HpbResponseData( - val hostID: String, - val encryptionPubKey: RSAPublicKey, - val encryptionVersion: String, - val authenticationPubKey: RSAPublicKey, - val authenticationVersion: String -) + companion object { + fun parseResponse(doc: Document, clientEncryptionKey: RSAPrivateCrtKey): EbicsResponse<ByteArray?> { + return XmlDestructor.fromDoc(doc, "ebicsKeyManagementResponse") { + lateinit var technicalCode: EbicsReturnCode + lateinit var bankCode: EbicsReturnCode + var payload: ByteArray? = null + one("header") { + one("mutable") { + technicalCode = EbicsReturnCode.lookup(one("ReturnCode").text()) + } + } + one("body") { + bankCode = EbicsReturnCode.lookup(one("ReturnCode").text()) + payload = opt("DataTransfer") { + val descriptionInfo = one("DataEncryptionInfo") { + DataEncryptionInfo( + one("TransactionKey").text().decodeBase64(), + one("EncryptionPubKeyDigest").text().decodeBase64() + ) + } + decryptAndDecompressPayload( + clientEncryptionKey, + descriptionInfo, + listOf(one("OrderData").text()) + ).readBytes() + } + } + EbicsResponse( + technicalCode = technicalCode, + bankCode, + content = payload + ) + } + } -fun parseEbicsHpbOrder(orderDataRaw: InputStream): HpbResponseData { - return XmlDestructor.fromStream(orderDataRaw, "HPBResponseOrderData") { - val (authenticationPubKey, authenticationVersion) = one("AuthenticationPubKeyInfo") { - Pair( - one("PubKeyValue").one("RSAKeyValue") { + fun parseHpbOrder(data: ByteArray): Pair<RSAPublicKey, RSAPublicKey> { + return XmlDestructor.fromStream(data.inputStream(), "HPBResponseOrderData") { + val authPub = one("AuthenticationPubKeyInfo").one("PubKeyValue").one("RSAKeyValue") { CryptoUtil.loadRsaPublicKeyFromComponents( one("Modulus").text().decodeBase64(), one("Exponent").text().decodeBase64(), ) - }, - one("AuthenticationVersion").text() - ) - } - val (encryptionPubKey, encryptionVersion) = one("EncryptionPubKeyInfo") { - Pair( - one("PubKeyValue").one("RSAKeyValue") { + } + val encPub = one("EncryptionPubKeyInfo").one("PubKeyValue").one("RSAKeyValue") { CryptoUtil.loadRsaPublicKeyFromComponents( one("Modulus").text().decodeBase64(), one("Exponent").text().decodeBase64(), ) - }, - one("EncryptionVersion").text() - ) - + } + Pair(authPub, encPub) + } } - val hostID: String = one("HostID").text() - HpbResponseData( - hostID = hostID, - encryptionPubKey = encryptionPubKey, - encryptionVersion = encryptionVersion, - authenticationPubKey = authenticationPubKey, - authenticationVersion = authenticationVersion - ) } -} - -data class EbicsKeyManagementResponseContent( - val technicalReturnCode: EbicsReturnCode, - val bankReturnCode: EbicsReturnCode?, - val orderData: ByteArray? -)
\ No newline at end of file +}
\ No newline at end of file |