Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Partnerships

A partnership is one directed relationship between an AS2 identity of yours (local_id) and one of a partner’s (remote_id). All of them live in partnerships.toml; one server can host many local identities.

Anatomy

[[partnership]]
id = "acme-outbound"              # unique config key (appears in logs/metrics)
local_id = "MYCOMPANY"            # our AS2-From when sending / AS2-To inbound
remote_id = "ACME"                # the partner's AS2 name
remote_url = "https://as2.acme.example/as2"   # present = outbound-capable
cert_aliases = { local = "me", remote = "acme" }

[partnership.security]
sign = "sha-256"                  # omit for unsigned
encrypt = "aes256-cbc"            # omit for unencrypted
compress = "before-signing"       # or "after-signing"; omit for none
content_transfer_encoding = "binary"   # "binary" (default) | "base64" | "quoted-printable"

[partnership.mdn]
request = true                    # ask for a receipt when we send
signed_micalg = "sha-256"         # ask for a SIGNED receipt with this digest
# async_url = "https://my.example/as2/mdn"   # asynchronous receipt delivery

# [partnership.http_auth]         # HTTP Basic for the partner's endpoint
# username = "u"
# password = "p"

# [partnership.interop]           # per-partner compatibility switches, see below

How inbound routing works

An arriving message’s AS2-From/AS2-To headers select the partnership (quoted AS2 names are handled per RFC 4130 §6.2). Unknown pairs are rejected with an authentication-failed disposition — there is no “accept anyone” mode.

The security policy is a floor, not a hint

Declaring sign and/or encrypt does two things:

  1. Outbound: those layers are applied when sending.
  2. Inbound: messages from this partner must carry those layers or they are rejected with insufficient-message-security. A partner (or an attacker) cannot downgrade the exchange to plaintext.

Migration escape hatches (interop.disable_decrypt, interop.disable_verify, interop.disable_decompress) opt out per layer, explicitly, per partner.

Onboarding gotcha — mirror the security attributes. In the BouncyCastle-derived AS2 world (and in as2d, for compatibility with it), whether MIME headers are included in the receipt digest is driven by each side’s own partnership attributes, not by the message. If you declare compression and the partner’s side does not, both implementations can be correct and the receipt MICs will still disagree. When receipts mismatch, compare partnership attributes with your partner first.

Interop switches

All default to sensible values; set them per partner when a counterpart needs it (see Working with specific products):

FlagDefaultPurpose
include_cert_in_signaturetrueembed our certificate in signatures (Peppol requires it)
rfc3851_micalgsfalseuse sha256-style spellings instead of sha-256
quote_header_valuesfalsequote outbound header values (some IBM Sterling setups)
block_error_mdnfalsenever send negative receipts to this partner
bc_style_gcmfalsesend AES-GCM the BouncyCastle way (Java AS2 partners)
force_decrypt / force_verifyfalseattempt the layer even when the content-type does not announce it
disable_decrypt / disable_verify / disable_decompressfalseskip a layer (weakens the floor; migration only)
verify_use_cert_in_body_partfalsetrust the certificate embedded in the message instead of the pinned one (weaker; for partners that rotate certificates in-band)

The full field list with types is in the partnerships.toml reference.