EDI AS2 HTTP 跟踪?

EDI AS2 HTTP trace?

我们正在研究 AS2 实现,并希望能够构建有意义的测试用例以与 SoapUI 或 Postman 一起使用。 为此,我们有两种方法:

  1. 只需尝试 tcp-dump/trace 来自现有客户的电话
  2. 从普通 EDI 文档开始手动构建一些简单的调用

或我们放弃 (1) 的各种原因,因此我们必须使用 (2),并且我们需要一些文档。 来自 Oracle 的文档是一个很好的起点:https://docs.oracle.com/cd/E19398-01/820-1228/agfat/index.html

但我们无法真正找到从 ORDERS edi 文档(我们已​​有)开始构建 AS2 请求的分步指南。

理想情况下,我想要一个循序渐进的指南,内容如下:

  1. 生成私有证书:+commandline
  2. 加密 EDI 文档:+commandline +sampleoutput
  3. 创建签名:+commandline +sampleoutput
  4. 构建 S/MIME 包:+commandline +sampleoutput
  5. 发送过来 HTTP/S:+commandline +samplehttptrace

正在发送消息

要发送消息,我们需要一个包含要发送的消息的文件,双方的两对密钥(每个合作伙伴都有一对用于签名的密钥和另一对用于加密的密钥,每对密钥包含 public 和私钥)。对于本教程,我们将使用同一对密钥对每个合作伙伴进行签名和加密。

生成密钥

使用 OpenSSL 创建两对密钥:

openssl req -x509 -newkey rsa:2048 -keyout P1_private.pem -out P1_public.pem -days 365

第二对相同:

openssl req -x509 -newkey rsa:2048 -keyout P2_private.pem -out P2_public.pem -days 365

扩展私钥文件

P1_private.pem 和 P2_private.pem 仅包含私钥。 OpenSSL 支持扩展的 PEM 格式,其中私钥和 public 密钥都可以在一个文件中。这简化了一些 OpenSSL 命令(可以给出一个文件而不是两个)。本教程假定已完成此操作:

cat P1_public.pem >> P1_private.pem

cat P2_public.pem >> P2_private.pem

否则,请查看 OpenSSL 命令手册,了解如何在需要的地方指定第二个文件。

签署文件

假设我们想通过 AS2 协议从 P1 合作伙伴发送 GETMSG.edi 文件 => 到 P2,并进行签名和加密。首先我们添加适当的 MIME headers 到它:

Content-Type: application/edi-consent
Content-Disposition: attachment; filename="GETMSG.edi"

UNA:+./*'
UIB+UNOA:0++2289+++77777777:C:PASSWORDA+111111:M+19971001:074620'
UIH+SCRIPT:010:006:GETMSG+111'
UIT+111+2'
UIZ++1'

将新文件另存为 GETMSG.msg

然后用发送伙伴P1的私钥签名文件:

openssl smime -sign -in GETMSG.msg -out GETMSG_SIGNED.msg -signer P1_private.pem

注意:OpenSSL 放置以 'x-pkcs7-' 开头的旧 MIME 类型,某些应用程序 (pyAS2) 只能处理没有 eks 'pkcs7-' 的新 MIME 类型。只需从生成的文件中删除所有地方的 'x-'。

加密

现在我们有了多部分附件,第一部分是文件内容,第二部分是签名。现在我们用接收伙伴 P2 的 public 密钥加密它:

openssl smime -encrypt -in GETMSG_SIGNED.msg -out GETMSG_ENC.msg -des3 P2_public.pem

生成的文件 GETMSG_ENC.msg 现在可以作为请求发送给收件人,附加 AS2 headers。

注意:OpenSSL 放置以 'x-pkcs7-' 开头的旧 MIME 类型,某些应用程序 (pyAS2) 只能处理没有 eks 'pkcs7-' 的新 MIME 类型。只需从生成的文件中删除所有地方的 'x-'。

通过 c 发送URL

要使用 cURL 发送,我们必须将 POST 请求的 header 和 body 分开。从文件 GETMSG_ENC.msg 中删除所有 header(它应该以 'MI..' 开头)。 使用此命令将其从 P1(AS2 ID:p1as2)发送到 P2(AS2 ID:p2as2),假设 P2 URL 为“http://localhost:8080/pyas2/as2receive”:

set NOW=%DATE:~10,4%%DATE:~4,2%%DATE:~7,2%%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%

curl -i -X POST-H "Content-Disposition: attachment; filename=\"smime.p7m\""-H "Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name=\"smime.p7m\""-H "Content-Transfer-Encoding: base64"-H "AS2-TO: p1as2"-H "AS2-FROM: p2as2"-H "AS2-VERSION: 1.2"-H "MESSAGE-ID: <openssl%NOW%@LOCALHOST>"-H "Disposition-Notification-To: response@localhost"-H "DISPOSITION-NOTIFICATION-OPTIONS: signed-receipt-protocol=required, pkcs7-signature; signed-receipt-micalg=optional, sha1"--data-binary @GETMSG_ENC.msg http://localhost:8080/pyas2/as2receive

注意:此命令还会请求带有签名的 MDN(因为 Disposition-Notification-To 的存在和 DISPOSITION-NOTIFICATION-OPTIONS 的值)。

正在接收消息

接收方已经发生以下情况。这将包括解密消息、验证签名、提取有效负载和准备确认或消息处置通知 (MDN)。它还需要计算接收到的消息 (MIC) 的哈希值以作为确认发送。

解密请求

使用OpenSSL命令解码请求内容保存为smime.p7m:

openssl smime -decrypt -in smime.p7m -recip P2_public.pem -inkey P2_private.pem -out request.txt

验证签名

openssl smime -verify -in request.txt -nosigs -noverify -signer P2_public.pem -out original.txt

计算Received-content-MIC

接收到的内容的摘要必须通过 MIME headers 的原始文件进行计算,在我们的例子中是 GETMSG.msg.

的内容
openssl dgst -sha1 -binary GETMSG.msg | openssl enc -e -base64

注意:在现实生活中,接收者必须从 multipart/signed 类型的解密内容中提取它。第一部分是接收到的内容。

消息处理通知

未签名的邮件处理通知或确认看起来像多部分报告:

Content-Type: multipart/report; report-type="disposition-notification"; boundary="===============1785295974=="

--===============1785295974==
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit

The AS2 message has been processed. Thank you for exchanging AS2 messages with Pyas2.

--===============1785295974==
Content-Type: message/disposition-notification; charset="us-ascii"
Content-Transfer-Encoding: 7bit

Reporting-UA: Bots Opensource EDI Translator
Original-Recipient: rfc822; p1as2
Final-Recipient: rfc822; p1as2
Original-Message-ID: <openssl20170706165018@LOCALHOST>
Disposition: automatic-action/MDN-sent-automatically; processed
Received-content-MIC: 1GZ1SDk5vvGz5YFGYP6lfhk4MXE=, sha1

--===============1785295974==--

签名消息处理通知

如果请求签名的 MDN(取决于 'Disposition-Notification-Options' HTTP header),那么上面显示的多部分报告将包装在 multipart/signed 中。第二部分是上面显示的第一部分的签名。如果我们假设 mdn.txt 包含如上所示未签名的 MDN,则对其进行签名:

openssl cms -sign -signer P2_private.pem -in mdn.txt -out mdn_signed.txt

现在我们只需要在 mdn.txt 或 mdn_signed.txt 的顶部添加一些特定于 AS2 的 header,这取决于所请求的 MDN 类型,然后再通过 HTTP 传输它(取自pyAS2的实际响应):

ediint-features: CEM
as2-from: p1as2
user-agent: PYAS2, A pythonic AS2 server
AS2-Version: 1.2
as2-to: p2as2
date: Thu, 06 Jul 2017 16:50:18 +0200
X-Frame-Options: SAMEORIGIN
Message-ID: <149935261885.25752.7388914440262498594@HOSTNAME>
Transfer-Encoding: chunked
Server: pyas2-webserver

基于来源: pyAS2 文档、OpenSSL 文档、NCPDP SCRIPT 消息示例。

我最近一直在尝试使用 Andrew Haritonkin 在他对这个问题的回答中描述的方法来测试新的 AS2 实现。

我发现了一些值得一提的怪癖。

  • openssl smime -encrypt 默认发出 - 逻辑上足够 - S/MIME 格式的内容。这不被我的 AS2 解码器接受 - 作为参考,这是 Azure Logic Apps AS2 decode action. I found that the correct format is specified by adding the -outform DER option to the encrypt step, which causes openssl to emit the encrypted message in DER format
  • 我从 Azure Key Vault 生成的 .pfx 证书开始。我找不到让 openssl 接受它进行签名的方法,所以我必须先将它转换为 PEM。命令行 openssl pkcs12 -in mycert.pfx -out mycert.pem -passin pass: -nodes 似乎可以解决问题。 -passin pass: 指定输入证书的私钥密码为空字符串,Azure 生成时默认为空字符串。不这样做会导致 openssl 提示输入密码,这在我使用它的上下文中使整个过程失败(Docker 容器)。 -nodes 表示 "no DES" 而不是 "nodes" 并且表示私钥不应在输出证书中由密码短语加密或保护。不用说,这听起来像是要传递的高风险数据,因为它没有任何防止私钥泄露的保护措施。