Documentation
¶
Overview ¶
Package ke implements TLS 1.2 key exchange methods.
Each Exchange implementation produces a ClientKeyExchange message body (cke) and the pre-master secret (preMaster) used by suites.MasterSecret.
Implementations: ECDHEExchange (P-256/P-384/P-521/X25519), RSAExchange, DHEExchange. GOST VKO is Phase 6.
Index ¶
- func DHEComputePublic(pBytes, baseBytes, exponentBytes []byte) ([]byte, error)
- func ECDHGeneratePublic(seed []byte) (privBytes, pubBytes []byte, err error)
- func GOST2001TestPublicKeyFromPrivate(prvRaw []byte) ([]byte, error)
- func NewVKOGost2001ExchangeTestCurve(prvRaw, pubRaw, ukm []byte) *vkoGost2001TestCurveExchange
- type DHEExchange
- type ECDHEExchange
- type Exchange
- type Gost2018Exchange
- type Gost2018Variant
- type RSAExchange
- type VKOGost2001Exchange
- type VKOGost2012_256Exchange
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DHEComputePublic ¶
DHEComputePublic computes base^exponent mod p using constant-time bigmod arithmetic. pBytes is the group prime; baseBytes is the base (g for computing public key, Yc for shared secret); exponentBytes is the private exponent x. Returns the result left-padded to len(pBytes) bytes.
Note: This function does NOT validate the DHE parameters (it is used for both key generation and shared-secret computation by trusted callers). Callers that receive base from an untrusted source must validate with validateDHEParams first.
func ECDHGeneratePublic ¶
ECDHGeneratePublic generates an ECDH P-256 public key from a fixed 32-byte seed. Returns the raw private key bytes and the uncompressed public key bytes. Used in tests to build deterministic server ECDHE parameters.
func GOST2001TestPublicKeyFromPrivate ¶
GOST2001TestPublicKeyFromPrivate derives the GOST R 34.10-2001 public key from a private key using the test parameter set curve. Used in tests to generate the public key for the upstream test vectors (which use CurveIdGostR34102001TestParamSet, not CryptoPro-A).
func NewVKOGost2001ExchangeTestCurve ¶
func NewVKOGost2001ExchangeTestCurve(prvRaw, pubRaw, ukm []byte) *vkoGost2001TestCurveExchange
NewVKOGost2001ExchangeTestCurve creates a VKOGost2001Exchange that uses the GOST R 34.10-2001 test parameter set curve (not CryptoPro-A). Used only in unit tests that verify round-trip logic with upstream gogost test vectors.
Production code uses NewVKOGost2001ExchangeWithKey (CryptoPro-A curve).
Types ¶
type DHEExchange ¶
type DHEExchange struct {
// contains filtered or unexported fields
}
DHEExchange implements the finite-field Diffie-Hellman Ephemeral (DHE) key exchange for TLS 1.2 (RFC 5246 §7.4.3, §8.1.2).
ServerParams encoding ¶
The raw ServerKeyExchange body per RFC 5246 §7.4.3:
dh_p opaque <1..2^16-1> — big-endian big integer dh_g opaque <1..2^16-1> dh_Ys opaque <1..2^16-1>
Each field is length-prefixed with a 2-byte big-endian length.
Parameter validation (fail-fast) ¶
- p must be at least 1024 bits (128 bytes).
- p must be odd (even p is not prime, hence invalid).
- g must be ≥ 2.
- 1 < Ys < p-1 (strict bounds; identity element and p-1 are both rejected).
For RFC 7919 named groups (ffdhe2048, ffdhe3072): the Ys^q ≡ 1 (mod p) check where q = (p-1)/2 is implied by the bounds check on safe primes. RFC 7919 ffdhe groups are safe primes (p = 2q+1, q prime), so the only elements of order ≤ 2 in (Z/pZ)* are {1, p-1}. Both are already caught by the strict range check. For non-named groups we skip the subgroup check (non-named groups may not be safe primes and the server is trusted per TLS).
Constant-time invariant ¶
The private exponent x and the shared secret Z = Ys^x mod p are computed exclusively with filippo.io/bigmod.Nat.Exp — a constant-time Montgomery modular exponentiation — never with math/big.Int.Exp.
math/big is used ONLY for public operations:
- Parsing p, g, Ys from bytes (math/big.Int.SetBytes — public data)
- Computing p-1 for the bounds check (public data)
- Comparing Ys against 1 and p-1 (public data)
- Checking g ≥ 2 (public data)
ClientKeyExchange body format ¶
Per RFC 5246 §7.4.7.2:
dh_Yc opaque <1..2^16-1> (2-byte length + client public key bytes)
Pre-master secret ¶
Z = Ys^x mod p, left-padded with zero bytes to len(p) bytes per RFC 5246 §8.1.2.
func NewDHEExchange ¶
func NewDHEExchange(privateX []byte) *DHEExchange
NewDHEExchange creates a DHEExchange.
privateX optionally fixes the client private exponent for testing. In production, pass nil to use a securely random exponent.
func (*DHEExchange) ClientKeyExchange ¶
func (d *DHEExchange) ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)
ClientKeyExchange parses the ServerKeyExchange DHE params, validates them, generates (or reuses) a client private exponent, computes the shared secret, and returns the CKE body and pre-master secret.
type ECDHEExchange ¶
type ECDHEExchange struct{}
ECDHEExchange implements the ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) key exchange for TLS 1.2.
Supported named curves (RFC 4492 NamedCurve values):
- 0x0017: secp256r1 (P-256)
- 0x0018: secp384r1 (P-384)
- 0x0019: secp521r1 (P-521)
- 0x001D: x25519
ServerParams format (RFC 5246 §7.4.3 / RFC 4492 §5.4):
curve_type uint8 = 3 (named_curve; any other value is rejected) named_curve uint16 point_len uint8 point [point_len]byte (uncompressed for P-curves; raw 32 bytes for X25519)
ClientKeyExchange body (cke):
point_len uint8 point [point_len]byte (client ephemeral public key)
Pre-master secret: the X coordinate (P-curves) or raw output (X25519) of the ECDH shared secret, with leading zeros preserved to the curve's fixed size.
func NewECDHEExchange ¶
func NewECDHEExchange() *ECDHEExchange
NewECDHEExchange creates an ECDHEExchange.
func (*ECDHEExchange) ClientKeyExchange ¶
func (e *ECDHEExchange) ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)
ClientKeyExchange generates a client ephemeral keypair, computes the shared secret against the server's public key, and returns the CKE body and pre-master secret.
type Exchange ¶
type Exchange interface {
// ClientKeyExchange computes the client's key-exchange contribution.
//
// cke is the raw ClientKeyExchange message body sent on the wire.
// preMaster is the pre-master secret fed into MasterSecret.
// err is non-nil if the server parameters are invalid or crypto fails.
ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)
}
Exchange is the interface implemented by all TLS 1.2 key exchange methods.
ServerParams encoding per key exchange type:
- ECDHE: raw body of the ServerKeyExchange message, starting with curve_type (1 byte) then named_curve (2 bytes) then server public key length-prefixed (1 byte). Defined in RFC 5246 §7.4.3 / RFC 4492 §5.4.
- DHE: raw body of the ServerKeyExchange message: dh_p (2-byte length + data), dh_g (2-byte length + data), dh_Ys (2-byte length + data). Defined in RFC 5246 §7.4.3.
- RSA: RSAExchange holds *rsa.PublicKey directly; ServerParams is ignored (pass nil). The server public key comes from the server certificate, not from a ServerKeyExchange message.
func NewECDHEExchangeWithRand ¶
NewECDHEExchangeWithRand creates an ECDHEExchange that reads from rnd instead of crypto/rand.Reader. If rnd is nil, crypto/rand.Reader is used.
type Gost2018Exchange ¶
type Gost2018Exchange struct {
// contains filtered or unexported fields
}
Gost2018Exchange implements the Exchange interface for GOST 2018 key exchange (draft-smyshlyaev-tls12-gost-suites, suites 0xC100 / 0xC101).
The exchange generates an ephemeral GOST R 34.10-2012 keypair, derives the 64-byte key material via KEG2012_256, and wraps the pre-master secret using kexp15 (R 1323565.1.020-2018 §6.3.2). The result is encoded as a PSKeyTransport_gost ASN.1 structure (tmp/engine/gost_asn1.c:70-76).
func NewGost2018Exchange ¶
func NewGost2018Exchange( curve *gost.Curve, spkiAlgo, serverPubRaw []byte, variant Gost2018Variant, randoms []byte, ) (*Gost2018Exchange, error)
NewGost2018Exchange creates a Gost2018Exchange ready to produce a CKE.
curve must be the GOST R 34.10-2012 256-bit curve from the server certificate (resolve via gost.CurveByOID). spkiAlgo is the raw DER of the server cert's SPKI AlgorithmIdentifier (used verbatim in the ephemeral SPKI). serverPubRaw is the 64-byte raw public key. variant selects Kuznyechik or Magma.
randoms is clientRandom || serverRandom (64 bytes). Per OpenSSL ssl/statem/statem_clnt.c:ossl_gost_ukm, the TLS 1.2 GOST 2018 UKM is Streebog-256(clientRandom || serverRandom) — not a fresh random. The server derives the same UKM independently and uses it to unwrap the CKE; if the UKM on the wire differs, `gost_kimp15` returns BAD_MAC and the handshake aborts. Callers may pass nil only for unit tests; production callers from the TLS handshake path must supply the 64-byte concatenation.
rng is injectable for deterministic testing; pass nil to use crypto/rand.Reader.
func (*Gost2018Exchange) ClientKeyExchange ¶
func (e *Gost2018Exchange) ClientKeyExchange(_ []byte) (cke, preMaster []byte, err error)
ClientKeyExchange implements Exchange for GOST 2018 KEX.
serverParams is ignored — the server public key was provided at construction time; GOST 2018 suites do not send a ServerKeyExchange message.
Orchestration reference: tmp/engine/gost_ec_keyx.c:413-551 (pkey_gost2018_encrypt).
type Gost2018Variant ¶
type Gost2018Variant int
Gost2018Variant selects the block cipher used for kexp15 key transport. Mirrors gost.KexpVariant but lives in ke for the public-surface Export.
const ( // Variant2018Kuznyechik uses Kuznyechik (128-bit block, iv_len=8, mac_len=16). // Corresponds to TLS suite 0xC100. Variant2018Kuznyechik Gost2018Variant = iota // Variant2018Magma uses Magma (64-bit block, iv_len=4, mac_len=8). // Corresponds to TLS suite 0xC101. Variant2018Magma )
type RSAExchange ¶
type RSAExchange struct {
// contains filtered or unexported fields
}
RSAExchange implements the RSA key exchange for TLS 1.2 (RFC 5246 §7.4.7.1).
The server public key is loaded at construction time (from the server certificate). There is no ServerKeyExchange message for RSA key exchange. ServerParams passed to ClientKeyExchange is ignored; pass nil.
Pre-master secret: 48 bytes with version prefix {0x03, 0x03} followed by 46 random bytes.
ClientKeyExchange body (cke): per RFC 5246 §7.4.7.1, a uint16 big-endian length prefix followed by the PKCS#1 v1.5 encrypted pre-master secret. Its length is 2 + modulus bytes (e.g. 258 bytes for RSA-2048).
func NewRSAExchange ¶
func NewRSAExchange(pub *rsa.PublicKey) *RSAExchange
NewRSAExchange creates an RSAExchange with the server's RSA public key. pub must not be nil.
func (*RSAExchange) ClientKeyExchange ¶
func (r *RSAExchange) ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)
ClientKeyExchange generates a 48-byte pre-master secret with version prefix {0x03, 0x03}, encrypts it with the server's RSA public key using PKCS#1 v1.5, and returns the encrypted bytes as the ClientKeyExchange body.
serverParams is ignored (RSA key exchange has no ServerKeyExchange); pass nil.
type VKOGost2001Exchange ¶
type VKOGost2001Exchange struct {
// contains filtered or unexported fields
}
VKOGost2001Exchange implements Exchange for GOST2001-GOST89-GOST89 (suite ID 0x0081). It uses GOST R 34.10-2001 VKO key agreement (RFC 4357) combined with CryptoPro key wrap to produce a GOST_KEY_TRANSPORT envelope, matching gost-engine's pkey_GOST_ECcp_encrypt.
The client generates a fresh ephemeral key pair per handshake on the same curve carried by the server's certificate.
func NewVKOGost2001Exchange ¶
func NewVKOGost2001Exchange(curve *gost.Curve, spkiAlgo, pubRaw, ukm []byte) (*VKOGost2001Exchange, error)
NewVKOGost2001Exchange creates a VKOGost2001Exchange that generates a fresh ephemeral key pair on the given curve. curve must match the curve OID from the server certificate (resolve via gost.CurveByOID). spkiAlgo is the DER of the server cert's SPKI AlgorithmIdentifier; it is reused to build the ephemeral key's SPKI inside the GOST_KEY_TRANSPORT envelope. pubRaw is the server's GOST R 34.10-2001 public key from the server certificate SPKI. ukm is derived from client_random (first 8 bytes).
func (*VKOGost2001Exchange) ClientKeyExchange ¶
func (e *VKOGost2001Exchange) ClientKeyExchange(_ []byte) (cke []byte, preMaster []byte, err error)
ClientKeyExchange implements Exchange for VKO2001.
serverParams is ignored (GOST suites have no ServerKeyExchange; the server public key was provided at construction time via pubRaw).
Produces a GOST_KEY_TRANSPORT-wrapped ClientKeyExchange body per RFC 9189 §4.1 and gost-engine's pkey_GOST_ECcp_encrypt (tmp/engine/gost_ec_keyx.c:277-407). The 32-byte premaster is a fresh random value wrapped via CryptoPro key wrap under the VKO2001-derived shared key (CryptoPro-A S-box); the wrap output goes into GOST_KEY_INFO, and the ephemeral public key + UKM go into GOST_KEY_AGREEMENT_INFO.
type VKOGost2012_256Exchange ¶
type VKOGost2012_256Exchange struct {
// contains filtered or unexported fields
}
VKOGost2012_256Exchange implements Exchange for GOST2012-GOST8912-GOST8912 (suite IDs 0xFF85 / 0xC102). It uses GOST R 34.10-2012 VKO with 256-bit KEK (RFC 7836) on the curve carried by the server certificate. Observed curves in Tarantool-EE fixtures include id-GostR3410-2001-CryptoPro-A (256-bit) for GOST2012-256 certificates; the 512-bit paramSetA may also appear.
func NewVKOGost2012_256Exchange ¶
func NewVKOGost2012_256Exchange(curve *gost.Curve, spkiAlgo, pubRaw, ukm []byte) (*VKOGost2012_256Exchange, error)
NewVKOGost2012_256Exchange creates a VKOGost2012_256Exchange with a fresh ephemeral key on the given curve. curve must match the server certificate's CurveOID (resolve via gost.CurveByOID). spkiAlgo is the DER of the server cert's SPKI AlgorithmIdentifier (x509gost.Certificate.SPKIAlgorithmDER); it is reused to build the ephemeral key's SPKI inside the GOST_KEY_TRANSPORT envelope. pubRaw is the server's public key bytes. ukm is derived from client_random (first 8 bytes).
func (*VKOGost2012_256Exchange) ClientKeyExchange ¶
func (e *VKOGost2012_256Exchange) ClientKeyExchange(_ []byte) (cke []byte, preMaster []byte, err error)
ClientKeyExchange implements Exchange for VKO2012_256.
Produces a GOST_KEY_TRANSPORT-wrapped ClientKeyExchange body per RFC 9189 §4.1 and gost-engine's pkey_GOST_ECcp_encrypt. The 32-byte premaster is a fresh random value wrapped via CryptoPro key wrap under the VKO-derived shared key; the wrap output goes into GOST_KEY_INFO, and the ephemeral public key + UKM go into GOST_KEY_AGREEMENT_INFO.