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:
+157
-44
@@ -15,9 +15,10 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
errModernPSKSecretEmpty = errors.New("modern psk secret must be non-empty")
|
||||
errModernPSKPayload = errors.New("invalid modern psk payload")
|
||||
errModernPSKRequired = errors.New("modern psk is required: call UseModernPSKClient/UseModernPSKServer or set a transport key before Connect/Listen")
|
||||
errModernPSKSecretEmpty = errors.New("modern psk secret must be non-empty")
|
||||
errModernPSKPayload = errors.New("invalid modern psk payload")
|
||||
errModernPSKRequired = errors.New("transport security is required: call UseModernPSKClient/UseModernPSKServer, UsePSKOverExternalTransportClient/Server, or set a transport key before Connect/Listen")
|
||||
errModernPSKForwardSecrecyUnsupported = errors.New("forward secrecy is unsupported for external transport protection")
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -47,9 +48,10 @@ var modernPSKPayloadPool sync.Pool
|
||||
// The current profile derives a 32-byte transport key with Argon2id and uses
|
||||
// AES-GCM with a per-codec nonce prefix plus a per-message counter.
|
||||
type ModernPSKOptions struct {
|
||||
Salt []byte
|
||||
AAD []byte
|
||||
Argon2Params starcrypto.Argon2Params
|
||||
Salt []byte
|
||||
AAD []byte
|
||||
Argon2Params starcrypto.Argon2Params
|
||||
RequireForwardSecrecy bool
|
||||
}
|
||||
|
||||
// DefaultModernPSKOptions returns the recommended settings for the current
|
||||
@@ -78,24 +80,17 @@ func defaultModernPSKTransportBundle() modernPSKTransportBundle {
|
||||
// Argon2id, and switches message protection to AES-GCM. Configure it before
|
||||
// calling Connect/ConnectTimeout.
|
||||
func UseModernPSKClient(c Client, sharedSecret []byte, opts *ModernPSKOptions) error {
|
||||
key, aad, err := deriveModernPSKKey(sharedSecret, opts)
|
||||
managed, err := deriveModernPSKProtectionProfile(sharedSecret, opts, ProtectionManaged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transport := buildModernPSKTransportBundle(aad)
|
||||
runtime, err := newModernPSKCodecRuntime(key, aad)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.SetSecretKey(key)
|
||||
c.SetMsgEn(transport.msgEn)
|
||||
c.SetMsgDe(transport.msgDe)
|
||||
if client, ok := c.(*ClientCommon); ok {
|
||||
client.fastStreamEncode = transport.fastStreamEncode
|
||||
client.fastBulkEncode = transport.fastBulkEncode
|
||||
client.fastPlainEncode = transport.fastPlainEncode
|
||||
client.modernPSKRuntime = runtime
|
||||
client.configureClientSecurityProfiles(AuthPSK, ProtectionManaged, managed, managed, opts != nil && opts.RequireForwardSecrecy)
|
||||
return nil
|
||||
}
|
||||
c.SetSecretKey(managed.secretKey)
|
||||
c.SetMsgEn(managed.msgEn)
|
||||
c.SetMsgDe(managed.msgDe)
|
||||
c.SetSkipExchangeKey(true)
|
||||
return nil
|
||||
}
|
||||
@@ -106,24 +101,95 @@ func UseModernPSKClient(c Client, sharedSecret []byte, opts *ModernPSKOptions) e
|
||||
// It derives a transport key with Argon2id and switches message protection to
|
||||
// AES-GCM. Configure it before calling Listen.
|
||||
func UseModernPSKServer(s Server, sharedSecret []byte, opts *ModernPSKOptions) error {
|
||||
key, aad, err := deriveModernPSKKey(sharedSecret, opts)
|
||||
managed, err := deriveModernPSKProtectionProfile(sharedSecret, opts, ProtectionManaged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
transport := buildModernPSKTransportBundle(aad)
|
||||
runtime, err := newModernPSKCodecRuntime(key, aad)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.SetSecretKey(key)
|
||||
s.SetDefaultCommEncode(transport.msgEn)
|
||||
s.SetDefaultCommDecode(transport.msgDe)
|
||||
if server, ok := s.(*ServerCommon); ok {
|
||||
server.defaultFastStreamEncode = transport.fastStreamEncode
|
||||
server.defaultFastBulkEncode = transport.fastBulkEncode
|
||||
server.defaultFastPlainEncode = transport.fastPlainEncode
|
||||
server.defaultModernPSKRuntime = runtime
|
||||
server.configureServerSecurityProfiles(AuthPSK, ProtectionManaged, managed, managed, opts != nil && opts.RequireForwardSecrecy)
|
||||
return nil
|
||||
}
|
||||
s.SetSecretKey(managed.secretKey)
|
||||
s.SetDefaultCommEncode(managed.msgEn)
|
||||
s.SetDefaultCommDecode(managed.msgDe)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UsePSKOverExternalTransportClient authenticates bootstrap with PSK and then
|
||||
// trusts the external channel for steady-state payload protection.
|
||||
func UsePSKOverExternalTransportClient(c Client, sharedSecret []byte, opts *ModernPSKOptions) error {
|
||||
if opts != nil && opts.RequireForwardSecrecy {
|
||||
return errModernPSKForwardSecrecyUnsupported
|
||||
}
|
||||
bootstrap, err := deriveModernPSKProtectionProfile(sharedSecret, opts, ProtectionManaged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
steady := buildExternalProtectionProfile(bootstrap.secretKey)
|
||||
if client, ok := c.(*ClientCommon); ok {
|
||||
client.configureClientSecurityProfiles(AuthPSK, ProtectionExternal, bootstrap, steady, false)
|
||||
return nil
|
||||
}
|
||||
c.SetSecretKey(bootstrap.secretKey)
|
||||
c.SetMsgEn(bootstrap.msgEn)
|
||||
c.SetMsgDe(bootstrap.msgDe)
|
||||
c.SetSkipExchangeKey(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UsePSKOverExternalTransportServer authenticates bootstrap with PSK and then
|
||||
// trusts the external channel for steady-state payload protection.
|
||||
func UsePSKOverExternalTransportServer(s Server, sharedSecret []byte, opts *ModernPSKOptions) error {
|
||||
if opts != nil && opts.RequireForwardSecrecy {
|
||||
return errModernPSKForwardSecrecyUnsupported
|
||||
}
|
||||
bootstrap, err := deriveModernPSKProtectionProfile(sharedSecret, opts, ProtectionManaged)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
steady := buildExternalProtectionProfile(bootstrap.secretKey)
|
||||
if server, ok := s.(*ServerCommon); ok {
|
||||
server.configureServerSecurityProfiles(AuthPSK, ProtectionExternal, bootstrap, steady, false)
|
||||
return nil
|
||||
}
|
||||
s.SetSecretKey(bootstrap.secretKey)
|
||||
s.SetDefaultCommEncode(bootstrap.msgEn)
|
||||
s.SetDefaultCommDecode(bootstrap.msgDe)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UseNestedSecurityClient keeps notify transport protection enabled even when
|
||||
// the physical connection is already protected by an outer trusted channel.
|
||||
func UseNestedSecurityClient(c Client, sharedSecret []byte, opts *ModernPSKOptions) error {
|
||||
managed, err := deriveModernPSKProtectionProfile(sharedSecret, opts, ProtectionNested)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if client, ok := c.(*ClientCommon); ok {
|
||||
client.configureClientSecurityProfiles(AuthPSK, ProtectionNested, managed, managed, opts != nil && opts.RequireForwardSecrecy)
|
||||
return nil
|
||||
}
|
||||
c.SetSecretKey(managed.secretKey)
|
||||
c.SetMsgEn(managed.msgEn)
|
||||
c.SetMsgDe(managed.msgDe)
|
||||
c.SetSkipExchangeKey(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// UseNestedSecurityServer keeps notify transport protection enabled even when
|
||||
// the physical connection is already protected by an outer trusted channel.
|
||||
func UseNestedSecurityServer(s Server, sharedSecret []byte, opts *ModernPSKOptions) error {
|
||||
managed, err := deriveModernPSKProtectionProfile(sharedSecret, opts, ProtectionNested)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if server, ok := s.(*ServerCommon); ok {
|
||||
server.configureServerSecurityProfiles(AuthPSK, ProtectionNested, managed, managed, opts != nil && opts.RequireForwardSecrecy)
|
||||
return nil
|
||||
}
|
||||
s.SetSecretKey(managed.secretKey)
|
||||
s.SetDefaultCommEncode(managed.msgEn)
|
||||
s.SetDefaultCommDecode(managed.msgDe)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -132,15 +198,22 @@ func UseModernPSKServer(s Server, sharedSecret []byte, opts *ModernPSKOptions) e
|
||||
//
|
||||
// It is kept only as an explicit fallback path for existing deployments.
|
||||
func UseLegacySecurityClient(c Client) {
|
||||
if client, ok := c.(*ClientCommon); ok {
|
||||
client.clearClientSecurityProfiles()
|
||||
client.setClientTransportProtectionProfile(transportProtectionProfile{
|
||||
mode: ProtectionManaged,
|
||||
msgEn: defaultMsgEn,
|
||||
msgDe: defaultMsgDe,
|
||||
secretKey: bytes.Clone(defaultAesKey),
|
||||
})
|
||||
client.securityReadyCheck = false
|
||||
client.skipKeyExchange = false
|
||||
client.handshakeRsaPubKey = bytes.Clone(defaultRsaPubKey)
|
||||
return
|
||||
}
|
||||
c.SetSecretKey(bytes.Clone(defaultAesKey))
|
||||
c.SetMsgEn(defaultMsgEn)
|
||||
c.SetMsgDe(defaultMsgDe)
|
||||
if client, ok := c.(*ClientCommon); ok {
|
||||
client.fastStreamEncode = nil
|
||||
client.fastBulkEncode = nil
|
||||
client.fastPlainEncode = nil
|
||||
client.modernPSKRuntime = nil
|
||||
}
|
||||
c.SetSkipExchangeKey(false)
|
||||
c.SetRsaPubKey(bytes.Clone(defaultRsaPubKey))
|
||||
}
|
||||
@@ -150,15 +223,21 @@ func UseLegacySecurityClient(c Client) {
|
||||
//
|
||||
// It is kept only as an explicit fallback path for existing deployments.
|
||||
func UseLegacySecurityServer(s Server) {
|
||||
if server, ok := s.(*ServerCommon); ok {
|
||||
server.clearServerSecurityProfiles()
|
||||
server.setServerDefaultTransportProtectionProfile(transportProtectionProfile{
|
||||
mode: ProtectionManaged,
|
||||
msgEn: defaultMsgEn,
|
||||
msgDe: defaultMsgDe,
|
||||
secretKey: bytes.Clone(defaultAesKey),
|
||||
})
|
||||
server.securityReadyCheck = false
|
||||
server.handshakeRsaKey = bytes.Clone(defaultRsaKey)
|
||||
return
|
||||
}
|
||||
s.SetSecretKey(bytes.Clone(defaultAesKey))
|
||||
s.SetDefaultCommEncode(defaultMsgEn)
|
||||
s.SetDefaultCommDecode(defaultMsgDe)
|
||||
if server, ok := s.(*ServerCommon); ok {
|
||||
server.defaultFastStreamEncode = nil
|
||||
server.defaultFastBulkEncode = nil
|
||||
server.defaultFastPlainEncode = nil
|
||||
server.defaultModernPSKRuntime = nil
|
||||
}
|
||||
s.SetRsaPrivKey(bytes.Clone(defaultRsaKey))
|
||||
}
|
||||
|
||||
@@ -174,6 +253,40 @@ func deriveModernPSKKey(sharedSecret []byte, opts *ModernPSKOptions) ([]byte, []
|
||||
return key, cfg.AAD, nil
|
||||
}
|
||||
|
||||
func deriveModernPSKProtectionProfile(sharedSecret []byte, opts *ModernPSKOptions, mode ProtectionMode) (transportProtectionProfile, error) {
|
||||
key, aad, err := deriveModernPSKKey(sharedSecret, opts)
|
||||
if err != nil {
|
||||
return transportProtectionProfile{}, err
|
||||
}
|
||||
transport := buildModernPSKTransportBundle(aad)
|
||||
runtime, err := newModernPSKCodecRuntime(key, aad)
|
||||
if err != nil {
|
||||
return transportProtectionProfile{}, err
|
||||
}
|
||||
return newTransportProtectionProfile(mode, transport, runtime, key), nil
|
||||
}
|
||||
|
||||
func buildExternalProtectionProfile(secretKey []byte) transportProtectionProfile {
|
||||
return newTransportProtectionProfile(ProtectionExternal, buildExternalTransportBundle(), nil, secretKey)
|
||||
}
|
||||
|
||||
func deriveModernPSKSessionProtectionProfile(base transportProtectionProfile, sessionKey []byte, sessionID []byte) (transportProtectionProfile, error) {
|
||||
aad := bytes.Clone(defaultModernPSKAAD)
|
||||
if base.runtime != nil && len(base.runtime.aad) != 0 {
|
||||
aad = bytes.Clone(base.runtime.aad)
|
||||
}
|
||||
runtime, err := newModernPSKCodecRuntime(sessionKey, aad)
|
||||
if err != nil {
|
||||
return transportProtectionProfile{}, err
|
||||
}
|
||||
profile := newTransportProtectionProfile(base.mode, buildModernPSKTransportBundle(aad), runtime, sessionKey)
|
||||
profile.keyMode = peerAttachKeyModeECDHE
|
||||
profile.sessionID = cloneTransportSessionID(sessionID)
|
||||
profile.forwardSecrecy = true
|
||||
profile.forwardSecrecyFallback = false
|
||||
return profile, nil
|
||||
}
|
||||
|
||||
func normalizeModernPSKOptions(opts *ModernPSKOptions) ModernPSKOptions {
|
||||
cfg := DefaultModernPSKOptions()
|
||||
if opts == nil {
|
||||
|
||||
Reference in New Issue
Block a user