feat(transport): 完成安全架构拆分并收口 stream/bulk 传输优化
- 新增 managed/external/nested 三种传输保护模式 - 新增 peer attach 显式认证、抗重放、channel binding 和可选前向保密协商 - 明确单连接注入与可重拨连接源的语义边界 - 禁止 ConnectByConn 场景下 dedicated bulk 走 sidecar,auto 模式自动回退 shared - 修正 dedicated attach 在 bootstrap/steady profile 切换下的处理逻辑 - 优化 shared bulk super-batch 与批量 framed write 路径 - 降低 stream/bulk fast path 的复制和分发损耗 - 补齐 benchmark、回归测试、运行时快照和 README 文档
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdh"
|
||||
"crypto/hmac"
|
||||
cryptorand "crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
peerAttachECDHEPublicKeySize = 32
|
||||
peerAttachSessionIDSize = 16
|
||||
|
||||
peerAttachKeyModeStatic = "psk-static"
|
||||
peerAttachKeyModeECDHE = "psk-ecdhe"
|
||||
transportKeyModeExternal = "external"
|
||||
)
|
||||
|
||||
var errPeerAttachForwardSecrecyInvalid = errors.New("peer attach forward secrecy is invalid")
|
||||
|
||||
type peerAttachRequestState struct {
|
||||
forwardSecrecy *peerAttachForwardSecrecyClientState
|
||||
}
|
||||
|
||||
type peerAttachForwardSecrecyClientState struct {
|
||||
privateKey *ecdh.PrivateKey
|
||||
publicKey []byte
|
||||
}
|
||||
|
||||
type peerAttachResponseVerifyResult struct {
|
||||
authFallback bool
|
||||
steadyProfile transportProtectionProfile
|
||||
}
|
||||
|
||||
func newPeerAttachForwardSecrecyClientState() (*peerAttachForwardSecrecyClientState, error) {
|
||||
curve := ecdh.X25519()
|
||||
privateKey, err := curve.GenerateKey(cryptorand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
publicKey := privateKey.PublicKey().Bytes()
|
||||
if len(publicKey) != peerAttachECDHEPublicKeySize {
|
||||
return nil, errPeerAttachForwardSecrecyInvalid
|
||||
}
|
||||
return &peerAttachForwardSecrecyClientState{
|
||||
privateKey: privateKey,
|
||||
publicKey: bytes.Clone(publicKey),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func derivePeerAttachForwardSecrecyTransportProfile(base transportProtectionProfile, bootstrapKey []byte, localPrivateKey *ecdh.PrivateKey, peerPublicKey []byte, req peerAttachRequest, resp peerAttachResponse) (transportProtectionProfile, error) {
|
||||
if len(bootstrapKey) == 0 || localPrivateKey == nil || len(peerPublicKey) != peerAttachECDHEPublicKeySize {
|
||||
return transportProtectionProfile{}, errPeerAttachForwardSecrecyInvalid
|
||||
}
|
||||
curve := ecdh.X25519()
|
||||
publicKey, err := curve.NewPublicKey(peerPublicKey)
|
||||
if err != nil {
|
||||
return transportProtectionProfile{}, errPeerAttachForwardSecrecyInvalid
|
||||
}
|
||||
sharedSecret, err := localPrivateKey.ECDH(publicKey)
|
||||
if err != nil {
|
||||
return transportProtectionProfile{}, errPeerAttachForwardSecrecyInvalid
|
||||
}
|
||||
transcriptHash := peerAttachForwardSecrecyTranscriptHash(req, resp)
|
||||
ikm := make([]byte, 0, len(sharedSecret)+len(transcriptHash))
|
||||
ikm = append(ikm, sharedSecret...)
|
||||
ikm = append(ikm, transcriptHash...)
|
||||
prk := hkdfExtractSHA256(bootstrapKey, ikm)
|
||||
sessionKey := hkdfExpandSHA256(prk, []byte("notify/transport/session/v1"), 32)
|
||||
sessionID := hkdfExpandSHA256(prk, []byte("notify/session-id/v1"), peerAttachSessionIDSize)
|
||||
return deriveModernPSKSessionProtectionProfile(base, sessionKey, sessionID)
|
||||
}
|
||||
|
||||
func peerAttachForwardSecrecyTranscriptHash(req peerAttachRequest, resp peerAttachResponse) []byte {
|
||||
buf := make([]byte, 0, 256+len(req.PeerID)+len(resp.PeerID)+len(resp.Error)+len(req.ClientECDHEPublicKey)+len(resp.ServerECDHEPublicKey))
|
||||
buf = appendPeerAttachTranscriptString(buf, "notify/peer-attach/forward-secrecy/v1")
|
||||
buf = binary.BigEndian.AppendUint64(buf, req.Features)
|
||||
buf = appendPeerAttachTranscriptString(buf, req.PeerID)
|
||||
buf = appendPeerAttachTranscriptBytes(buf, req.ClientNonce)
|
||||
buf = appendPeerAttachTranscriptBytes(buf, req.ClientECDHEPublicKey)
|
||||
buf = binary.BigEndian.AppendUint64(buf, resp.Features)
|
||||
buf = appendPeerAttachTranscriptString(buf, resp.PeerID)
|
||||
buf = appendPeerAttachTranscriptBool(buf, resp.Accepted)
|
||||
buf = appendPeerAttachTranscriptBool(buf, resp.Reused)
|
||||
buf = appendPeerAttachTranscriptString(buf, resp.Error)
|
||||
buf = appendPeerAttachTranscriptBytes(buf, resp.ServerNonce)
|
||||
buf = appendPeerAttachTranscriptString(buf, resp.KeyMode)
|
||||
buf = appendPeerAttachTranscriptBytes(buf, resp.ServerECDHEPublicKey)
|
||||
sum := sha256.Sum256(buf)
|
||||
return sum[:]
|
||||
}
|
||||
|
||||
func appendPeerAttachTranscriptBytes(dst []byte, data []byte) []byte {
|
||||
dst = binary.BigEndian.AppendUint32(dst, uint32(len(data)))
|
||||
return append(dst, data...)
|
||||
}
|
||||
|
||||
func appendPeerAttachTranscriptString(dst []byte, value string) []byte {
|
||||
return appendPeerAttachTranscriptBytes(dst, []byte(value))
|
||||
}
|
||||
|
||||
func appendPeerAttachTranscriptBool(dst []byte, value bool) []byte {
|
||||
if value {
|
||||
return append(dst, 1)
|
||||
}
|
||||
return append(dst, 0)
|
||||
}
|
||||
|
||||
func hkdfExtractSHA256(salt []byte, ikm []byte) []byte {
|
||||
mac := hmac.New(sha256.New, salt)
|
||||
_, _ = mac.Write(ikm)
|
||||
return mac.Sum(nil)
|
||||
}
|
||||
|
||||
func hkdfExpandSHA256(prk []byte, info []byte, size int) []byte {
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
out := make([]byte, 0, size)
|
||||
var block []byte
|
||||
for counter := byte(1); len(out) < size; counter++ {
|
||||
mac := hmac.New(sha256.New, prk)
|
||||
if len(block) != 0 {
|
||||
_, _ = mac.Write(block)
|
||||
}
|
||||
_, _ = mac.Write(info)
|
||||
_, _ = mac.Write([]byte{counter})
|
||||
block = mac.Sum(nil)
|
||||
remaining := size - len(out)
|
||||
if remaining > len(block) {
|
||||
remaining = len(block)
|
||||
}
|
||||
out = append(out, block[:remaining]...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user