Skip to content

feat(kas): Adds FIPS-203 wrap with ML-KEM-768/1024#3652

Merged
dmihalcik-virtru merged 41 commits into
mainfrom
DSPX-3383-merge-main
Jun 29, 2026
Merged

feat(kas): Adds FIPS-203 wrap with ML-KEM-768/1024#3652
dmihalcik-virtru merged 41 commits into
mainfrom
DSPX-3383-merge-main

Conversation

@dmihalcik-virtru

@dmihalcik-virtru dmihalcik-virtru commented Jun 22, 2026

Copy link
Copy Markdown
Member

ML-KEM 768/1024

The primary motivation for this work is ML-KEM 768 and 1024 support for key wrapping and KAS/policy algorithm selection. These provide FIPS 3 compliant NIST 203 implementations, which will provide post-quantum resistance for TDFs created with this algorithm, just as the hybrids do, but in a way that should be compliant with FIPS 3 approved software and hardware encryption modules.

Since this is a new feature for the file, we place it within the new mlkem-wrapped KAO type.

As part of this work, we also extend the policy service, KAS, and the otdfctl tool to support key generation, import, and public key access.

For the configuration, this piggy-backs mlkem_tdf_enabled on the existing hybrid_tdf_enabled, so if the latter is set then pure mlkem is also enabled. You can enable just pure mlkem without hybrid, though. I mostly did this as a convenience for testing, so I can uncouple these later if desired. but to me it makes sense - hybrid implies mlkem, but the use of mlkem does not imply hybrid. As part of this, I've made a normalization pass on the config to set the values, removing the need to check deprecated config names later when making decisions.

Notes for the reviewer

  • refactored the hybrid KEM to share more code with the pure mlkem-wrapped kaos
  • Still duplicating logic between the asym enc/dec .go and the key_pair.go. The former are mostly used by service, and the latter by the sdk, so this is compound interest on the technical debt from not unifying these
  • removes a couple of deprecated constructors for the asym library, which would produce non-conformant mechanisms anyway. I probalby should put an ! in the CC because of this, lmk if you want me to. I couldn't find any live use in a github search
  • some other small move refactors

Summary by CodeRabbit

  • New Features
    • Added ML-KEM 768 and 1024 support across key creation, wrapping/rewrapping, PEM import/export, and TDF flows (including mlkem-wrapped manifest handling).
  • Bug Fixes
    • Improved encryption/decryption dispatch for ML-KEM vs hybrid-wrapped keys and tightened validation/error behavior for algorithm mismatches.
  • Documentation
    • Updated OpenAPI/proto schemas, CLI/SDK mappings, and man pages to include the new ML-KEM options and refreshed policy.Condition.operator field documentation.

dmihalcik-virtru and others added 26 commits June 16, 2026 13:55
Add pure ML-KEM (Module-Lattice-Based Key-Encapsulation Mechanism)
support alongside existing hybrid post-quantum algorithms.

Changes:
- Add ALGORITHM_MLKEM_768 and ALGORITHM_MLKEM_1024 to proto enums
- Add ML-KEM key types (mlkem:768, mlkem:1024) to ocrypto library
- Implement MLKEMKeyPair and MLKEM1024KeyPair with key generation
- Update proto validation to accept ML-KEM algorithms
- Regenerate all protocol buffers and OpenAPI docs

This is a partial implementation. Remaining work includes:
- Add ML-KEM encryption/decryption to asym_encryption.go
- Add ML-KEM support to SDK and service layers
- Add corresponding tests

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implement complete ML-KEM 768/1024 encryption and decryption support
in the ocrypto library.

Encryption changes (asym_encryption.go):
- Add MLKEM SchemeType constant
- Add MLKEMEncryptor768 and MLKEMEncryptor1024 types
- Implement newMLKEM768/newMLKEM1024 constructors
- Handle mlkem.EncapsulationKey in FromPublicPEMWithSalt
- Implement all PublicKeyEncryptor interface methods
- Use AES-GCM with shared secret from KEM encapsulation

Decryption changes (asym_decryption.go):
- Add DecryptWithEphemeralKey method to interface
- Add MLKEMDecryptor768 and MLKEMDecryptor1024 types
- Handle "MLKEM DECAPSULATION KEY" PEM blocks
- Implement Decrypt and DecryptWithEphemeralKey methods
- Use AES-GCM with shared secret from KEM decapsulation

