Skip to content

Add EBICS 3.0 (H005) support alongside 2.5 (H004) - #2

Draft
Uepsilon wants to merge 12 commits into
mainfrom
feature/ebics-3.0-h005-support
Draft

Add EBICS 3.0 (H005) support alongside 2.5 (H004)#2
Uepsilon wants to merge 12 commits into
mainfrom
feature/ebics-3.0-h005-support

Conversation

@Uepsilon

@Uepsilon Uepsilon commented Jul 3, 2026

Copy link
Copy Markdown

Context

EBICS 2.5 (H004) is sunsetting. This PR adds EBICS 3.0 (H005) support as an opt-in version: client option (default :h004), so existing 2.5 users are unaffected — no breaking changes.

Epics::Client.new(keys, 'pass', url, host, user, partner, version: :h005)

The crypto layer (A006 RSA-PSS / X002 / E002 / AES) already matches what H005 uses, so the work is confined to the XML envelope, the OrderDetails/BTF structure, response parsing, and X.509 key management.

What changed

  • Version abstraction: descriptor table + client namespace/protocol_version/h005? readers; envelope and all response/client XPaths parameterized by namespace.
  • OrderDetails: version-branched. H005 emits AdminOrderType + BTF Service (order ServiceName, Scope, ServiceOption, Container, MsgName), an empty SignatureFlag (with optional requestEDS), and StandardOrderParams for admin downloads.
  • BTU/BTD: new order classes + Epics::BTF value object + Epics::BtfMapping (German starter set). Common convenience methods (CCT, CDD, STA, C53, …) auto-route to BTU/BTD under H005.
  • Uploads: mandatory H005 DataDigest (A006).
  • Key management: self-signed X.509 certificate generation; INI/HIA/HPB send certificates only (S002 namespace, no RSAKeyValue) as H005 requires.

Verification

Bundled the official H005 XSD set into spec/xsd/. The matcher is version-aware and the suite XSD-validates every generated H005 request (INI/HIA/HPB, HTD/HAA/HKD/HPD/HAC, BTU/BTD across init/transfer/receipt) plus the INI payload against ebics_signature_S002.xsd.

225 examples, 0 failures — all original H004 specs unchanged.

Follow-ups

  • End-to-end verification against a live German H005 test endpoint (needs bank credentials).
  • BTF message versions in BtfMapping are common defaults and are bank-specific — verify per bank / override via raw BTU/BTD.
  • Pre-existing quirk (shared with H004): X509IssuerSerial reports the cert version rather than its serial number.

🤖 Generated with Claude Code

Uepsilon and others added 8 commits July 3, 2026 13:13
Introduce an opt-in `version:` client option (default :h004) so existing
2.5 users are unaffected. The crypto layer (A006/X002/E002) already matches
H005, so the changes are the XML envelope, OrderDetails/BTF structure,
response parsing and X.509 key management.

- Version descriptor table + client namespace/version readers
- Parameterized request envelope and response/client XPaths by namespace
- Version-branched OrderDetails: H005 AdminOrderType + BTF Service, empty
  SignatureFlag (with requestEDS), StandardOrderParams for admin downloads
- New BTU/BTD orders + Epics::BTF value object + BtfMapping (German starter
  set); common convenience methods route to BTU/BTD under H005
- Mandatory H005 upload DataDigest (A006)
- H005 key management: self-signed X.509 cert generation, INI/HIA/HPB send
  certs only (S002 namespace, no RSAKeyValue)
- Bundled official H005 XSD set; matcher is version-aware and the suite
  XSD-validates every H005 request plus the INI S002 payload
- 225 examples, 0 failures (all original H004 specs unchanged)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The H005 HPB response (HPBResponseOrderDataType) transmits the bank's
authentication and encryption keys only as X.509 certificates, with no
PubKeyValue/RSAKeyValue. The existing parser found nothing on H005, so
initialization could not complete.

- HPB branches on version; H004 modulus/exponent path preserved (refactored
  into rsa_from_modulus_exponent)
- hpb_h005 extracts the public key from each PubKeyInfo's X509Certificate,
  keyed by the version element (X002/E002), with an RSAKeyValue fallback
- Spec: crafted H005 HPBResponseOrderData with self-signed bank certs proves
  bank_x/bank_e are imported correctly

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
H005 replaced the flat OrderTypes list with BTF Service structures, so the
old //OrderTypes parsing returned nothing on H005.

