Repository navigation
Conversation
At provisioning time (clevis encrypt tang), call GET /version on the Tang server. When features.tang_pub is true, create a new-format binding that stores only the Tang URL and key identifier — the full advertisement is not persisted in the JWE header. When /version returns 404 or tang_pub is absent, fall back to current behavior. At recovery time (clevis decrypt tang), check the binding format: new-format bindings extract tang_pub from the POST /rec/$kid response for ECMR recovery; legacy bindings use the stored advertisement unchanged. If a new-format recovery fails because tang_pub is missing from the server response, fail clearly without silent fallback. clevis luks regen automatically migrates eligible legacy bindings to the new format by re-querying /version during re-encryption. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Introduce hybrid PQC support to the Tang pin. When a Tang server advertises an ML-KEM-768 key (kty: AKP) and reports hybrid_recovery support via /version, clevis-encrypt-tang performs dual key agreement: ECDH with the ECMR key and KEM encapsulation with the ML-KEM key. Both shared secrets are combined through HKDF-SHA-256 (RFC 5869) with domain separation (label NBDE-HYBRID-v1, version, suite, and both key thumbprints bound into the info parameter) to derive the content encryption key. All hybrid cryptographic operations (ECDH, KEM encapsulation, HKDF derivation) are performed inline using jose CLI and openssl kdf commands. On the decrypt side, ECMR recovery via /rec is shared with the classical path, followed by KEM recovery via /rec-kem and HKDF derivation to reconstruct the content encryption key. The JWE uses alg:dir with A256GCM and stores the client EC public key as epk, the KEM ciphertext as clevis.tang.kem_ct, and the KEM key thumbprint as kem_kid in the protected header. Both encrypt and decrypt paths gracefully fall back to classical ECDH-ES when the server lacks PQC support. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Protect enc_kem_key during hybrid recovery by implementing the
bidirectional ML-KEM envelope protocol specified for the unsecure
channel, replacing the plaintext KEM shared secret exchange.
Encrypt side (clevis-encrypt-tang):
- Compute ek_digest = SHA_256(enc_kem_key) at bind time for anti-oracle
verification on the Tang side
- Store tang_kem_pub and ek_digest in the JWE header
- Rename hybrid_cek to enc_key to match specification terminology
Decrypt side (clevis-decrypt-tang):
- Separate recovery into /rec (ECMR, inherently blinding-protected) and
/rec-kem (KEM, bidirectional envelope-protected) as two independent
calls
- Generate ephemeral KEM keypair (clevis_kem_priv, clevis_kem_pub)
- Establish forward transport channel via Encapsulate(tang_kem_pub)
- Encrypt {kem_ct, clevis_kem_pub, ek_digest} under forward key
- POST encrypted envelope to /rec-kem
- Decapsulate return channel and decrypt enc_kem_key from Tang response
- Derive enc_key = PRF(enc_ec_key, enc_kem_key) via HKDF
- Discard all ephemeral and transport material after use
- Extract helpers: derive_enc_key(), ecmr_unblind(), validate_tang_ec_pub(),
ecmr_recover()
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Rename variables and JSON field names to match the secure transport protocol specification consistently: - kem_ct → clevis_kem_ct (JWE header and inner payload field) - kem_ss_k/kem_ss_jwk → enc_key_k/enc_key_jwk (shared secret from KEM) - clevis_kem_key → clevis_kem_priv (ephemeral KEM private key) - kem_k → enc_key_k (recovered KEM shared secret) - enc_kem_key_json → enc_key_json (decrypted key from Tang) - encrypted_blob → clevis_encrypted_blob (request field) - transport_ct → clevis_transport_ct (request field) - encrypted_key → tang_encrypted_key (response field) - transport_ct → tang_transport_ct (response field) Fix ek_digest computation to use JWK Thumbprint (jose jwk thp -a S256) matching Tang's jose_jwk_thp_buf(), instead of raw SHA-256 of key bytes. Fix ek_digest being unset before it was stored in the JWE header. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Add a new C++ pin (tang-pqc) implementing hybrid post-quantum cryptography combining classical ECMR with ML-KEM-768 (FIPS 203). The pin provides clevis-encrypt-tang-pqc and clevis-decrypt-tang-pqc binaries with the following architecture: - jose_types.h: RAII wrappers (JsonPtr, CStringPtr, BufferPtr) for jose/jansson resources using C++ smart pointers - jose_wrapper: Type-safe C++ interface over jose C API (key generation, ECDH, KEM encapsulation, JWE, JWS, base64url) - key_deriver: HKDF-SHA256 key derivation with domain separation (label "NBDE-HYBRID-v1", suite "ECMR+ML-KEM-768") - tang_client: HTTP client using libcurl with TLS/mTLS support, handles /adv, /adv-kem, /rec, /rec-kem endpoints - ecmr_ops: ECMR blinding and unblinding operations using jose's three ECMR modes (scalar mult, point addition, point subtraction) - encrypt_main: Full hybrid encryption flow producing JWE with alg:dir and pin:tang-pqc, with JWS verification of both /adv and /adv-kem responses - decrypt_main: Full hybrid decryption with secure KEM transport channel for recovery Unit tests cover all crypto components without requiring a Tang server: jose_wrapper (key gen, ECDH, KEM round-trip, JWE, base64, thumbprints), key_deriver (determinism, domain separation, real-key integration), and ecmr_ops (blind/unblind recovery matches ECDH across P-256/P-384/P-521, ephemeral independence). The pin is gated behind a meson feature option (tang-pqc, default auto) so it is only built when dependencies (libcrypto, libcurl, jose, jansson) are available. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Move all hybrid ECC+KEM post-quantum encryption logic exclusively to the tang-pqc pin, keeping the classical tang scripts focused on standard ECDH-ES. The tang_pub feature support is retained, allowing the server to provide its exchange key in the /rec response instead of storing the advertisement in the JWE header. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Read interactive trust confirmation from /dev/tty instead of stdin, matching the classical tang pin behavior. When clevis-luks-bind pipes the LUKS key through stdin, the prompt was consuming key data instead of reading user input from the terminal. Also add tang-pqc pin documentation to README.md covering usage, build dependencies (jose with KEM, OpenSSL 3.5+), meson options, and Tang server requirements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Add dracut module clevis-pin-tang-pqc to include the hybrid PQC binaries in the initramfs for early boot LUKS unlocking. The module depends on clevis and network, sets rd.neednet=1 when tang-pqc bindings are detected, and installs clevis-encrypt-tang-pqc, clevis-decrypt-tang-pqc, curl and openssl. Also add conditional copy of tang-pqc binaries to the initramfs-tools hook for Debian-based systems. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Replace extracted functions (ecmr_unblind, validate_tang_ec_pub, ecmr_recover) with inline code matching the original tang_pub patch. No functional change — same tang_pub support, simpler structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
In the end, it has been decided to move all the PQC Hybrid logic to a brand new pin that will act as the main entrypoint for Hybrid PQC encryption/decryption. This change removes previous leftover when the Hybrid PQC was implemented inside clevis-encrypt-tang and clevis-decrypt-tang Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Add tang-pqc case to clevis_luks_process_sss_pin() so that clevis luks list and clevis luks regen correctly handle SSS bindings that include tang-pqc as a child pin. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
When the tang server supports tang_pub, clevis-encrypt-tang skips storing adv in the JWE header. This broke clevis-luks-report (which expected adv to always be present) and the luksmeta corruption test (which relied on a large adv causing bind failure). - clevis-luks-report: return success when adv is absent from metadata instead of failing, since rotation detection is not possible without stored keys but decryption still works via tang_pub - clevis-luks-report: add tang-pqc to the pin case statement - bind-luks1-avoid-luksmeta-corruption: provide adv as a file to force it into the JWE header, preserving the original test intent Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Allow offline binding by providing both adv and adv_kem together in the configuration. When both are present, the encrypt skips fetching from the network and assumes tang_pub is enabled. Providing only one of adv/adv_kem without the other is rejected with a clear error. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Add shell-based integration tests for the tang-pqc pin, following the same patterns as the existing tang tests: - pin-tang-pqc: basic encrypt/decrypt round-trip, JWE header validation, server-down failure - pin-tang-pqc-version: /version endpoint validation (tang_pub, hybrid_recovery), /adv-kem endpoint, AKP key presence - pin-tang-pqc-offline: offline binding with file paths and inline JSON, validates that providing adv-only or adv_kem-only fails - pin-tang-pqc-sss: SSS combination with two tang-pqc pins, mixed tang-pqc + classic tang, one-server-down resilience - pin-tang-pqc-errors: missing url, unreachable server, wrong thumbprint, tampered JWE Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
When adv is not stored in the JWE header (tang_pub mode), the report now extracts the kid from the protected header and checks if it is still present in the server's current advertisement. If the kid is missing from the current adv, the key was rotated and the report flags it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
sarroutbi
force-pushed
the
tang-kem-pub
branch
2 times, most recently
from
October 6, 2026 08:41
edfe9d1 to
c11ca47
Compare
Add a cc.links() check for jose_jwk_kem_enc to detect whether the installed jose library supports ML-KEM operations. When the API is absent, the tang-pqc pin is disabled with a clear warning instead of failing at compile time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
sarroutbi
force-pushed
the
tang-kem-pub
branch
from
October 6, 2026 08:46
c11ca47 to
fb1070c
Compare
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
sarroutbi
force-pushed
the
tang-kem-pub
branch
from
October 6, 2026 08:57
3013427 to
a7ccb07
Compare
Remove C++ from the project() declaration so it is no longer unconditionally required. The C++ compiler is only added via add_languages() when jose has ML-KEM KEM API support, since the tang-pqc pin is the sole consumer of C++ in the project. This avoids requiring a C++ toolchain on systems where the pin will not be compiled. The KEM API link check is moved from tang-pqc/meson.build to the root meson.build so that add_project_arguments() for C++ can be called before any build targets are defined. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
sarroutbi
force-pushed
the
tang-kem-pub
branch
from
October 6, 2026 09:24
2f746ad to
13d8d4a
Compare
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Address six security findings from static review of the tang-pqc pin: - Add cleanseJsonSecrets() to zero sensitive strings inside jansson objects (private keys, shared secrets, derived CEKs) before they are freed by json_decref, preventing heap residue recovery via cold-boot or memory forensics attacks. - Replace string concatenation with json_pack() for inner payload construction in secureTransportRecover(), eliminating a JSON injection vector through unverified JWE header values parsed before AEAD authentication. - Add CURLOPT_CONNECTTIMEOUT (10s) and CURLOPT_TIMEOUT (30s) to prevent indefinite hangs during early-boot NBDE unlock when the Tang server is unreachable or tarpitting. - RAII-wrap curl_slist via SlistPtr to prevent memory leak on exception paths in httpPost(), and add try/catch in writeCallback to avoid undefined behavior from C++ exceptions propagating through libcurl C frames. - Length-prefix kid and kemKid in HKDF info parameter to eliminate ambiguous concatenation that could allow cross-binding key collisions per NIST SP 800-56C. Wire-format change, safe pre-GA. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
sarroutbi
force-pushed
the
tang-kem-pub
branch
from
October 9, 2026 13:53
0f3053c to
1e5c5fa
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds a new tang-pqc pin implementing hybrid ECC+ML-KEM-768 post-quantum encryption for Tang-based NBDE (Network-Bound Disk Encryption). This protects LUKS bindings against future quantum attacks while retaining classical ECMR security guarantees through a dual key exchange design.
LUKS infrastructure integration
Build system
Test suite
Documentation