mirror of
https://github.com/slackhq/nebula.git
synced 2026-11-15 15:06:52 +01:00
cert: Name the post-quantum algorithms of a version 3 certificate with a PQSuite, like its curve, and pick the hybrid subtype by the suite's KEM
This commit is contained in:
1 parent
84e28c62ea
commit
656164b259
29 files changed
+1124
-365
No files matched your search
+33
-12
@@ -77,12 +77,23 @@ CertificateV3 ::= SEQUENCE {
|
||||
curve [1] Curve DEFAULT curve25519,
|
||||
publicKey [2] OCTET STRING, -- classical: X25519 / P256 for hosts, Ed25519 / ECDSA P256 for CAs
|
||||
signature [3] OCTET STRING, -- classical CA signature over details || curve || publicKey, as in v2
|
||||
pqPublicKey [4] OCTET STRING, -- ML-KEM-1024 encapsulation key for hosts, ML-DSA-87 public key for CAs
|
||||
pqSignature [5] OCTET STRING -- ML-DSA-87 by the issuing CA, context "nebula certificate v3",
|
||||
-- over the DER of fields 0 to 4, curve always present
|
||||
pqSuite [4] OCTET STRING, -- one byte, the PQSuite; always present
|
||||
pqPublicKey [5] OCTET STRING, -- the suite's KEM public key for hosts, its signature public key for CAs
|
||||
pqSignature [6] OCTET STRING -- the suite's signature by the issuing CA, context "nebula certificate v3",
|
||||
-- over the DER of fields 0 to 5, curve always present
|
||||
}
|
||||
```
|
||||
|
||||
- **The suite.** `pqSuite` names the post-quantum algorithms the way `curve` names the classical
|
||||
ones: the KEM of host keys, and the signature algorithm of CA keys and of the certificates a CA
|
||||
signs. A CA and every certificate it signs share a suite, as they share a curve; the CA pool
|
||||
rejects a mismatch, and the post-quantum signature covers the suite, so a certificate can not be
|
||||
relabelled. The field is always present, in handshakes too, with no default, and 0 is never
|
||||
valid. There is one suite today, `MLKEM1024_MLDSA87` (1): ML-KEM-1024 hosts, ML-DSA-87 CAs. A
|
||||
new suite is an entry in the cert package's suite table plus, for a new KEM, a hybrid subtype; no
|
||||
new certificate version. Changing a CA's suite means a new CA, or a new v3 extension of its v2
|
||||
form that replaces the old one, since one v2 CA has one v3 extension.
|
||||
|
||||
- **The v2 form.** Fields 0 to 3 are a byte exact v2 certificate, signed by the v2 form of the CA.
|
||||
A v3 holder presents it in classical and phase 1 handshakes, so peers that only speak v2 accept
|
||||
it as they always have, and old parsers never see v3 bytes. A node therefore needs one
|
||||
@@ -109,7 +120,9 @@ CertificateV3 ::= SEQUENCE {
|
||||
- **Keys are composite**, classical followed by post-quantum, wherever a v3 certificate deals in
|
||||
them: `PublicKey()` returns `classical || pq`, and private keys are `classical || seed` (64 byte
|
||||
ML-KEM seed for hosts, 32 byte ML-DSA seed for CAs), in one PEM block in `pki.key` with banners
|
||||
such as `NEBULA X25519 MLKEM1024 PRIVATE KEY` and `NEBULA ED25519 MLDSA87 PRIVATE KEY`.
|
||||
such as `NEBULA X25519 MLKEM1024 PRIVATE KEY` and `NEBULA ED25519 MLDSA87 PRIVATE KEY`. The
|
||||
banner names the post-quantum algorithm, not the suite, because a seed's size does not tell the
|
||||
algorithm's strength.
|
||||
- **Both curves.** Curve25519 and P256; the post-quantum half does not depend on the curve.
|
||||
- **In-place upgrade.** `nebula-cert pq-extend` turns an existing v2 CA into a v3 CA whose v2 form
|
||||
is the old CA certificate, byte for byte, and extends existing host certificates the same way.
|
||||
@@ -118,8 +131,8 @@ CertificateV3 ::= SEQUENCE {
|
||||
|
||||
| Certificate | Full | In a handshake | v2 form |
|
||||
|---|---|---|---|
|
||||
| CA, Curve25519 | 7362 B | n/a | 134 B |
|
||||
| Host, Curve25519 | 6375 B | 4769 B | 171 B |
|
||||
| CA, Curve25519 | 7365 B | n/a | 134 B |
|
||||
| Host, Curve25519 | 6378 B | 4772 B | 171 B |
|
||||
|
||||
`crypto/mldsa` is new in Go 1.27, so `go.mod` moves to Go 1.27.
|
||||
|
||||
@@ -163,11 +176,17 @@ design rationale and security argument), with ML-KEM-1024 supplied by nebula:
|
||||
initiator sealed.
|
||||
- v3 certificates go with this subtype and nothing else: a v3 certificate on any other subtype, or
|
||||
a v2 one on this one, is a protocol error.
|
||||
- **One subtype per KEM.** A hybrid subtype names its KEM, and a v3 holder initiates the subtype of
|
||||
its suite's KEM. Peers need the same KEM, not the same suite: suites that differ only in their
|
||||
signature algorithm share a subtype, and each certificate carries its own suite. A responder
|
||||
whose suite uses another KEM drops msg1, so the pair behaves as if the responder did not speak
|
||||
PQ: classical fallback, or no tunnel under `require`. A suite's KEM must have a subtype for the
|
||||
pki to load a certificate in it.
|
||||
|
||||
| Message | Size (Curve25519) | Data fragments (k) |
|
||||
|---|---|---|
|
||||
| msg1 | 8006 B | 7 |
|
||||
| msg2 | 9625 B | 9 |
|
||||
| msg1 | 8009 B | 7 |
|
||||
| msg2 | 9628 B | 9 |
|
||||
| msg3 | 1616 B | 2 |
|
||||
|
||||
**Dependency.** DefinedNet/noise is a private repository today. `go.mod` points at a local clone
|
||||
@@ -484,10 +503,11 @@ in every scenario above, and within three at least 99.99%.
|
||||
|
||||
## Implementation (phase 2)
|
||||
|
||||
- `cert`: `cert_v3.go` (format, `V2Form`, `ExtendToV3`, `SignPQ`), `SignHybridWith` and the
|
||||
composite `Sign` path, the CA pool's v3 index and v2-form blocklisting, and the composite key
|
||||
PEM banners.
|
||||
- `cert`: `cert_v3.go` (format, `V2Form`, `ExtendToV3`, `SignPQ`), `pq_suite.go` (`PQSuite` and
|
||||
the suite table), `SignHybridWith` and the composite `Sign` path, the CA pool's v3 index, suite
|
||||
check and v2-form blocklisting, and the composite key PEM banners, generated per suite.
|
||||
- `handshake`: the `ix_hybrid_mlkem1024` subtype on `noise.HandshakeHybridIX`, `KEMMLKEM1024`,
|
||||
`HybridSubtype` mapping a suite to the subtype of its KEM,
|
||||
composite credentials, cipher states ordered by role for three message patterns, and
|
||||
`Machine.PeerCert` for a responder that has to act before completion.
|
||||
- `pki.go` loads a v3 certificate with its composite key and derives the v2 form; messages after
|
||||
@@ -496,7 +516,8 @@ in every scenario above, and within three at least 99.99%.
|
||||
initiator's msg3 resends and teardown; `outside.go` keeps quiet about pending responder indexes.
|
||||
- `nebula-cert`: `ca`, `keygen` and `sign` take `-version 3`, `keygen -in-key` extends an existing
|
||||
host key, `sign -version 2` with a v3 CA signs as its v2 form, and `pq-extend` upgrades v2
|
||||
certificates in place, keeping an encrypted CA key encrypted.
|
||||
certificates in place, keeping an encrypted CA key encrypted. `ca`, `keygen` and `pq-extend` of a
|
||||
CA take `-pq-suite`; `sign` and `pq-extend` of a host take the CA's suite.
|
||||
- Tests: certificate format, strictness, tampering, pool and blocklist rules and in-place
|
||||
extension on both curves; Machine-level hybrid handshakes including corrupted msg3 and
|
||||
impersonation with only the classical key; e2e tests for a clean hybrid handshake, a lost
|
||||
|
||||
Reference in new issue
Block a user