- HAA (H005): parse //Service into Epics::BTF objects
- HTD (H005): read OrderInfo entries — order_types now exposes the distinct
  AdminOrderType values, plus a new #services accessor for the BTF services;
  name/iban/bic XPaths carry over unchanged
- service_from_node helper parses a <Service> element into an Epics::BTF
- Specs: crafted H005 HAA/HTD response order data proves parsing

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Self-signed H005 certificates were memoized per client instance only, so
every process restart generated a new certificate (fresh not_before). The
certificate submitted via INI/HIA and the fingerprint printed on the INI
letter could then diverge between runs, and the bank would reject the
subscriber verification.

Certificates now live in the encrypted keys blob under a ".crt" suffix
("A006.crt", ...): dump_keys serializes them, extract_keys restores them,
and self_signed_certificate reuses the persisted one. Existing key files
without .crt entries load unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
hpb_h005 derived the key suffix (X002/E002) from the PubKeyInfo's last
child element. The schema allows arbitrary foreign-namespace elements
after AuthenticationVersion/EncryptionVersion, so a bank appending one
would have made the parser read the wrong content as the key type.

Look up AuthenticationVersion/EncryptionVersion by name instead; the HPB
spec fixture now carries a trailing wildcard element to pin this down.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
If a PubKeyInfo contained neither an X509Certificate nor an RSAKeyValue,
bank_key_from_info died with a bare NoMethodError on nil. Raise a message
naming the offending element instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
x_509_certificate_hash only read externally supplied certificate content,
so an H005 client with generated self-signed certificates rendered the
plain key letter — without the certificate fingerprints the bank needs
for subscriber verification.

Route the hash through x_509_certificate (which covers self-signed certs)
and let the template print the PEM via the parsed certificate instead of
the raw content option. Externally supplied certificates render as before.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Uepsilon
Uepsilon marked this pull request as draft July 3, 2026 12:07
Uepsilon and others added 4 commits July 7, 2026 14:00
The H005 convenience methods (CCT/CCS/CDD/CDB, STA/VMK/C52/C53/C54)
relied on BtfMapping's hardcoded German starter-set defaults, so a bank
expecting a different message version, scope, or service option forced
callers down to the raw BTU/BTD API.

Thread keyword overrides through the convenience methods into
BtfMapping, merging them onto the mapped default (nil values ignored).
Renamed the BTF version field msg_version -> msg_name_version to match
the naming in railslove/epics PR railslove#154, easing a future switch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ests

Only ~10 classic order codes have an H005 branch. Any other business
order (XE2, AZV, CIP, Z52-54, FDL, ...) fell through to the classic path,
and because build_h005_order_details derives AdminOrderType from the
order_type, it emitted e.g. <AdminOrderType>XE2</AdminOrderType> with
StandardOrderParams — an order the bank rejects, with no hint why.

Add a central guard: business order codes reaching the H005 order-details
builder now raise Epics::VersionSupportError pointing at the raw BTU/BTD
API and BtfMapping. Administrative order types (HPB/HTD/HAA/HKD/HPD/HAC/
PTK/INI/HIA) and the BTU/BTD transports are whitelisted. H004 is
unaffected (the H005 builder only runs under an H005 client).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Extend BtfMapping and wire the H005 branch into more convenience methods
so they route to BTU/BTD instead of raising VersionSupportError. Service
tuples follow railslove/epics PR railslove#154's v3 factory:

  uploads:   AZV (XCT/dtazv), C2S/CDS (SDD/BIL), CIP (SCI), XE2 (MCT), XE3 (SDD)
  downloads: Z52/Z53/Z54, Z01, BKA, C5N, CDZ, CRZ (EOP/STM/REP/PSR camt/pain)

Message versions are only pinned where the DE default is well-known;
elsewhere <MsgName> carries no version so the bank applies its own, and
callers can override per call. Order codes with no H005 form (CD1, FUL,
WSS, XCT, XDS) remain unmapped and are rejected by the guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The signature version 'A006' was duplicated across the INI order data,
the H005 DataDigest, the user-signature block, the key accessor, setup,
and the cert-type map. Extract Epics::SIGNATURE_VERSION and document the
gem's deliberate A006-only design (RSASSA-PSS; X002 auth stays PKCS#1
v1.5 on its own path, legacy A005 is unsupported).

Move the Epics module constants above the epics/* requires so
load-time references (e.g. KEY_FOR_CERT_TYPE) resolve.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant