Repository navigation
Conversation
Embed the server's ECMR public key as a `tang_pub` field in the recovery response so that clients can obtain it at recovery time instead of persisting it on disk. The public key is a deep copy with private material stripped via jose_jwk_pub(), ensuring no secret data leaks. The field is additive: old clients ignore the unknown JSON field, so existing Clevis bindings and recovery flows are unaffected. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Embed the server's ECMR public key as a `tang_pub` field in the POST /rec/$kid response so that clients can obtain it at recovery time instead of persisting it on disk. Private material is stripped via jose_jwk_pub() before inclusion. Add a Tang-Capabilities: tang_pub header to the GET /adv response so clients can detect server support before creating a binding. Both changes are additive: old clients ignore the unknown JSON field and HTTP header, so existing bindings and recovery flows are unaffected. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Replace the Tang-Capabilities HTTP header with a dedicated
GET /version endpoint that returns structured JSON describing
server capabilities.
The response format:
{"features":{"tang_pub":true},"tang_version":"15"}
Clients calling /version on an old Tang server receive a 404,
which cleanly signals the server lacks capability discovery and
the client should fall back to legacy binding behavior.
The /version endpoint respects the -e (endpoint) option, so
/endpoint/version works consistently with /endpoint/adv and
/endpoint/rec.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Extend Tang with hybrid post-quantum cryptography capabilities: ML-KEM-768 key generation: - Generate an ML-KEM-768 (kty: AKP) key pair alongside the existing ES512 and ECMR keys, both in the C daemon (create_new_keys) and in the tangd-keygen shell script. - Key generation is optional: if jose does not support ML-KEM, the server logs a warning and continues operating with classical keys only. This preserves backward compatibility with older jose builds. PQC state tracking: - Add m_has_pqc field to tang_keys_info, set during key loading when an AKP-type key is found among regular (non-rotated) keys. - Expose PQC availability via the /version endpoint as the "hybrid_recovery" feature flag, allowing clients to detect server support before creating hybrid bindings. KEM decapsulation endpoint (POST /rec-kem/<thumbprint>): - Accept a JSON body with a "ct" field containing base64url-encoded ML-KEM ciphertext. - Look up the server ML-KEM private key by thumbprint, validate it is kty: AKP with deriveKey permission, and call jose_jwk_kem_dec to perform decapsulation. - Return the shared secret as an oct JWK, enabling the client to combine it with the ECDH shared secret for hybrid key derivation. - Support custom --endpoint prefix, consistent with existing routes. Test adjustment: - Relax test_create_new_keys assertion to m_keys_count >= 2, since ML-KEM generation may produce a third key when jose supports it. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Separate concerns between /rec (ECMR exchange) and /rec-kem (KEM recovery). The legacy plaintext path that returned shared secrets directly is removed — all KEM recovery now uses a bidirectional envelope where enc_kem_key is always encrypted in transit. Removed rec_kem_legacy() and the detection branch in rec_kem(). Removed all ECMR logic from rec_kem_secure() (EC key lookup, jose_jwk_exc exchange, transport_key/tang_ec_pub in response). Added JWE compact serialization helpers (jwe_from_compact, jwe_to_compact) and secure memory cleansing (secure_zero, str_cleanse) for intermediate secrets. Updated tests to exercise the full bidirectional envelope protocol: forward-channel encapsulation, encrypted inner payload, return-channel decapsulation, and shared secret verification. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
The client now includes an ek_digest (SHA-256 JWK thumbprint of the stored shared secret) in the encrypted inner payload. Tang verifies this digest against the decapsulated enc_kem_key before proceeding with the return channel. If verification fails, Tang returns 400 without encrypting or returning anything. This prevents an attacker who intercepts clevis_transport_ct from replaying a recomputed clevis_encrypted_blob to have Tang act as a decapsulation oracle. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Rename C variables and JSON wire-format fields to match the
hybrid KEM protocol specification consistently:
C variables:
kem_jwk → tang_kem_priv
transport_ct_str → clevis_transport_ct
fwd_ss → clevis_transport_key
encrypted_blob → clevis_encrypted_blob
kem_ct → clevis_kem_ct
enc_kem_key → enc_key
ret_ss → tang_transport_key
tang_ct → tang_transport_ct
jwe_compact → tang_encrypted_key
ek_json → enc_key_json
JSON fields (request):
encrypted_blob → clevis_encrypted_blob
transport_ct → clevis_transport_ct
JSON fields (inner payload):
kem_ct → clevis_kem_ct
JSON fields (response):
encrypted_key → tang_encrypted_key
transport_ct → tang_transport_ct
The ambiguous "transport_ct" field that appeared in both request
and response with different meanings is now disambiguated with
clevis_/tang_ prefixes.
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>
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #165 +/- ##
==========================================
+ Coverage 58.44% 62.56% +4.11%
==========================================
Files 4 5 +1
Lines 580 625 +45
Branches 147 156 +9
==========================================
+ Hits 339 391 +52
+ Misses 140 129 -11
- Partials 101 105 +4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
sarroutbi
force-pushed
the
tang-kem-pub
branch
from
October 5, 2026 16:15
5c05db2 to
6954665
Compare
Split all post-quantum cryptography code (adv_kem, rec_kem, KEM helpers) from tangd.c into pqc.c/pqc.h, with pqc_noop.c providing stubs when jose lacks KEM API support. This removes every #ifdef HAVE_PQC from keys.h, keys.c, and tangd.c — the meson build conditionally compiles the real or noop implementation based on the existing jose KEM probe. 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 5, 2026 16:21
6954665 to
f2fd2f7
Compare
Use a meson probe to detect explicit_bzero at configure time, falling back to memset_s (C11 Annex K) then memset with a compiler barrier. This avoids the volatile-loop pattern and leverages OS-provided secure wiping when available. Also sets *str = NULL after freeing in str_cleanse to prevent use-after-free. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
sarroutbi
marked this pull request as ready for review
October 7, 2026 10:42
jansson does not zero heap memory when freeing json_t string values. The "k" field of oct JWK objects containing KEM shared secrets (clevis_transport_key, enc_key, tang_transport_key) remained in freed heap pages after json_decref, recoverable via heap grooming, core dumps, or /proc/pid/mem reads. Add wipe_jwk_secret() to SECURE_WIPE the "k" field in-place before jansson frees the underlying buffer. Apply it to all three shared secrets in rec_kem_secure on the success path and to clevis_transport_key before its explicit json_decref. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
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.
For PQC to work appropriately, library requires usage of updated JOSE library. Changes (unmerged) available at:
latchset/jose#184
In case specific JOSE functions and algorithms are not available, Tang will work as previously, not including the files that are PQC specific
Add hybrid post-quantum cryptography (ML-KEM-768) support to Tang via a bidirectional KEM envelope protocol, maintaining full backward compatibility with existing Clevis clients.
Tang generates an ML-KEM-768 keypair alongside its existing EC keys. Two new endpoints handle the PQC key lifecycle:
GET /adv-kem — Serves a signed JWS containing only KEM (kty=AKP) keys, separate from /adv so legacy Clevis clients never encounter key types they can't handle.
POST /rec-kem/:thp — Bidirectional KEM recovery endpoint implementing a forward+return channel envelope:
a. Client encapsulates to Tang's KEM public key (forward channel), encrypts an inner payload under that shared secret
b. Tang decapsulates, verifies ek_digest (SHA-256 thumbprint of the enc_key) to prevent oracle attacks, then encapsulates back to the client's ephemeral KEM public key (return channel)
c. Tang encrypts enc_key under the return-channel shared secret and returns it — enc_key never appears in plaintext in the response
Architecture
PQC code is cleanly isolated from the core server:
Other changes
GET /version — New endpoint reporting server capabilities (tang_pub, hybrid_recovery) and version.
tangd-keygen — Generates ML-KEM-768 keys when jose supports it (soft-fails otherwise).
Test coverage