Skip to content

Add post-quantum cryptography support with ML-DSA-65#37

Open
therealpaulgg wants to merge 9 commits intomainfrom
claude/quantum-resistant-key-generation-XTHBx
Open

Add post-quantum cryptography support with ML-DSA-65#37
therealpaulgg wants to merge 9 commits intomainfrom
claude/quantum-resistant-key-generation-XTHBx

Conversation

@therealpaulgg
Copy link
Owner

@therealpaulgg therealpaulgg commented Feb 13, 2026

Summary

Adds post-quantum cryptography support using ML-DSA (FIPS 204, MLDSA65 parameter set) for JWT authentication alongside existing ECDSA. The server can now accept, validate, and verify ML-DSA-signed JWTs while maintaining full backward compatibility.

Key Changes

New PQC crypto package (pkg/crypto/pqc.go)

  • Uses filippo.io/mldsa library (not Cloudflare CIRCL)
  • DetectKeyType(): Identifies key type from PEM block ("MLDSA PUBLIC KEY" vs EC)
  • ValidatePublicKey(): Validates both ECDSA and ML-DSA public keys
  • ParseMLDSAPublicKey(): Parses ML-DSA public key from PEM
  • DetectJWTAlgorithm(): Extracts algorithm from JWT header
  • ExtractJWTClaims(): Manually parses JWT claims (for algorithms unsupported by lestrrat-go/jwx)
  • VerifyMLDSAJWT(): Verifies ML-DSA signatures and token expiration

Authentication middleware (pkg/web/middleware/auth.go)

  • Algorithm-aware routing: ES256/ES512 → lestrrat-go/jwx; MLDSA → manual verification
  • JWT algorithm header identifier: "MLDSA" (matches the filippo.io/mldsa parameter set naming)

Machine key management (pkg/web/router/routes/machine.go)

  • New PUT /api/v1/machines/key endpoint for updating a machine's public key
  • Validates uploaded keys via ValidatePublicKey() (supports both ECDSA and ML-DSA)

Setup route (pkg/web/router/routes/setup.go)

  • Uses ValidatePublicKey() during machine registration to accept both key types

Repository (pkg/database/repository/machine.go)

  • Added UpdateMachinePublicKey(id, publicKey) to MachineRepository interface and implementation
  • Machine model stores a single PublicKey []byte (no separate encapsulation key)

WebSocket challenge flow (pkg/web/live/main.go)

  • Validates incoming public key with pqc.ValidatePublicKey() before storing

Test utilities (pkg/web/testutils/main.go)

  • GenerateMLDSATestKeys(): Creates ML-DSA keypairs for testing
  • EncodeMLDSAToPem(): PEM-encodes ML-DSA public keys ("MLDSA PUBLIC KEY" block type)
  • GenerateMLDSATestToken() / GenerateExpiredMLDSATestToken(): Creates signed ML-DSA JWTs

Test coverage

  • pkg/crypto/pqc_test.go: Tests for key detection, parsing, JWT algorithm detection, claims extraction, and signature verification
  • Updated auth middleware tests: valid ML-DSA token, wrong key, expired token
  • Machine route tests for key update endpoint
  • Setup route test for ML-DSA key registration

Implementation Notes

  • PEM block type: "MLDSA PUBLIC KEY" for clear identification
  • ECDSA verification unchanged; lestrrat-go/jwx still used for ES256/ES512 paths
  • Full backward compatibility: existing ECDSA-based clients continue to work without changes

claude and others added 7 commits February 13, 2026 19:43
…pport

Server-side support for post-quantum cryptography alongside existing ECDSA:

- Add pkg/crypto/pqc.go with ML-DSA-65 key detection, parsing, and JWT
  verification using Cloudflare CIRCL library
- Update auth middleware to dual-path: ES512 (classic) and MLDSA65 (PQ)
  with automatic algorithm detection from JWT header
- Update setup endpoint to accept both ECDSA and ML-DSA-65 public keys
- Add PUT /api/v1/machines/key endpoint for key migration
- Add public key format validation in WebSocket challenge flow
- Add UpdateMachinePublicKey to machine repository
- Comprehensive tests for all PQ crypto operations and endpoints

