Skip to content

fix: HNVSK carries the signature's security profile version (PIN:2 for two-step) - #38

Merged
robocode13 merged 1 commit into
robocode13:mainfrom
sebsebgo:fix/hnvsk-security-profile-version
Sep 13, 2026
Merged

robocode13 merged 1 commit into
robocode13:mainfrom
sebsebgo:fix/hnvsk-security-profile-version

Conversation

@sebsebgo

@sebsebgo sebsebgo commented Sep 9, 2026

Copy link
Copy Markdown

The problem

CustomerMessage.encode() hardcodes the encryption header to PIN:1, while sign() correctly puts PIN:2 into the signature header for a two-step TAN method. Consorsbank (BLZ 76030080, brokerage-hbci.consorsbank.de) rejects every message built that way:

9010  Ungültiger Signaturaufbau: Fehler im Segmentaufbau
9800  Der Dialog wurde abgebrochen

so a two-step dialog can never be opened there; only the one-step, method-less sync succeeds.

Why the bank is right to complain

  • hbci4java derives both SigHead and CryptHead from one getProfileVersion() (1 for one-step, 2 otherwise). On 2019-09-17 its author switched to "always send 1" (commit 1982a78) — Consorsbank immediately broke with this exact 9010 and he reverted the same day (9813da9, "Sollte sich Consors tatsächlich an der Profil-Version stören?").
  • python-fints has the mirror-image bug (HNSHK stuck at version 1, HNVSK escalated to 2) and fails with the same code pair: Consorsbank: Error during dialog initialization, could not fetch BPD. raphaelm/python-fints#99.
  • The FinTS 3.0 Security spec defines the security profile per dialog, not per segment; the two headers are meant to agree.

The fix

HNVSK takes its secVersion from the signature it wraps — one line. Two tests pin the behaviour (two-step → PIN:2 in both headers, one-step → PIN:1 in both).

Measured

Against the live bank with this change and nothing else: dialog init with method 901 accepted (0030 Auftrag empfangen - Sicherheitsfreigabe erforderlich + HITAN reference), TAN step completes (Angemeldet, UPD received), HKSAL and HKKAZ follow with 3076 Keine starke Authentifizierung erforderlich. I have not re-tested other banks; every bank that accepted PIN:1 before did so while the signature already said PIN:2, so the risk is a bank that requires the headers to disagree, which none of the reference implementations do.

Related: #36 fixes the second thing Consorsbank rejects (HKKAZ v7 without the IBAN); I'll add the measurements there.

🤖 Generated with Claude Code

https://claude.ai/code/session_0113JyWvWThppT9YzAHQG6RA

…r two-step)

The encryption header was hardcoded to `PIN:1` while the signature header
correctly sends `PIN:2` for a two-step TAN method. Consorsbank (BLZ 76030080)
rejects that combination with `9010 Ungültiger Signaturaufbau: Fehler im
Segmentaufbau` + `9800 Der Dialog wurde abgebrochen`, so no two-step dialog
could ever be opened there.

Evidence that the bank checks both headers: hbci4java commit 1982a78
(2019-09-17, "always send profile version 1") broke Consorsbank with this
exact error and was reverted the same day in 9813da9; hbci4java has derived
both headers from one getProfileVersion() ever since. python-fints has the
mirror-image bug (HNSHK stuck at 1) and fails identically
(raphaelm/python-fints#99).

Measured against the live bank with this change: the dialog init is accepted
(`0030 Auftrag empfangen - Sicherheitsfreigabe erforderlich`), the TAN step
completes (`Angemeldet`), and HKSAL/HKKAZ follow with `3076`. DKB, ING and
Postbank were not re-tested; the specification (FinTS 3.0 Security, PIN/TAN)
defines the profile version per dialog, not per segment, so sending the same
value in both headers is the conforming form.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0113JyWvWThppT9YzAHQG6RA
@robocode13
robocode13 force-pushed the fix/hnvsk-security-profile-version branch from c4b581c to 05224cc Compare September 13, 2026 09:25
@robocode13

Copy link
Copy Markdown
Owner

Thank you for the contribution. I tested it successfully with four banks (DKB, ING, Renault, Baader)

@robocode13
robocode13 merged commit c705819 into robocode13:main Sep 13, 2026
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.

2 participants