Also updated existing decryptors:
- Add DecryptWithEphemeralKey to AsymDecryption (RSA)
- Add DecryptWithEphemeralKey to ECDecryptor (ECDH)
- Add DecryptWithEphemeralKey to XWingDecryptor (hybrid)
- Add DecryptWithEphemeralKey to HybridNISTDecryptor (hybrid)

All lib/ocrypto tests pass.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add ML-KEM-768 and ML-KEM-1024 support to the KAS service layer:
- Add AlgorithmMLKEM768 and AlgorithmMLKEM1024 constants
- Add ML-KEM decryption support to BasicManager
- Add StandardMLKEMCrypto type for ML-KEM key management
- Add MLKEMPublicKey method for public key export
- Add ML-KEM case to StandardCrypto.Decrypt method

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Complete ML-KEM integration across the service layer:
- Add ML-KEM algorithms to InProcessProvider key listing and decryption
- Add ML-KEM support to public key export in KAS access layer
- Add ML-KEM algorithm mappings in policy grant_mappings

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Add ML-KEM-768 and ML-KEM-1024 algorithm support to SDK:
- Add ML-KEM cases to KeyTypeToPolicyAlgorithm conversion
- Add ML-KEM cases to PolicyAlgorithmToKeyType conversion
- Add ML-KEM enum mappings in convertAlgEnum2Simple
- Add ML-KEM string mappings in algProto2String

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Add ML-KEM-768 and ML-KEM-1024 support to otdfctl and experimental SDK:
- Add ML-KEM key generation in kasKeys command
- Add "mlkem:768" and "mlkem:1024" string mappings in CLI helpers
- Add ML-KEM validation in PEM validator
- Add ML-KEM enum conversions in experimental keysplit SDK

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Add ML-KEM-768 and ML-KEM-1024 key generation:
- Add ML-KEM key generation to service keygen command
- Add ML-KEM key generation to BDD test utilities
- Generate kas-mlkem768-private.pem and kas-mlkem768-public.pem
- Generate kas-mlkem1024-private.pem and kas-mlkem1024-public.pem

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Add pure post-quantum encryption tests for ML-KEM-768 and ML-KEM-1024 algorithms.
Tests validate KAO type (mlkem-wrapped), KID assignment (m1, m2), and successful
encrypt/decrypt roundtrips. Also updates KAS config to include ML-KEM keys.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Refactors plain ML-KEM (768/1024) to use ASN.1 DER encoding and HKDF key
derivation, matching the X-Wing and Hybrid NIST patterns. Stores ML-KEM
ciphertext concatenated with wrapped DEK in ASN.1 structure instead of
overloading ephemeralKey metadata.

- Add lib/ocrypto/mlkem.go with X-Wing-style wrap/unwrap functions
- Add comprehensive test coverage in mlkem_test.go
- Preserve backwards compatibility by renaming old types to Legacy variants
- Update otdfctl documentation to include mlkem:768 and mlkem:1024 algorithms

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…Legacy ML-KEM types

Remove DecryptWithEphemeralKey method from PrivateKeyDecryptor interface,
making it EC-specific. Only ECDecryptor needs ephemeral keys for ECDH.

Remove Legacy ML-KEM types and implementations:
- MLKEMEncryptor768Legacy, MLKEMEncryptor1024Legacy
- MLKEMDecryptor768Legacy, MLKEMDecryptor1024Legacy
- Old "MLKEM DECAPSULATION KEY" PEM handling
- Helper functions newMLKEM768(), newMLKEM1024()

Add PEM block constants for new ML-KEM implementation:
- PEMBlockMLKEM768PublicKey, PEMBlockMLKEM768PrivateKey
- PEMBlockMLKEM1024PublicKey, PEMBlockMLKEM1024PrivateKey

Remove DecryptWithEphemeralKey from all non-EC decryptors:
- MLKEMDecryptor768, MLKEMDecryptor1024
- XWingDecryptor, HybridNISTDecryptor
- AsymDecryption (RSA)

Update service layer to use Decrypt() for ML-KEM instead of
DecryptWithEphemeralKey. EC decryption continues to use the
EC-specific DecryptWithEphemeralKey method.

