Skip to content

Shorter topoh callid - ff1-alnum62 - #4229

Open
digipigeon wants to merge 2 commits into
OpenSIPS:masterfrom
connexcs:shorter-topoh-callid
Open

Shorter topoh callid - ff1-alnum62#4229
digipigeon wants to merge 2 commits into
OpenSIPS:masterfrom
connexcs:shorter-topoh-callid

Conversation

@digipigeon

Copy link
Copy Markdown

Summary

This PR adds an optional ff1-alnum62 Call-ID encoding scheme to the topology_hiding module.

The new scheme reduces the size of topology-hiding Call-IDs compared with the existing XOR/word64 encoding, particularly when Call-IDs are processed by multiple topology-hiding hops. The historical xor-word64 scheme remains the default for backward compatibility.

Details

When topology hiding is enabled with the C flag, OpenSIPS replaces the original Call-ID before sending the dialog toward the callee. The existing implementation applies repeating-key XOR followed by word64 encoding.

Word64 expands the encoded data by approximately 33%. This can produce unnecessarily long Call-IDs, especially when several topology-hiding systems successively encode an already encoded Call-ID.

For example, using the same two-character prefix for both methods:

Input length xor-word64 length ff1-alnum62 length
4 10 7
16 26 19
40 58 43
80 110 83
160 218 163

The new implementation also avoids modifying the original Call-ID buffer while encoding it.

This is an optional new feature rather than a change to the default wire format.

Solution

The PR introduces the th_callid_encode_scheme module parameter with two supported values:

  • xor-word64: the existing encoding and the default.
  • ff1-alnum62: the new AES-256 FF1 format-preserving encoding.

The new format is:

th_callid_prefix || marker || payload

The marker identifies how the input was represented:

  • A: the original Call-ID was already alphanumeric and was encrypted directly in radix 62.
  • B: an RFC 3261-compliant Call-ID containing punctuation or @ was ranked in the complete SIP Call-ID domain, converted to radix 62 and encrypted.
  • C: the input could not use the FF1 domain and was encoded using the historical XOR/word64 fallback.

RFC 3261 defines a Call-ID as:

word [ "@" word ]

The implementation supports the complete RFC word alphabet and preserves the position of the optional @ through reversible domain ranking.

FF1 uses:

  • AES-256;
  • ten FF1 rounds;
  • radix 62 ciphertext;
  • an empty tweak;
  • an HKDF-SHA-256-derived key;
  • a minimum FF1 domain size of one million.

The configured th_callid_passwd is used as HKDF input with a fixed, versioned and module-specific salt and context. The default password is rejected for ff1-alnum62, and a high-entropy password of at least 32 characters is recommended.

Additional robustness measures include:

  • separate limits for plaintext and structured ciphertext;
  • support for structured plaintext up to 4096 characters and the corresponding radix-62 payload of up to 4411 characters;
  • early rejection of oversized or malformed ciphertext;
  • validation of legacy-decoded plaintext to prevent control characters from being inserted into reconstructed SIP headers;
  • rejection of unknown markers and malformed word64 padding;
  • optimized structured-length recovery using binary search;
  • secure cleanup of derived key material.

The implementation includes tests for:

  • an official NIST FF1 vector;
  • alphanumeric Call-IDs;
  • every RFC-compliant Call-ID character;
  • the optional @ separator;
  • lengths from 1 through 256;
  • boundary lengths of 3804, 3805 and 4096;
  • malformed and oversized ciphertext;
  • non-compliant visible characters through the legacy fallback;
  • rejection of CR/LF and other control characters;
  • ten successive topology-hiding encoding and decoding layers;
  • legacy wire-format compatibility;
  • raw SIP request and response processing.

SIPp end-to-end tests were also performed using complete:

INVITE -> 200 OK -> ACK -> BYE -> 200 OK

dialogs. Both the old and new schemes completed all tested dialogs without SIPp errors. Additional full-dialog tests covered RFC punctuation/@ marker B and non-compliant fallback marker C.

Compatibility

The default remains xor-word64, so existing configurations retain their current wire format and behavior.

To enable the new scheme:

modparam("topology_hiding", "th_callid_encode_scheme", "ff1-alnum62")
modparam("topology_hiding", "th_callid_prefix", "TH1")
modparam("topology_hiding", "th_callid_passwd",
         "replace-with-at-least-32-random-characters")

Compatibility considerations:

  • ff1-alnum62 requires an alphanumeric, non-empty th_callid_prefix. The existing default prefix contains _, so deployments enabling FF1 must configure a new prefix.
  • Scheme, password and prefix are part of the wire format. Active dialogs must be drained before changing them.
  • Nodes handling the same encoded dialogs must use matching settings.
  • The format provides confidentiality but not integrity. A wrong password can potentially decode ciphertext into plausible but incorrect text.
  • Visible non-compliant Call-ID characters are handled through marker C and the legacy fallback. Control characters are rejected.
  • When th_callid_loop_protection is enabled, its internal separator is outside the RFC Call-ID alphabet. The combined Call-ID and loop tag therefore use marker C. Loop protection remains functional but does not receive the FF1 length reduction.
  • The topology-hiding module now links against OpenSSL libcrypto, even when the default legacy scheme is selected.
  • No automatic key rotation or previous-key decoding is included. Active dialogs must be drained before rotating the Call-ID password.
  • The historical xor-word64 output remains byte-for-byte compatible for compliant existing Call-IDs.

Closing issues

No linked issue.

This commit introduces a new codec for encoding and decoding Call-IDs using the FF1 algorithm, which preserves radix and enhances security. The following changes were made:

- Implemented `topo_hiding_codec.c` and `topo_hiding_codec.h` to define the FF1 encoding scheme and related functions.
- Updated `topo_hiding_logic.c` to utilize the new codec for encoding and decoding Call-IDs, replacing the previous XOR-based method.
- Modified `topology_hiding.c` to include configuration parameters for the new encoding scheme and initialize the codec during module initialization.
- Added unit tests for the new encoding and decoding functions to ensure correctness.

This enhancement allows for more secure handling of Call-IDs in the topology hiding module, supporting both legacy and new encoding schemes.
…module

- Update bounds for FF1 processing and structured payloads in documentation.
- Introduce safe legacy plaintext checks to prevent malformed SIP headers.
- Adjust maximum lengths for plaintext and structured payloads in codec implementation.
- Add warning for loop protection's impact on Call-ID encoding.
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