summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine A <>2024-03-06 17:07:27 +0100
committerAntoine A <>2024-03-06 20:51:07 +0100
commit509c14f45fcbeb1eb09da1e16fa0ba4958db6854 (patch)
tree560ff9625ba5e232886b1eab9f08de55bc28de46
parentc5f106ddc3335ef63080ab4ebe4868f1f8917520 (diff)
downloadlibeufin-509c14f45fcbeb1eb09da1e16fa0ba4958db6854.tar.gz
libeufin-509c14f45fcbeb1eb09da1e16fa0ba4958db6854.tar.bz2
libeufin-509c14f45fcbeb1eb09da1e16fa0ba4958db6854.zip
Ebics3 HAC
-rw-r--r--ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt4
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt26
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt114
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt4
-rw-r--r--nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt55
5 files changed, 28 insertions, 175 deletions
diff --git a/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt b/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt
index c8370d4c..bc48fa6f 100644
--- a/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt
+++ b/ebics/src/main/kotlin/ebics_h005/Ebics3Request.kt
@@ -404,7 +404,7 @@ class Ebics3Request {
date: XMLGregorianCalendar,
bankEncPub: RSAPublicKey,
bankAuthPub: RSAPublicKey,
- myOrderParams: OrderDetails.BTDOrderParams
+ myOrderParams: OrderDetails.BTDOrderParams?
): Ebics3Request {
return Ebics3Request().apply {
version = "H005"
@@ -421,7 +421,7 @@ class Ebics3Request {
timestamp = date
partnerID = partnerId
orderDetails = OrderDetails().apply {
- this.adminOrderType = "BTD"
+ this.adminOrderType = if (myOrderParams == null) "HAC" else "BTD"
this.btdOrderParams = myOrderParams
}
bankPubKeyDigests = BankPubKeyDigests().apply {
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt
index f66e77a7..bea1c3f3 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/EbicsFetch.kt
@@ -84,31 +84,19 @@ private suspend fun downloadHelper(
doc: SupportedDocument,
processing: (InputStream) -> Unit
) {
- val isEbics3 = doc != SupportedDocument.PAIN_002_LOGS
- val initXml = if (isEbics3) {
- createEbics3DownloadInitialization(
- ctx.cfg,
- ctx.bankKeys,
- ctx.clientKeys,
- doc,
- lastExecutionTime
- )
- } else {
- createEbics25DownloadInit(
- ctx.cfg,
- ctx.clientKeys,
- ctx.bankKeys,
- doc,
- lastExecutionTime
- )
- }
+ val initXml = createEbics3DownloadInitialization(
+ ctx.cfg,
+ ctx.bankKeys,
+ ctx.clientKeys,
+ doc,
+ lastExecutionTime
+ )
return ebicsDownload(
ctx.httpClient,
ctx.cfg,
ctx.clientKeys,
ctx.bankKeys,
initXml,
- isEbics3,
processing
)
}
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 b561be8d..1c791886 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics2.kt
@@ -43,120 +43,6 @@ import javax.xml.datatype.DatatypeFactory
private val logger: Logger = LoggerFactory.getLogger("libeufin-nexus-ebics2")
/**
- * Creates a EBICS 2.5 download init. message. So far only used
- * to fetch the PostFinance bank accounts.
- */
-fun createEbics25DownloadInit(
- cfg: EbicsSetupConfig,
- clientKeys: ClientPrivateKeysFile,
- bankKeys: BankPublicKeysFile,
- whichDoc: SupportedDocument,
- startDate: Instant? = null,
- endDate: Instant? = null,
-): ByteArray {
- val orderType = when(whichDoc) {
- SupportedDocument.PAIN_002 -> "Z01"
- SupportedDocument.CAMT_052 -> "Z52"
- SupportedDocument.CAMT_053 -> "Z53"
- SupportedDocument.CAMT_054 -> "Z54"
- SupportedDocument.PAIN_002_LOGS -> "HAC"
- }
- val nonce = getNonce(128)
- val req = EbicsRequest.createForDownloadInitializationPhase(
- cfg.ebicsUserId,
- cfg.ebicsPartnerId,
- cfg.ebicsHostId,
- nonce,
- DatatypeFactory.newInstance().newXMLGregorianCalendar(
- GregorianCalendar(
- TimeZone.getTimeZone(ZoneId.systemDefault())
- )
- ),
- bankKeys.bank_encryption_public_key,
- bankKeys.bank_authentication_public_key,
- orderType,
- EbicsRequest.StandardOrderParams().apply {
- if (startDate != null) {
- val r = EbicsDateRange(startDate, endDate ?: Instant.now())
- dateRange = EbicsRequest.DateRange().apply {
- start = getXmlDate(r.start)
- end = getXmlDate(r.end)
- }
- }
- }
- )
- val doc = XMLUtil.convertJaxbToDocument(req)
- XMLUtil.signEbicsDocument(
- doc,
- clientKeys.authentication_private_key,
- withEbics3 = false
- )
- return XMLUtil.convertDomToBytes(doc)
-}
-
-/**
- * Creates raw XML for an EBICS receipt phase.
- *
- * @param cfg configuration handle.
- * @param clientKeys user EBICS private keys.
- * @param transactionId transaction ID of the EBICS communication that
- * should receive this receipt.
- * @param success was the download successfully processed
- * @return receipt request in XML.
- */
-fun createEbics25DownloadReceiptPhase(
- cfg: EbicsSetupConfig,
- clientKeys: ClientPrivateKeysFile,
- transactionId: String,
- success: Boolean
-): ByteArray {
- val req = EbicsRequest.createForDownloadReceiptPhase(
- transactionId,
- cfg.ebicsHostId,
- success
- )
- val doc = XMLUtil.convertJaxbToDocument(req)
- XMLUtil.signEbicsDocument(
- doc,
- clientKeys.authentication_private_key,
- withEbics3 = false
- )
- return XMLUtil.convertDomToBytes(doc)
-}
-
-/**
- * Creates raw XML for an EBICS transfer phase.
- *
- * @param cfg configuration handle.
- * @param clientKeys user EBICS private keys.
- * @param segNumber which segment we ask the bank.
- * @param totalSegments how many segments compose the whole EBICS transaction.
- * @param transactionId ID of the EBICS transaction that transports all the segments.
- * @return raw XML string of the request.
- */
-fun createEbics25DownloadTransferPhase(
- cfg: EbicsSetupConfig,
- clientKeys: ClientPrivateKeysFile,
- segNumber: Int,
- totalSegments: Int,
- transactionId: String
-): ByteArray {
- val req = EbicsRequest.createForDownloadTransferPhase(
- hostID = cfg.ebicsHostId,
- segmentNumber = segNumber,
- numSegments = totalSegments,
- transactionID = transactionId
- )
- val doc = XMLUtil.convertJaxbToDocument(req)
- XMLUtil.signEbicsDocument(
- doc,
- clientKeys.authentication_private_key,
- withEbics3 = false
- )
- return XMLUtil.convertDomToBytes(doc)
-}
-
-/**
* Parses the raw XML that came from the bank into the Nexus representation.
*
* @param clientEncryptionKey client private encryption key, used to decrypt
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt
index e1b17699..29a5e5e7 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/Ebics3.kt
@@ -124,14 +124,14 @@ fun createEbics3DownloadInitialization(
DatatypeFactory.newInstance().newXMLGregorianCalendar(GregorianCalendar()),
bankAuthPub = bankkeys.bank_authentication_public_key,
bankEncPub = bankkeys.bank_encryption_public_key,
- myOrderParams = Ebics3Request.OrderDetails.BTDOrderParams().apply {
+ myOrderParams = if (whichDoc == SupportedDocument.PAIN_002_LOGS) null else Ebics3Request.OrderDetails.BTDOrderParams().apply {
service = Ebics3Request.OrderDetails.Service().apply {
serviceName = when(whichDoc) {
SupportedDocument.PAIN_002 -> "PSR"
SupportedDocument.CAMT_052 -> "STM"
SupportedDocument.CAMT_053 -> "EOP"
SupportedDocument.CAMT_054 -> "REP"
- SupportedDocument.PAIN_002_LOGS -> throw Exception("HAC (--only-logs) not available in EBICS 3")
+ SupportedDocument.PAIN_002_LOGS -> "HAC"
}
scope = "CH"
container = Ebics3Request.OrderDetails.Service.Container().apply {
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt
index c4231455..edbef2e9 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/ebics/EbicsCommon.kt
@@ -113,6 +113,7 @@ suspend fun HttpClient.postToBank(bankUrl: String, msg: ByteArray): InputStream
setBody(msg)
}
if (res.status != HttpStatusCode.OK) {
+ println(res.bodyAsText())
throw Exception("Invalid response status: ${res.status}")
}
return res.bodyAsChannel().toInputStream()
@@ -273,7 +274,6 @@ private fun areCodesOk(ebicsResponseContent: EbicsResponseContent) =
* @param clientKeys client EBICS private keys.
* @param bankKeys bank EBICS public keys.
* @param reqXml raw EBICS XML request of the init phase.
- * @param isEbics3 true for EBICS 3, false otherwise.
* @param processing processing lambda receiving EBICS files as a byte stream if the transaction was not empty.
* @return T if the transaction was successful. If the failure is at the EBICS
* level EbicsSideException is thrown else ités the exception of the processing lambda.
@@ -284,7 +284,6 @@ suspend fun ebicsDownload(
clientKeys: ClientPrivateKeysFile,
bankKeys: BankPublicKeysFile,
reqXml: ByteArray,
- isEbics3: Boolean,
processing: (InputStream) -> Unit
) = coroutineScope {
val scope = this
@@ -293,7 +292,7 @@ suspend fun ebicsDownload(
// error loop until the pending transaction timeout.
// TODO find a way to cancel the pending transaction ?
withContext(NonCancellable) {
- val initResp = postEbics(client, cfg, bankKeys, reqXml, isEbics3)
+ val initResp = postEbics(client, cfg, bankKeys, reqXml, true)
logger.debug("Download init phase done. EBICS- and bank-technical codes are: ${initResp.technicalReturnCode}, ${initResp.bankReturnCode}")
if (initResp.technicalReturnCode != EbicsReturnCode.EBICS_OK) {
throw Exception("Download init phase has EBICS-technical error: ${initResp.technicalReturnCode}")
@@ -332,11 +331,9 @@ suspend fun ebicsDownload(
for (x in 2 .. howManySegments) {
if (!scope.isActive) break
// request segment number x.
- val transReq = if (isEbics3)
- createEbics3DownloadTransferPhase(cfg, clientKeys, x, howManySegments, tId)
- else createEbics25DownloadTransferPhase(cfg, clientKeys, x, howManySegments, tId)
+ val transReq = createEbics3DownloadTransferPhase(cfg, clientKeys, x, howManySegments, tId)
- val transResp = postEbics(client, cfg, bankKeys, transReq, isEbics3)
+ val transResp = postEbics(client, cfg, bankKeys, transReq, true)
if (!areCodesOk(transResp)) {
throw EbicsSideException(
"EBICS transfer segment #$x failed.",
@@ -350,9 +347,7 @@ suspend fun ebicsDownload(
ebicsChunks.add(chunk)
}
suspend fun receipt(success: Boolean) {
- val receiptXml = if (isEbics3)
- createEbics3DownloadReceiptPhase(cfg, clientKeys, tId, success)
- else createEbics25DownloadReceiptPhase(cfg, clientKeys, tId, success)
+ val receiptXml = createEbics3DownloadReceiptPhase(cfg, clientKeys, tId, success)
// Sending the receipt to the bank.
postEbics(
@@ -360,7 +355,7 @@ suspend fun ebicsDownload(
cfg,
bankKeys,
receiptXml,
- isEbics3
+ true
)
}
if (scope.isActive) {
@@ -433,33 +428,17 @@ fun prepareUploadPayload(
clientKeys: ClientPrivateKeysFile,
bankKeys: BankPublicKeysFile,
payload: ByteArray,
- isEbics3: Boolean
): PreparedUploadData {
- val encryptionResult: CryptoUtil.EncryptionResult = if (isEbics3) {
- val innerSignedEbicsXml = signOrderEbics3( // A006 signature.
- payload,
- clientKeys.signature_private_key,
- cfg.ebicsPartnerId,
- cfg.ebicsUserId
- )
- val userSignatureDataEncrypted = CryptoUtil.encryptEbicsE002(
- EbicsOrderUtil.encodeOrderDataXml(innerSignedEbicsXml),
- bankKeys.bank_encryption_public_key
- )
- userSignatureDataEncrypted
- } else {
- val innerSignedEbicsXml = signOrder( // A006 signature.
- payload,
- clientKeys.signature_private_key,
- cfg.ebicsPartnerId,
- cfg.ebicsUserId
- )
- val userSignatureDataEncrypted = CryptoUtil.encryptEbicsE002(
- EbicsOrderUtil.encodeOrderDataXml(innerSignedEbicsXml),
- bankKeys.bank_encryption_public_key
- )
- userSignatureDataEncrypted
- }
+ val innerSignedEbicsXml = signOrderEbics3( // A006 signature.
+ payload,
+ clientKeys.signature_private_key,
+ cfg.ebicsPartnerId,
+ cfg.ebicsUserId
+ )
+ val encryptionResult = CryptoUtil.encryptEbicsE002(
+ EbicsOrderUtil.encodeOrderDataXml(innerSignedEbicsXml),
+ bankKeys.bank_encryption_public_key
+ )
val plainTransactionKey = encryptionResult.plainTransactionKey
?: throw Exception("Could not generate the transaction key, cannot encrypt the payload!")
// Then only E002 symmetric (with ephemeral key) encrypt.
@@ -526,7 +505,7 @@ suspend fun doEbicsUpload(
payload: ByteArray,
): EbicsResponseContent = withContext(NonCancellable) {
// TODO use a lambda and pass the order detail there for atomicity ?
- val preparedPayload = prepareUploadPayload(cfg, clientKeys, bankKeys, payload, isEbics3 = true)
+ val preparedPayload = prepareUploadPayload(cfg, clientKeys, bankKeys, payload)
val initXml = createEbics3RequestForUploadInitialization(
cfg,
preparedPayload,