| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- package handshake
- import (
- "crypto/mlkem"
- "crypto/rand"
- "github.com/DefinedNet/noise"
- "github.com/slackhq/nebula/cert"
- )
- // Credential holds everything needed to participate in a handshake
- // at a given cert version. Version and Curve are read from Cert; the public
- // half of the static keypair likewise comes from Cert.PublicKey().
- type Credential struct {
- Cert cert.Certificate // the certificate
- Bytes []byte // pre-marshaled certificate bytes
- privateKey []byte // static private key (public half lives in Cert)
- publicKey []byte // static public key, the classical half for a v3 Cert
- kemKey noise.KEMKey // static KEM keypair of the Cert's suite, only for a v3 Cert
- kemDK *mlkem.DecapsulationKey1024 // kemKey expanded, when the suite's KEM is ML-KEM-1024
- cipherSuite noise.CipherSuite // pre-built cipher suite (DH + cipher + hash)
- }
- // NewCredential creates a Credential with all material needed for handshake
- // participation. The cipherSuite should be pre-built by the caller with the
- // appropriate DH function, cipher, and hash.
- //
- // For a version 3 certificate privateKey is the composite private key,
- // classical || the seed of its suite's KEM, matching the composite
- // Cert.PublicKey().
- func NewCredential(
- c cert.Certificate,
- hsBytes []byte,
- privateKey []byte,
- cipherSuite noise.CipherSuite,
- ) *Credential {
- hc := &Credential{
- Cert: c,
- Bytes: hsBytes,
- privateKey: privateKey,
- publicKey: c.PublicKey(),
- cipherSuite: cipherSuite,
- }
- if suite := cert.PQSuiteOf(c); suite != cert.PQSuiteUnknown {
- // The pki checked the private key against the certificate, so both split.
- hc.publicKey, hc.kemKey.Public, _ = suite.SplitPublicKey(false, c.PublicKey())
- hc.privateKey, hc.kemKey.Private, _ = suite.SplitPrivateKey(false, privateKey)
- // Expand the static KEM key once rather than in every handshake.
- if st, ok := HybridSubtype(suite); ok && subtypeInfos[st].kem == KEMMLKEM1024 {
- hc.kemDK, _ = mlkem.NewDecapsulationKey1024(hc.kemKey.Private)
- }
- }
- return hc
- }
- // buildHandshakeState creates a noise.HandshakeState from this credential. A
- // hybrid pattern also gets its KEM and the static KEM key.
- func (hc *Credential) buildHandshakeState(initiator bool, info subtypeInfo) (*noise.HandshakeState, error) {
- cfg := noise.Config{
- CipherSuite: hc.cipherSuite,
- Random: rand.Reader,
- Pattern: info.pattern,
- Initiator: initiator,
- StaticKeypair: noise.DHKey{Private: hc.privateKey, Public: hc.publicKey},
- }
- if info.kem != nil {
- cfg.KEMFunc = info.kem
- cfg.StaticKEMKeypair = hc.kemKey
- if info.kem == KEMMLKEM1024 {
- cfg.KEMFunc = &mlkem1024Keys{static: hc.kemDK, staticSeed: hc.kemKey.Private}
- }
- }
- return noise.NewHandshakeState(cfg)
- }
- // GetCredentialFunc returns the handshake credential for the given version,
- // or nil if that version is not available.
- //
- // Implementations must return credentials drawn from a snapshot stable for
- // the lifetime of any single Machine. The Machine may call this multiple
- // times during a handshake (e.g. when negotiating to the peer's version)
- // and assumes the underlying static keypair is consistent across calls.
- type GetCredentialFunc func(v cert.Version) *Credential
|