https://claude.ai/code/session_01SmqP3CTDjjbT3pZ85ffBS1
Replace ML-DSA-65 JWT verification with standard ES256/ES512 dual-path
auth. The client now signs JWTs with ECDSA (P-256 for hybrid, P-521 for
legacy) instead of ML-DSA-65.

Key changes:
- Remove all ML-DSA-65 code (CIRCL dependency no longer needed)
- Add ML-KEM-768 encapsulation key storage per machine (nullable)
- Parse two-block PEM (PUBLIC KEY + MLKEM768 ENCAPSULATION KEY) at
  setup and key migration endpoints
- Update WebSocket challenge flow to relay encapsulation_key alongside
  public_key between machines
- Auth middleware simplified to ES256 + ES512 only via jwx
- Backward compatible: legacy users with EC-only keys continue working

https://claude.ai/code/session_01SmqP3CTDjjbT3pZ85ffBS1
@therealpaulgg
Copy link
Owner Author

this PR has been tested in docker configuration (ssh-sync and ssh-sync-server). Post quantum crypto is working.

Need to do a deeper dive into the code to ensure the somewhat "vibed" parts of the code are quality and not overly verbose and hard to maintain.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces post-quantum JWT authentication support by adding ML-DSA-based key/JWT handling alongside the existing ECDSA flow, and updates routes and tests to accept/validate the new key type.

Changes:

  • Added pkg/crypto/pqc.go (+ tests) to detect/validate ECDSA vs ML-DSA public keys and verify ML-DSA-signed JWTs.
  • Updated auth middleware to route verification by JWT alg (ECDSA via jwx; ML-DSA via the new PQC verifier).
  • Added a machine public-key rotation endpoint and updated setup/live flows to validate ML-DSA keys; expanded test utilities and test coverage.

Reviewed changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 14 comments.

Show a summary per file
File Description
pkg/web/testutils/main.go Adds ML-DSA key + JWT generation helpers for tests.
pkg/web/router/routes/user_test.go Switches DTO import to ssh-sync-common.
pkg/web/router/routes/user.go Switches DTO import to ssh-sync-common.
pkg/web/router/routes/setup_test.go Adds initial setup test for ML-DSA key registration.
pkg/web/router/routes/setup.go Uses new PQC key validation in setup; replaces deprecated ioutil.ReadAll.
pkg/web/router/routes/machine_test.go Adds tests for machine key update endpoint (valid/invalid key).
pkg/web/router/routes/machine.go Adds /key route to update stored machine public key with PQC validation.
pkg/web/router/routes/data_test.go Switches DTO import to ssh-sync-common.
pkg/web/router/routes/data.go Switches DTO import to ssh-sync-common.
pkg/web/middleware/auth_test.go Adds ML-DSA auth scenarios and adjusts unsigned-token test.
pkg/web/middleware/auth.go Adds algorithm detection and ML-DSA JWT verification path.
pkg/web/live/main.go Moves WS helpers to ssh-sync-common and validates incoming public keys in challenge flow.
pkg/database/repository/machinemock.go Extends machine repository mock with UpdateMachinePublicKey.
pkg/database/repository/machine.go Adds DB update method for machine public key rotation.
pkg/crypto/pqc_test.go New test suite for PQC key/JWT helpers and ML-DSA JWT verification.
pkg/crypto/pqc.go New PQC helper implementation (key detection/validation, JWT alg/claims, ML-DSA JWT verification).
go.sum Updates sums for new/updated dependencies.
go.mod Updates Go version and dependencies (adds filippo.io/mldsa, ssh-sync-common, bumps uuid/ws).
docker-compose.yaml Changes DB image reference.
Dockerfile.debug Adds debug Dockerfile using Go builder image.
Dockerfile Updates Go builder image version.
Comments suppressed due to low confidence (1)

go.mod:9

  • The golang.org/x/sys require line has a duplicated/garbled indirect comment (// indirect; indirect\). Running go mod tidy (or manually cleaning this comment) would keep go.mod in a standard, tool-generated form and reduce churn in future diffs.
require (
	github.com/go-chi/chi v1.5.4
	github.com/rs/zerolog v1.28.0
	golang.org/x/sys v0.30.0 // indirect; indirect\
)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@therealpaulgg therealpaulgg marked this pull request as ready for review February 24, 2026 07:15
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.

3 participants