Breaking changes:
- Old ML-KEM PEM format ("MLKEM DECAPSULATION KEY") no longer supported
- Callers must use concrete ECDecryptor type for DecryptWithEphemeralKey

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
ML-KEM keys loaded through InProcessProvider failed FindKeyByID and
Decrypt with "could not determine key type" because the type switch in
determineKeyType was missing the StandardMLKEMCrypto case. Add the
case and a regression test exercising both mlkem:768 and mlkem:1024
through determineKeyType and FindKeyByID.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Cache the ML-KEM PrivateKeyDecryptor on StandardMLKEMCrypto during
loadKey instead of re-parsing the PEM on every Decrypt call. Mirrors
the existing RSA pattern.

Also fixes a latent bug in ocrypto.MLKEMKeyPair PEM writers: they
emitted "MLKEM DECAPSULATION KEY" / "MLKEM ENCAPSULATOR" block types,
but commit 40d10ce removed parser support for those headers. Updated
the writers to use the PEMBlockMLKEM{768,1024}{Private,Public}Key
constants the parser now recognizes.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
The key_algorithm CEL validation on ListKeysRequest only accepted
algorithm values 0-8, which excluded the post-quantum ML-KEM-768 (20)
and ML-KEM-1024 (21) values. Filtering by these algorithms returned a
validation error even though the server could store and serve them.

RotateKeyRequest.NewKey already includes 20 and 21 in its allowed set.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
ExportPublicKey fell through RSA/Hybrid/XWing to ECPublicKey, so pure
ML-KEM keys returned ErrCertNotFound and KAS PublicKey requests for
mlkem:768/mlkem:1024 failed with not_found.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
InProcessProvider.Decrypt rejected empty ephemeralPublicKey for ML-KEM,
but StandardCrypto.Decrypt and BasicManager.Decrypt both reject
non-empty values. The KEM ciphertext is the encapsulation; there is no
separate ephemeral key. Invert the check to match the HPQT case above
and pass nil downstream.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
MLKEMEncryptor768/1024.PublicKeyInPemFormat emitted "MLKEM
ENCAPSULATOR", but FromPublicPEMWithSalt dispatches on
PEMBlockMLKEM768PublicKey / PEMBlockMLKEM1024PublicKey, breaking PEM
round-trip. Use the canonical constants to match the X-Wing pattern
and the existing MLKEMKeyPair serialization in ec_key_pair.go.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Mirrors the negative assertion already in
TestInProcessProviderDetermineKeyType.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Replace the custom "MLKEM768 PUBLIC KEY" / "MLKEM1024 PRIVATE KEY" PEM
labels (raw key bytes with no ASN.1 envelope) with standard "PUBLIC KEY"
and "PRIVATE KEY" labels carrying RFC 5280 SubjectPublicKeyInfo and
RFC 5958 OneAsymmetricKey, with the algorithm conveyed by NIST OIDs
2.16.840.1.101.3.4.4.2 (ML-KEM-768) and 2.16.840.1.101.3.4.4.3
(ML-KEM-1024). The private-key PKCS#8 inner CHOICE uses [0] IMPLICIT
OCTET STRING (seed form, 64 bytes) per draft-ietf-lamps-kyber-certificates.

The encoding is hand-rolled rather than via crypto/x509 because stdlib
ML-KEM support in MarshalPKIXPublicKey / MarshalPKCS8PrivateKey landed in
Go 1.26 and this module pins go 1.25.

FromPublicPEMWithSalt / FromPrivatePEMWithSalt now peek at the OID after
PEM decode and route ML-KEM blobs to the existing encryptor/decryptor
constructors. Non-ML-KEM blobs fall through to the existing RSA/EC
parsers unchanged. The hybrid SECP256R1-MLKEM768, SECP384R1-MLKEM1024,
and X-Wing schemes keep their custom PEM labels for now; conformance to
IETF composite-KEM and X-Wing drafts is tracked under DSPX-3396 and will
land in a separate PR off main.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Add support for generating KAOs with type=mlkem-wrapped when using
pure ML-KEM wrapping keys (MLKEM768, MLKEM1024), while maintaining
backwards compatibility for reading type=wrapped KAOs.

