Skip to content

Fix CCM counter carry and AAD encoding (N-147/N-148) - #169

Merged
tinic merged 3 commits into
mainfrom
fix/n147-ccm
Oct 3, 2026
Merged

tinic merged 3 commits into
mainfrom
fix/n147-ccm

Conversation

@tinic

@tinic tinic commented Oct 3, 2026

Copy link
Copy Markdown
Owner

Pins independently reviewed NetX bb340972: carry across the full L-byte CCM counter, reset all counter bytes for A(0), omit empty AAD blocks and correctly encode large UINT32 AAD. N-147 affects supported larger TLS CCM records; N-148 is latent for current TLS AAD sizes.

Exact combined head 0463f3a retains current-main RSA and X509 fixes. Independent primary and peer source review complete. Maintained OpenSSL/Python AESCCM reference vectors cover 100 cases and 1300 checks: counter boundaries, tags 8/16, nonces 7/12/13, empty/short/large AAD, whole-record and block-aligned split UPDATEs. Old vendor fails 526; counter-only fails 220 AAD checks; combined passes all 1300. Host and ASan/UBSan logs inspected, no diagnostic reports; pinned 16.2.3 m68000/m68020 production compiles inspected. Compiler intentionally reports 16.2.0b.

Registered one maintained host gate and updated census; normal required CI still gates parent integration. No full-emulator/hardware run, attack reproduction, toolchain repin or unaligned streaming redesign. Clean temporary branches/build outputs after merge.

tinic and others added 3 commits October 2, 2026 18:37
… (N-147, N-148)

tests/ccm/test_ccm_contract checks the vendored AES-CCM through both TLS
method objects (crypto_method_aes_ccm_16 and _8) against known answers
from Python cryptography's AESCCM: payloads 0, 1, 16, 4080, 4096, 4112
and 16384 bytes, AAD 0, 5 and 13, and AAD 65279, 65280 and 70000 over
payloads 0, 16 and 4096, tags 16 and 8, 60 cases.  Each case runs the
record layer's INITIALIZE/UPDATE/CALCULATE path both ways, the one-shot
ENCRYPT/DECRYPT, and a flipped tag bit that must be refused.  Output is
key=value, exit status is the verdict.

Vectors: tests/ccm/gen_ccm_vectors.py (sha256 0f10410c4347fe45...),
Python 3.13.5, cryptography 43.0.0, OpenSSL 3.5.7, run on playhouse3:
  python3 tests/ccm/gen_ccm_vectors.py > tests/ccm/ccm_vectors.h
Regenerates byte-identical.

Not registered: needs add_subdirectory(ccm) after add_subdirectory(x509)
in tests/CMakeLists.txt and HOST_TESTS_EXPECTED + 1 in tools/ci.sh.

third_party/netxduo -> bb340972 (tinic/netxduo fix/n147-ccm-counter):
REVIEW-ONLY TOPIC PIN, not fork master.  Two commits on fork master
4bf8d7e1: 261db214 carries the CCM counter over all L octets (N-147),
bb340972 encodes l(a) per RFC 3610 2.2, no AAD block at 0 and the
6-octet form from 0xFF00 (N-148).

x86_64 Linux, ci-warnings host build, test_ccm_contract:
  4bf8d7e1  failures=228/660  every payload >= 4096 fails, first bad
            ciphertext block 255 (the 256th); AAD 0, 65280, 70000 fail
  261db214  failures=104/660  only AAD 0/65280/70000 cases fail
  bb340972  failures=0/660
ASan+UBSan build (AMINETXDUO_SANITIZE=ON): 228 at 4bf8d7e1, 0 at
bb340972, no sanitizer reports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
third_party/netxduo stays at the review-only topic pin bb340972, which
contains main's pin 4bf8d7e1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Registers tests/ccm (add_subdirectory(ccm) after x509) and raises
HOST_TESTS_EXPECTED 547 -> 548.  ctest -N on Linux x86_64 counts 548 for
both the host and the sanitize configure.  Darwin is derived, not run:
548 - 30 - 1 = 517 on arm64, 548 - 1 = 547 on x86_64; the comment's
513/543 were stale from an earlier base.

The fixture gains:
- a split control on the record path, both ways: UPDATE 255 blocks
  (4080 bytes), then the rest, so the second UPDATE starts on counter
  256 (every payload over 4080);
- nonce 7 (L = 8) and 13 (L = 2) groups, payloads 0, 16, 4080, 4096,
  4112, AAD 0 and 13, tags 16 and 8, with their own reference
  ciphertexts from the same generator;
- a note that the whole-record UPDATE is one shape and real callers may
  split; block-unaligned streaming is out of scope.
100 cases, 1300 checks.

Vectors: tests/ccm/gen_ccm_vectors.py (sha256 c7330ce08e738940...),
Python 3.13.5, cryptography 43.0.0, OpenSSL 3.5.7, on playhouse3:
  python3 tests/ccm/gen_ccm_vectors.py > tests/ccm/ccm_vectors.h
Regenerates byte-identical.

x86_64 Linux, test_ccm_contract, ci-warnings host build:
  4bf8d7e1  failures=526/1300  every payload >= 4096 at every nonce
            and on all three paths (record, split255, oneshot), first
            bad ciphertext block 255; AAD 0/65280/70000 fail
  261db214  failures=220/1300  AAD 0/65280/70000 only, no ciphertext
  bb340972  failures=0/1300
ASan+UBSan: 526 at 4bf8d7e1, 0 at bb340972, no sanitizer reports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tinic
tinic merged commit 988a24f into main Oct 3, 2026
42 of 43 checks passed
@tinic
tinic deleted the fix/n147-ccm branch October 3, 2026 02:54
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