AS2 & AS4 · ebMS3 · Rust

AS2 and AS4 messaging for Rust, strict by default.

asx-rs is an async Rust library for AS2 (RFC 4130) and AS4 (OASIS ebMS3 / eDelivery). Pick a network profile — BDEW, Peppol, eDelivery, ENTSOG or AS2 — and the client signs, encrypts and verifies as that network requires. A crate you embed, not a gateway you operate.

cargo add asx-rs

Design

A profile, not knobs

Profile::bdew(), peppol(), edelivery_1_15(), entsog() and as2() fix every algorithm, token form and header rule. Nothing loosens a profile; misconfiguration is refused at build().

Verification is a type

send returns Verified<Receipt>, and your inbound handler receives Verified<UserMessage>. Only the library constructs one, so nothing unchecked reaches your code.

A library, not a platform

No container, database or JVM. Deduplication, the audit trail, HTTP and private keys (HSM/KMS) are traits; the testkit checks your implementation.

What it implements

AS2 — RFC 4130

  • CMS/S/MIME signing and encryption (RSA, ECDSA)
  • Signed MDN with the MIC verified, synchronous or asynchronous
  • Duplicate detection on receive
  • RFC 5402 compression accepted on receive
AS2 guide →

AS4 — OASIS ebMS3

  • WS-Security signatures with XML Signature Wrapping defences; ECDSA as XMLDSig 1.1 r ‖ s
  • WSS SwA encryption: RSA-OAEP or ECDH-ES + ConcatKDF, AES-GCM
  • Signed receipts verified as non-repudiation evidence
  • One-Way/Push, the ebMS3 test service, the BDEW path switch
  • Peppol dynamic discovery (BDXL, SMP)
AS4 guide →

Send a BDEW AS4 message

use asx::{as4::{As4, Message}, Certificate, KeyPair, LocalParty, Partner, Payload, Profile};

async fn send(partner: Partner, sig: KeyPair, enc: KeyPair, root: Certificate, edi: Vec<u8>) -> asx::Result<()> {
    let as4 = As4::builder(Profile::bdew())
        .local(LocalParty::new("9900000000001")
            .party_type("urn:oasis:names:tc:ebcore:partyid-type:unregistered:BDEW")
            .signer(sig)
            .decrypter(enc))
        .trust_anchor(root)
        .partner(partner.clone())
        .build()?;
    let receipt = as4
        .send(Message::to(&partner)
            .service("https://www.bdew.de/as4/communication/services/MP")
            .payload(Payload::new(edi, "application/octet-stream")))
        .await?;
    println!("delivered, receipt record {}", receipt.evidence().record_id());
    Ok(())
}

send returns only a receipt signed by the partner's pinned certificate that echoes the digests of what you sent. Full program: examples/as4_send.rs.

FAQ

Is this a gateway I have to run?

No. It is a crate you link into your own service. Deduplication, the audit sink and keys are traits you implement; a conformance suite tests your backend.

Which networks use AS4?

Peppol (e-invoicing), eDelivery (EU sector networks), the German energy market (BDEW; mandatory for electricity and gas) and ENTSOG (gas transmission). Each is a preset; see profiles.

Does it do AS2 as well?

Yes — RFC 4130: S/MIME signing and encryption, signed MDNs (synchronous, or asynchronous on send), duplicate detection.

Is it conformance-certified?

No. It is tested against independent implementations — phase4 (BDEW, both directions), xmlsec1, the openssl CLI and Holodeck B2B; see the conformance page.

What does it need to build?

Rust 1.88 or newer and a working OpenSSL. as2, as4 and http-client are default features; peppol and metrics are opt-in. No unsafe.

Start reading