Changes:
- Add IsMLKEMKeyType() helper in lib/ocrypto/ec_key_pair.go
- Add kMLKEMWrapped constant and ML-KEM case to createKeyAccess() in sdk/tdf.go
- Implement generateWrapKeyWithMLKEM() in sdk/tdf.go
- Add ML-KEM handling to wrapKeyWithPublicKey() in sdk/experimental/tdf/key_access.go
- Implement wrapKeyWithMLKEM() in sdk/experimental/tdf/key_access.go

This ensures integration tests pass which expect mlkem-wrapped type
for pure ML-KEM keys, while type=wrapped continues for RSA keys.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Make MLKEM768WrapDEK and MLKEM1024WrapDEK accept multiple input formats:
- Raw key bytes (1184/1568 bytes) - fast path
- SPKI DER (1206/1590 bytes)
- PEM-wrapped SPKI (~1686/~2206 bytes)

This fixes the issue introduced in 6a7480d where KAS started returning
SPKI-encoded PEM keys but callers expected raw bytes. Instead of requiring
all callers to decode manually, the crypto library now handles format
detection transparently.

Changes:
- Add normalizeMLKEMPublicKey() helper for format detection
- Export ParseMLKEMPublicSPKI() and OidMLKEM768/OidMLKEM1024 constants
- Update all internal references to use exported names
- Add comprehensive tests for format handling

Benefits:
- Backward compatible (raw keys still work)
- Simpler callers (no manual PEM decoding needed)
- Better encapsulation (format logic in crypto library)
- Future-proof (handles new formats automatically)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Adds support for pure ML-KEM key agreement objects in the KAS rewrap
handler. The SDK now emits type="mlkem-wrapped" for MLKEM768/MLKEM1024
KAOs, and this change adds the corresponding case to handle decryption.

Follows the hybrid-wrapped pattern: uses HybridTDFEnabled flag, no
ephemeral key processing, and generic error messages per security
guidelines.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Collapse the three near-identical KEM wrap/unwrap implementations behind
one OID-keyed registry and a single internal kem contract. ML-KEM-768,
ML-KEM-1024, X-Wing, P-256+ML-KEM-768, and P-384+ML-KEM-1024 now share
one envelope type, one wrap function, one unwrap function, and one
encryptor/decryptor pair routed through FromPublicPEM / FromPrivatePEM.

Service and SDK callers shrink accordingly: StandardXWingCrypto,
StandardHybridCrypto, and StandardMLKEMCrypto fold into a single
StandardKEMCrypto; the per-algorithm wrap dispatch in sdk/tdf.go and
sdk/experimental/tdf/key_access.go collapses to one IsKEMKeyType branch
calling ocrypto.WrapDEK.

Wire formats are preserved byte-for-byte (hybrid-wrapped, mlkem-wrapped).
The OID registry leaves the planned hybrid-PEM-to-SPKI follow-up as a
near-zero change: three OID constants plus three registry entries.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
…DF references

