Преглед изворни кода

Use SSH_PADDING_MULTIPLE with legacy SSH clients

Rod Hynes пре 7 година
родитељ
комит
3e56b980cc
1 измењених фајлова са 51 додато и 25 уклоњено
  1. 51 25
      psiphon/common/obfuscator/obfuscatedSshConn.go

+ 51 - 25
psiphon/common/obfuscator/obfuscatedSshConn.go

@@ -35,6 +35,7 @@ const (
 	SSH_MAX_PACKET_LENGTH      = 256 * 1024 // OpenSSH max packet length
 	SSH_MSG_NEWKEYS            = 21
 	SSH_MAX_PADDING_LENGTH     = 255 // RFC 4253 sec. 6
+	SSH_PADDING_MULTIPLE       = 16  // Default cipher block size
 )
 
 // ObfuscatedSshConn wraps a Conn and applies the obfuscated SSH protocol
@@ -64,6 +65,7 @@ type ObfuscatedSshConn struct {
 	readBuffer      *bytes.Buffer
 	writeBuffer     *bytes.Buffer
 	transformBuffer *bytes.Buffer
+	legacyPadding   bool
 }
 
 type ObfuscatedSshConnMode int
@@ -237,6 +239,9 @@ func (conn *ObfuscatedSshConn) readAndTransform(buffer []byte) (int, error) {
 					return 0, common.ContextError(err)
 				}
 				if bytes.HasPrefix(conn.readBuffer.Bytes(), []byte("SSH-")) {
+					if bytes.Contains(conn.readBuffer.Bytes(), []byte("Ganymed")) {
+						conn.legacyPadding = true
+					}
 					break
 				}
 				// Discard extra line
@@ -362,7 +367,7 @@ func (conn *ObfuscatedSshConn) transformAndWrite(buffer []byte) error {
 
 	case OBFUSCATION_WRITE_STATE_KEX_PACKETS:
 		hasMsgNewKeys, err := extractSshPackets(
-			conn.writeBuffer, conn.transformBuffer)
+			conn.legacyPadding, conn.writeBuffer, conn.transformBuffer)
 		if err != nil {
 			return common.ContextError(err)
 		}
@@ -518,7 +523,9 @@ func extractSshIdentificationLine(writeBuffer, transformBuffer *bytes.Buffer) bo
 	return false
 }
 
-func extractSshPackets(writeBuffer, transformBuffer *bytes.Buffer) (bool, error) {
+func extractSshPackets(
+	legacyPadding bool, writeBuffer, transformBuffer *bytes.Buffer) (bool, error) {
+
 	hasMsgNewKeys := false
 	for writeBuffer.Len() >= SSH_PACKET_PREFIX_LENGTH {
 
@@ -547,34 +554,53 @@ func extractSshPackets(writeBuffer, transformBuffer *bytes.Buffer) (bool, error)
 		transformedPacket := transformBuffer.Bytes()[transformedPacketOffset:]
 
 		// Padding transformation
-		// This does not satisfy RFC 4253 sec. 6 constraints:
-		// - The goal is to vary packet sizes as much as possible.
-		// - We implement both the client and server sides and both sides accept
-		//   less constrained paddings (for plaintext packets).
-		possibleExtraPaddingLength := (SSH_MAX_PADDING_LENGTH - paddingLength)
-		if possibleExtraPaddingLength > 0 {
-
-			// TODO: proceed without padding if MakeSecureRandom* fails?
-
-			// selectedPadding is integer in range [0, possiblePadding + 1)
-			extraPaddingLength, err := common.MakeSecureRandomInt(
-				possibleExtraPaddingLength + 1)
-			if err != nil {
-				return false, common.ContextError(err)
-			}
-			extraPadding, err := common.MakeSecureRandomBytes(extraPaddingLength)
-			if err != nil {
-				return false, common.ContextError(err)
+
+		extraPaddingLength := 0
+
+		if !legacyPadding {
+			// This does not satisfy RFC 4253 sec. 6 constraints:
+			// - The goal is to vary packet sizes as much as possible.
+			// - We implement both the client and server sides and both sides accept
+			//   less constrained paddings (for plaintext packets).
+			possibleExtraPaddingLength := (SSH_MAX_PADDING_LENGTH - paddingLength)
+			if possibleExtraPaddingLength > 0 {
+
+				// TODO: proceed without padding if MakeSecureRandom* fails?
+
+				// extraPaddingLength is integer in range [0, possiblePadding + 1)
+				extraPaddingLength, err = common.MakeSecureRandomInt(
+					possibleExtraPaddingLength + 1)
+				if err != nil {
+					return false, common.ContextError(err)
+				}
 			}
+		} else {
+			// See RFC 4253 sec. 6 for constraints
+			possiblePaddings := (SSH_MAX_PADDING_LENGTH - paddingLength) / SSH_PADDING_MULTIPLE
+			if possiblePaddings > 0 {
 
-			setSshPacketPrefix(
-				transformedPacket,
-				packetLength+extraPaddingLength,
-				paddingLength+extraPaddingLength)
+				// selectedPadding is integer in range [0, possiblePaddings)
+				selectedPadding, err := common.MakeSecureRandomInt(possiblePaddings)
+				if err != nil {
+					return false, common.ContextError(err)
+				}
+				extraPaddingLength = selectedPadding * SSH_PADDING_MULTIPLE
+			}
+		}
 
-			transformBuffer.Write(extraPadding)
+		extraPadding, err := common.MakeSecureRandomBytes(extraPaddingLength)
+		if err != nil {
+			return false, common.ContextError(err)
 		}
+
+		setSshPacketPrefix(
+			transformedPacket,
+			packetLength+extraPaddingLength,
+			paddingLength+extraPaddingLength)
+
+		transformBuffer.Write(extraPadding)
 	}
+
 	return hasMsgNewKeys, nil
 }