# VERDICT — DF-3569 camellia_set_key() key-length validation gap

**Status: reproduced (harness, production-kernel semantics) — impact: none
today (latent; zero in-tree consumers). Confidence: certain.**

## The defect

`camellia_set_key()` (`sys/crypto/camellia/camellia-api.c:36-42`) is the API
boundary of the camellia wrapper and the natural place a key length must be
validated. It does nothing of the sort:

```c
void
camellia_set_key(camellia_ctx *ctx, const u_char *key, int bits)
{
    Camellia_Ekeygen(bits, key, ctx->subkey);   /* camellia.c:1253 KASSERT is
                                                   the ONLY guard          */
    ctx->bits = bits;                            /* stored unconditionally  */
}
```

`Camellia_Ekeygen()` (`sys/crypto/camellia/camellia.c:1249-1268`) guards the
length with `KASSERT(keyBitLength == 128 || == 192 || == 256)` at :1253-1254
and then `switch`es with a bare `default: break;`. On a production kernel
(`KASSERT` compiled out — no `INVARIANTS`), any other length:

1. leaves `ctx->subkey[68]` **untouched** — the schedule for that key is never
   generated;
2. still gets recorded in `ctx->bits` (`camellia-api.c:41`);
3. makes later `camellia_encrypt()`/`camellia_decrypt()`
   (`camellia-api.c:44-56`) route into
   `Camellia_EncryptBlock`/`Camellia_DecryptBlock`'s own
   `default: break;` (camellia.c:1283-1287, 1315-1319), which loads the 16-byte
   block into `tmp[]` and stores it back **without executing any round** —
   the "cipher" is the identity function.

## Why this matters / why only Info

Cryptographic consequence, not memory corruption: unlike the rijndael twin
(DF-3568, where an invalid length overreads the key buffer and a Nr=0
schedule walks wild), camellia's `default:` paths read neither the key
buffer nor the schedule. The failure mode is **silent plaintext pass-through
in place of encryption** — catastrophic if a future consumer forwards a
length from an untrusted source, invisible to that consumer because the API
returns `void`.

Reachability on this tree: **none**. `rg` over all of `sys/` finds zero
callers of `camellia_set_key`/`camellia_encrypt`/`camellia_decrypt` and zero
includers of `crypto/camellia/camellia.h` outside the directory; the only
references are build registrations (`sys/conf/files:2258-2259`,
`sys/crypto/Makefile:19-20`). The code ships as dead code in `option crypto`
kernels and in the `crypto.ko` primitive bundle (anchored by the dummy
`sys/crypto/crypto.c` module, audited clean in the same batch). Filed Info
(latent hardening) per the batch precedent (DF-3560/DF-3568).

## Verification (guest, harness = real kernel sources in userland)

`camellia.c:40-43` maps `KASSERT`→`assert()` in userland, so compiling the
actual `camellia-api.c` + `camellia.c` with `-DNDEBUG` reproduces production
kernel semantics exactly; without the flag it reproduces INVARIANTS
semantics. Guest sources at `/usr/src` are cksum-identical to the audited
tree (env.txt).

Baseline (run.log):

- `guard_prod kat` — RFC 3713 Appendix A 128/192/256 known-answer vectors all
  PASS, decrypt roundtrip OK, and a canary after `subkey[68]` proves the
  schedule writes stay in bounds for every valid size (ctx-layout interplay
  checked clean).
- `guard_prod guard` — for bits ∈ {64, 0, −1, 129}: no trap;
  `ctx->bits` set to the invalid value; `0xA5A5A5A5` schedule sentinel
  intact ("never generated"); `ciphertext == plaintext` byte-for-byte;
  `BUG-CONFIRMED`, **exit 42**.
- `guard_dbg guard` — `Assertion failed: (keyBitLength == 128 || ...) ...
  camellia.c, line 1254`, SIGABRT — proving the only guard is debug-only.

Fixed (fixval.log): `fix.diff` applied to a guest copy of the pristine
sources (patch: both hunks OK) and rebuilt:

- `guard_fix kat` — still `RESULT-PASS: 0 failures` (valid sizes unaffected);
- `guard_fix guard` — all four invalid lengths REJECTED before touching key
  material (`ctx->bits` keeps its marker, schedule sentinel intact) and
  `camellia_encrypt` refuses, leaving dst untouched;
  `BUG-NOT-PRESENT`, **exit 0**.

Harness-level validation only (no kernel build) — no in-tree caller can
deliver an invalid length, so a kernel build would prove nothing the harness
does not; identical rationale to the accepted DF-3568 validation.

## Fix

`fix.diff` (validated above): `camellia_set_key()` returns `int`
(-1 before touching key material or ctx for lengths outside
{128,192,256}; 0 on success — statement-style calls remain source-compatible,
and there are no in-tree consumers), plus encrypt/decrypt guards that refuse
schedules with an invalid `ctx->bits`, leaving dst untouched (defense in
depth for callers that ignore the return and use a stale ctx).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