The HKDF-removal for mlkem-wrapped landed in 455f280; flip the ADR to accepted and update two comments that still described the old HKDF-everywhere behaviour for pure ML-KEM (kemWrapKeySize and defaultTDFSalt docstring).

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
Reconcile the branch's unified KEM architecture with main's IETF-draft PQ
key-format conformance (#3563 / dc18568) and PQ CLI disable (#3625).

Resolution:
- ocrypto: adopt main's IETF-conformant hybrid types (composite-KEM OIDs,
  SPKI/PKCS#8 PEM, SHA3-256 draft-14 combiner) wholesale; keep the branch's
  unified kem.go + pure ML-KEM (NIST OIDs) as additive, trimming the unified
  adapters for hybrids. Dispatchers try ML-KEM SPKI first, then main's
  hybrid OID routing. Re-added unified WrapDEK; kemDecryptor exposes KeyType().
- service/security: keep the branch's unified StandardKEMCrypto container and
  port main's assertDecryptorAlgorithm load-time guard (now covers ML-KEM).
- protocol: regenerated objects.pb.go/enums.gen.go/connect wrappers from the
  cleanly-merged proto (ML-KEM enums + DynamicValueMapping).
- otdfctl: keep HPQT hybrids disabled (#3625); keep pure ML-KEM CLI support.

Verified: ocrypto/service-security/sdk/otdfctl/kas build, vet, and tests pass
(incl. main's hybrid_conformance_test.go and SDK end-to-end); proto regen is
deterministic; gofumpt clean; ocrypto golangci-lint 0 issues.

Signed-off-by: Dave Mihalcik <dmihalcik@virtru.com>
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds ML-KEM 768/1024 support for direct wrapping, expands policy and KAS enums, and routes the algorithms through ocrypto, security services, SDK/CLI plumbing, and integration tests.

Changes

ML-KEM direct key-wrap rollout

Layer / File(s) Summary
Decision, schemas, and docs
adr/decisions/2026-06-16-mlkem-direct-key-wrap.md, service/policy/objects.proto, service/policy/kasregistry/key_access_server_registry.proto, docs/grpc/index.html, docs/openapi/**/*.yaml
Records the ML-KEM direct-wrap decision and extends policy enums, validation allowlists, and generated API documentation with ML-KEM 768 and 1024 values.
Core KEM types and ML-KEM wrap flow
lib/ocrypto/key_type.go, lib/ocrypto/ecc_mode.go, lib/ocrypto/mlkem.go, lib/ocrypto/kem.go, lib/ocrypto/hybrid_common.go, lib/ocrypto/mlkem_test.go
Defines shared key and curve types, ML-KEM ASN.1 helpers, the shared KEM interface and envelope flow, the exported wrap helper, and ML-KEM-focused unit coverage.
Key pairs, PEM dispatch, and adapter unification
lib/ocrypto/ec_key_pair.go, lib/ocrypto/asym_encryption.go, lib/ocrypto/asym_decryption.go, lib/ocrypto/hybrid_nist.go, lib/ocrypto/xwing.go, lib/ocrypto/hybrid_conformance_test.go, lib/ocrypto/hybrid_nist_test.go, lib/ocrypto/xwing_test.go, lib/ocrypto/benchmark_test.go
Adds ML-KEM key-pair PEM support, routes ML-KEM and hybrid PEM parsing through shared KEM dispatch, and moves X-Wing and NIST hybrid wrapping onto the common KEM path with updated tests and benchmarks.
Security service loading, preview gating, and rewrap
service/internal/security/*.go, service/kas/access/provider.go, service/kas/access/rewrap.go, service/kas/access/publicKey.go, service/kas/kas.go, service/kas/*_test.go
Introduces shared KEM-backed key loading and decrypt paths in security services, extends ML-KEM algorithm support, and adds ML-KEM preview gating, public-key export, and KAS mechanism filtering and rewrap handling.
SDK, CLI, and key generation plumbing
sdk/*.go, sdk/experimental/tdf/*.go, otdfctl/cmd/policy/kasKeys.go, otdfctl/pkg/cli/sdkHelpers.go, otdfctl/pkg/utils/pemvalidate.go, service/cmd/keygen/main.go, tests-bdd/cukes/utils/utils_genKeys.go, otdfctl/docs/man/policy/kas-registry/key/*.md
Routes SDK wrapping and enum translation through shared KEM helpers, replaces deprecated asymmetric decryptor construction, adds ML-KEM CLI mappings and validation, and extends key generation tooling and docs.
Roundtrip and local-mode integration coverage
test/tdf-roundtrips.bats, otdfctl/e2e/kas-keys.bats
Adds Z-TDF and local key-management end-to-end coverage for ML-KEM algorithms, including configuration updates and manifest assertions for the new wrapped scheme.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • opentdf/platform#3276: Refactors the earlier hybrid NIST EC+ML-KEM wrapping API into the shared KEM flow used here.
  • opentdf/platform#3563: Changes the same hybrid NIST wire-format and adapter path that this PR updates to the shared KEM envelope.
  • opentdf/platform#3564: Updates the same mechanism-advertisement and supported-algorithm plumbing extended here for ML-KEM.

Suggested labels

pqc

Suggested reviewers

  • strantalis
  • elizabethhealy

🐇 ML-KEM keys go hop and hum,
Through kemEnvelope they now come.
No HKDF needed, secret bright,
Wrapped and unwrapped in one clean flight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.39% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding FIPS-203 ML-KEM-768/1024 wrapping support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch DSPX-3383-merge-main

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added comp:db DB component comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati labels Jun 22, 2026
@dmihalcik-virtru

Copy link
Copy Markdown
Member Author

Issues

  1. Breaking config change (main concern)HybridTDFEnabled moved from top-level KASConfig to Preview (provider.go). Existing config files with hybrid_tdf_enabled: true at the KAS config root will silently stop enabling hybrid on upgrade. normalizePreview only reads Preview.HybridTDFEnabled. Should verify no production configs rely on the old location, or add a deprecation shim.

I've added back and deprecated the moved field, and added handling of it to the normalizePreview method so reading code doesn't have to look at the old value anymore.

  1. privSize() returning -1 for hybrid NIST (hybrid_nist.go) — newKEMDecryptor special-cases k.privSize() >= 0 to skip validation. Works but is fragile — a future kem implementation accidentally returning -1 would skip validation silently. Consider a hasFixedPrivSize() bool method or a named sentinel constant.

If we have integer overflow in our size estimates, we may have other signals that there is an issue.

  1. generateHybridKeys function name (utils_genKeys.go) — now generates pure ML-KEM keys too but wasn't renamed. The comment was updated; consider renaming to generatePostQuantumKeys.

Done.

  1. kemRegistry is a write-once package-level map (kem.go) — safe today since it's never modified after init, but worth a comment noting this invariant.

Is it? I'll just be here waiting for more constexpr style support in golang while my beard grows longer

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 199.156385ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 108.919738ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 420.806373ms
Throughput 237.64 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.725972874s
Average Latency 445.611516ms
Throughput 111.79 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 201.521022ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 101.289671ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 420.975228ms
Throughput 237.54 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 44.694925664s
Average Latency 444.503354ms
Throughput 111.87 requests/second

@github-actions

Copy link
Copy Markdown
Contributor
Benchmark results, click to expand

Benchmark authorization.GetDecisions Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 211.957898ms

Benchmark authorization.v2.GetMultiResourceDecision Results:

Metric Value
Approved Decision Requests 1000
Denied Decision Requests 0
Total Time 111.75834ms

Benchmark Statistics

Name № Requests Avg Duration Min Duration Max Duration

Bulk Benchmark Results

Metric Value
Total Decrypts 100
Successful Decrypts 100
Failed Decrypts 0
Total Time 431.8941ms
Throughput 231.54 requests/second

TDF3 Benchmark Results:

Metric Value
Total Requests 5000
Successful Requests 5000
Failed Requests 0
Concurrent Requests 50
Total Time 46.055998905s
Average Latency 459.468124ms
Throughput 108.56 requests/second

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Govulncheck found vulnerabilities ⚠️

The following modules have known vulnerabilities:

  • examples
  • otdfctl
  • sdk
  • service
  • lib/fixtures
  • tests-bdd

See the workflow run for details.

@dmihalcik-virtru dmihalcik-virtru added this pull request to the merge queue Jun 29, 2026
Merged via the queue into main with commit 06f30ef Jun 29, 2026
107 of 115 checks passed
@dmihalcik-virtru dmihalcik-virtru deleted the DSPX-3383-merge-main branch June 29, 2026 15:26
dmihalcik-virtru added a commit to opentdf/java-sdk that referenced this pull request Jun 29, 2026
This PR updates the platform.branch property in all pom.xml files to the
new tag or branch: v0.36.0.

See the release:
https://github.com/opentdf/platform/releases/tag/protocol%2Fgo%2Fv0.36.0

Release Notes:
##
[0.36.0](opentdf/platform@protocol/go/v0.35.0...protocol/go/v0.36.0)
(2026-06-29)


### Features

* **kas:** Adds FIPS-203 wrap with ML-KEM-768/1024
([#3652](opentdf/platform#3652))
([06f30ef](opentdf/platform@06f30ef))

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Morgan Kleene <mkleene@virtru.com>
Co-authored-by: Mary Dickson <mary.dickson@virtru.com>
Co-authored-by: Dave Mihalcik <dmihalcik@virtru.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp:db DB component comp:kas Key Access Server comp:lib:ocrypto comp:policy Policy Configuration ( attributes, subject mappings, resource mappings, kas registry) comp:sdk A software development kit, including library, for client applications and inter-service communicati docs Documentation size/xl

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants