summaryrefslogtreecommitdiff
path: root/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt
diff options
context:
space:
mode:
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.kt346
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