Skip to content

Comments

[keymanager/wsd] Add Go orchestration layer (KOL) for WSD key generation#648

Closed
atulpatildbz wants to merge 12 commits intogoogle:mainfrom
atulpatildbz:wsd_generate_key_go
Closed

[keymanager/wsd] Add Go orchestration layer (KOL) for WSD key generation#648
atulpatildbz wants to merge 12 commits intogoogle:mainfrom
atulpatildbz:wsd_generate_key_go

Conversation

@atulpatildbz
Copy link
Collaborator

Summary of changes

  • Implement the Go Key Orchestration Layer (KOL) for the Workload Service Daemon (WSD)
  • Expose a single POST /keys:generate endpoint that orchestrates the full key generation flow:
    1. WSD KOL calls WSD KCC (Rust FFI) to generate a binding keypair
    2. WSD KOL passes the binding public key to KPS KOL (direct Go method call)
    3. KPS KOL calls KPS KCC (Rust FFI) to generate a KEM keypair
    4. WSD KOL stores the KEM UUID → Binding UUID mapping
    5. Returns the KEM UUID to the workload
  • Extend both Rust FFI functions to return public keys (6142136. cherry-pickable onto [KeyManager] Implement FFI for KEM and binding key generation #645)

PR Dependencies

This PR is built on top of:

More details

  • CGO bridges (wskcc, kpskcc): Go wrappers calling Rust FFI via CGO, returning (uuid.UUID, []byte, error)
  • C headers: Contract headers for both KCC crates
  • KPS KOL (key_protection_service/service.go): KEMKeyGenerator interface wrapping KPS KCC FFI
  • WSD KOL (workload_service/server.go): HTTP server with /keys:generate, kemToBindingMap, dependency-injected interfaces
  • Rust FFI extension: out_pubkey/out_pubkey_len params added to both FFI functions (commit 6142136, cherry-pickable on [KeyManager] Implement FFI for KEM and binding key generation #645)

Tests

  • Rust unit tests (141 tests) — BoringSSL crypto, km_common, ws_kcc, kps_kcc
  • Go unit tests (7 tests, mock-based, no CGO) — WSD server handler success/error/method-not-allowed/map-uniqueness, KPS service success/error
  • WSD KCC integration (2 tests) — Go → CGO → Rust binding key generation, returns valid UUID + 32-byte public key, unique across calls
  • KPS KCC integration (3 tests) — Go → CGO → Rust KEM key generation, validates empty binding key rejection, uniqueness
  • WSD KOL end-to-end (2 tests) — Full POST /keys:generate → WSD KCC FFI → KPS KOL → KPS KCC FFI, confirms KEM UUID returned and KEM→Binding map populated with unique entries

All 156 tests pass in a privileged container (required for memfd_secret).

NilanjanDaw and others added 12 commits February 6, 2026 23:22
bindings

Introduces a new `common` crate within the `keymanager` workspace to
house shared data structures and protobuf definitions.

Key changes:
- Adds ``keymanager/common`` crate with `uuid`, `memmap2`, `zeroize`,
  and `prost` dependencies.
- Defines core data structures in ``key_types.rs``: `KeySpec`,
  `KeyMetadata`, `Vault`, `KeyRecord`, and `KeyRegistry`.
- Implements protobuf bindings for cryptographic algorithms in
  ``proto/algorithms.proto``.
- Configures ``build.rs`` to generate Rust bindings from protos using
  `protoc-bin-vendored`.
- Updates ``keymanager/Cargo.toml`` to include `common` in the workspace.
Vault for secure key storage

Implements a secure Vault struct in keymanager/common
that stores sensitive key material in a memory-backed
file created via memfd_create.

Key Changes:

- Sealed Storage: Uses memfd_create with `MFD_CLOEXEC`
and `MFD_NOEXEC_SEAL` to create an anonymous file in RAM.
- Immutability: Applies `F_SEAL_GROW`, `F_SEAL_SHRINK`,
and `F_SEAL_SEAL` using fcntl to prevent modification
of the file's content or size after initialization.

- Secure Cleanup: Implements ZeroizeOnDrop
(via the zeroize crate) to ensure the memory map is
cleared when the Vault is dropped.

- Restricted Access: The underlying file descriptor
is dropped immediately after mapping (except in test builds),
ensuring no direct file access remains.
`km_common`

Introduces a `crypto` module in `km_common` to handle cryptographic
operations backed by BoringSSL (`bssl-crypto`).

Key Contributions:
1. HPKE Decryption (`decrypt`):
   - Implements `decrypt` using `bssl_crypto::hpke` for "single-shot"
     Hybrid Public Key Encryption (HPKE) opening.
   - Supports the standard HPKE suite: DHKEM(X25519, HKDF-SHA256),
     HKDF-SHA256, and AES-256-GCM.
   - Maps internal `HpkeAlgorithm` types to BoringSSL parameters.

2. DHKEM Decapsulation (`decaps`):
   - Implements a standalone `decaps` function for DHKEM(X25519, HKDF-SHA256).
   - Manually constructs the KEM context (suite ID, labeled IKM/Info)
     compliant with RFC 9180 to derive the shared secret directly from
     an encapsulated key and private key.
   - Validates implementation against test vectors accounting for
     BoringSSL's internal private key clamping.

3. Dependencies & Error Handling:
   - Adds `bssl-crypto` for underlying crypto operations.
   - Uses `thiserror` for structured error definitions (`KeyLenMismatch`,
     `DecapsError`, `HpkeDecryptionError`).
Introduces FFI-accessible functions for generating and managing
cryptographic keys within the Key Protection Service (KPS) and
Workload Service (WS).

Key Changes:
- FFI Compatibility: Configured prost_build in km_common to apply
  #[repr(C)] to the HpkeAlgorithm struct, enabling its use in C-style
  interfaces.
- Key Generation Logic: Added create_key_record in km_common to
  centralize secure keypair generation (X25519), ensuring private keys
  are immediately moved to secure Vault storage and zeroized from
  temporary memory.
- Key Management: Implemented KeyRegistry and a global registry instance
  in both KPS and WS to track generated keys by UUID.
- FFI Exports:
    - Added key_manager_generate_kem_keypair to KPS for generating
      KEM keys with associated binding public keys.
    - Added key_manager_generate_binding_keypair to WS for generating
      standard binding keys.
- Testing: Added comprehensive unit tests for FFI functions, including
  error handling for invalid algorithms and null pointers.
Integrates BoringSSL into the Cargo build process by adding a custom `build.rs`
to `third_party/bssl-sys`.

Implementation Details:
1. uses the `cmake` crate in `build.rs` to automatically configure and
build BoringSSL from git submodule.
2. Sets `RUST_BINDINGS` to ensure BoringSSL generates the necessary
Rust targets.
3. Preserves upstream bindgen logic to generate platform-specific
bindings during the build.
4. Enables standard `cargo build` workflows without requiring
external scripts or manual pre-build steps.
Implement the Go HTTP server and CGO bridges that expose the Rust FFI
key generation functions as HTTP APIs:

- POST /keys:generateBindingKeypair → WSD KCC FFI → returns binding UUID
- POST /keys:generateKEMKeypair → KPS KCC FFI → returns KEM UUID

Components added:
- C headers for ws_key_custody_core and kps_key_custody_core FFI contracts
- CGO bridges (wskcc, kpskcc packages) wrapping Rust FFI functions
- KPS KOL service with KEMKeyGenerator interface
- WSD KOL HTTP server with dependency-injected interfaces for testability
- Go module (keymanager/go.mod) added to go.work workspace
- staticlib crate-type for both Rust KCC crates

Tests:
- 9 unit tests for WSD server (mock-based, no CGO required)
- 2 unit tests for KPS service
- 7 integration tests (Go → CGO → Rust → BoringSSL) via podman container
- Integration test script (integration_test.sh) for containerized E2E testing
Extend both key_manager_generate_binding_keypair (WSD KCC) and
key_manager_generate_kem_keypair (KPS KCC) to also output the public
key via out_pubkey/out_pubkey_len parameters. This enables the Go
orchestration layer to pass the binding public key from WSD to KPS
when generating KEM keypairs.

Changes:
- Rust FFI: add out_pubkey and out_pubkey_len params to both functions
- Updated Rust tests for new signatures
…to-binding map

Rewrite the Go orchestration layer to expose a single POST
/keys:generate
endpoint that orchestrates the full key generation flow:
1. WSD KOL calls WSD KCC FFI to generate binding keypair
2. WSD KOL calls KPS KOL (direct method call) with binding public key
3. KPS KOL calls KPS KCC FFI to generate KEM keypair
4. WSD KOL stores KEM UUID → Binding UUID mapping
5. Returns KEM UUID to workload

Changes:
- C headers: update declarations with out_pubkey/out_pubkey_len params
- CGO bridges: return (uuid.UUID, []byte, error) with public key
- KPS service: updated interface and impl for new signature
- WSD server: single /keys:generate replacing two separate endpoints
- WSD server: kemToBindingMap populated, LookupBindingUUID accessor
- Integration tests: test full orchestrated flow (WSD KCC → KPS KOL →
KPS KCC)
- Removed integration_test.sh
Refactors the internal key management in workload_service to use a
KeyRegistry interface instead of an inline map. This improves testability
and concurrency handling.

Also adds integration_test.go to verify Go-Rust FFI interactions for both
binding and KEM key generation, ensuring the full flow works as expected
with the real Rust libraries.
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.

2 participants