Skip to content

Commit

Permalink
Fix: SSH KEX randomization bugs
Browse files Browse the repository at this point in the history
- Ensure randomization doesn't result in no actual KEX algorithms

- Use the correct starting value when mirroring peer randomization

- When patching a non-match, always use an actual KEX algorithm
  • Loading branch information
rod-hynes committed Jan 15, 2024
1 parent c86926a commit 8a9ab04
Showing 1 changed file with 46 additions and 5 deletions.
51 changes: 46 additions & 5 deletions psiphon/common/crypto/ssh/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"sync"

// [Psiphon]

"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
)

Expand Down Expand Up @@ -601,8 +602,6 @@ func (t *handshakeTransport) sendKexInit() error {

if t.config.KEXPRNGSeed != nil {

PRNG := prng.NewPRNGWithSeed(t.config.KEXPRNGSeed)

permute := func(PRNG *prng.PRNG, list []string) []string {
newList := make([]string, len(list))
perm := PRNG.Perm(len(list))
Expand Down Expand Up @@ -633,7 +632,33 @@ func (t *handshakeTransport) sendKexInit() error {
return list
}

msg.KexAlgos = truncate(PRNG, permute(PRNG, msg.KexAlgos))
firstKexAlgo := func(kexAlgos []string) (string, bool) {
for _, kexAlgo := range kexAlgos {
switch kexAlgo {
case "ext-info-c",
"kex-strict-c-v00@openssh.com",
"kex-strict-s-v00@openssh.com":
// These extensions are not KEX algorithms
default:
return kexAlgo, true
}
}
return "", false
}

selectKexAlgos := func(PRNG *prng.PRNG, kexAlgos []string) []string {
kexAlgos = truncate(PRNG, permute(PRNG, kexAlgos))

// Ensure an actual KEX algorithm is always selected
if _, ok := firstKexAlgo(kexAlgos); ok {
return kexAlgos
}
return retain(PRNG, kexAlgos, permute(PRNG, preferredKexAlgos)[0])
}

PRNG := prng.NewPRNGWithSeed(t.config.KEXPRNGSeed)

msg.KexAlgos = selectKexAlgos(PRNG, msg.KexAlgos)
ciphers := truncate(PRNG, permute(PRNG, msg.CiphersClientServer))
msg.CiphersClientServer = ciphers
msg.CiphersServerClient = ciphers
Expand Down Expand Up @@ -663,9 +688,25 @@ func (t *handshakeTransport) sendKexInit() error {

PeerPRNG := prng.NewPRNGWithSeed(t.config.PeerKEXPRNGSeed)

peerKexAlgos := truncate(PeerPRNG, permute(PeerPRNG, supportedKexAlgos))
// Note that only the client sends "ext-info-c"
// and "kex-strict-c-v00@openssh.com" and only the server
// sends "kex-strict-s-v00@openssh.com", so these will never
// match and do not need to be filtered out before findCommon.
//
// The following assumes that the server always starts with the
// default preferredKexAlgos along with
// "kex-strict-s-v00@openssh.com" appended before randomizing.

serverKexAlgos := append(
append([]string(nil), preferredKexAlgos...),
"kex-strict-s-v00@openssh.com")

peerKexAlgos := selectKexAlgos(PeerPRNG, serverKexAlgos)

if _, err := findCommon("", msg.KexAlgos, peerKexAlgos); err != nil {
msg.KexAlgos = retain(PRNG, msg.KexAlgos, peerKexAlgos[0])
if kexAlgo, ok := firstKexAlgo(peerKexAlgos); ok {
msg.KexAlgos = retain(PRNG, msg.KexAlgos, kexAlgo)
}
}

peerCiphers := truncate(PeerPRNG, permute(PeerPRNG, preferredCiphers))
Expand Down

0 comments on commit 8a9ab04

Please sign in to comment.