Explorar o código

Switched HTTP authentication to go-ntlm library, added a method to generate type 1 messages for NTLM handshake to the library

Eugene Fryntov %!s(int64=10) %!d(string=hai) anos
pai
achega
c2119e5f31

+ 27 - 8
psiphon/upstreamproxy/auth_ntlm.go

@@ -2,17 +2,28 @@ package upstreamproxy
 
 import (
 	"encoding/base64"
-	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/upstreamproxy/ntlm"
+	"errors"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/upstreamproxy/go-ntlm/ntlm"
 	"net/http"
 	"strings"
 )
 
 func ntlmAuthenticate(req *http.Request, challenge, username, password string) error {
+	err := errors.New("NTLM authentication unknown error")
+	var ntlmMsg []byte
+
+	session, err := ntlm.CreateClientSession(ntlm.Version2, ntlm.ConnectionOrientedMode)
+	if err != nil {
+		return err
+	}
 	if challenge == "" {
 		//generate TYPE 1 message
-		type1Msg := ntlm.Negotiate()
-		req.Header.Set("Proxy-Authorization", base64.StdEncoding.EncodeToString(type1Msg))
-		return nil
+		negotiate, err := session.GenerateNegotiateMessage()
+		if err != nil {
+			return err
+		}
+		ntlmMsg = negotiate.Bytes()
+		err = nil
 	} else {
 		// Parse username for domain in form DOMAIN\username
 		var NTDomain, NTUser string
@@ -24,15 +35,23 @@ func ntlmAuthenticate(req *http.Request, challenge, username, password string) e
 			NTDomain = ""
 			NTUser = username
 		}
-		chlg, err := base64.StdEncoding.DecodeString(challenge)
+		challengeBytes, err := base64.StdEncoding.DecodeString(challenge)
+		if err != nil {
+			return err
+		}
+		session.SetUserInfo(NTUser, password, NTDomain)
+		ntlmChallenge, err := ntlm.ParseChallengeMessage(challengeBytes)
 		if err != nil {
 			return err
 		}
-		type3Msg, err := ntlm.Authenticate(chlg, NTDomain, NTUser, password)
+		session.ProcessChallengeMessage(ntlmChallenge)
+		authenticate, err := session.GenerateAuthenticateMessage()
 		if err != nil {
 			return err
 		}
-		req.Header.Set("Proxy-Authorization", base64.StdEncoding.EncodeToString(type3Msg))
-		return nil
+		ntlmMsg = authenticate.Bytes()
+		err = nil
 	}
+	req.Header.Set("Proxy-Authorization", "NTLM "+base64.StdEncoding.EncodeToString(ntlmMsg))
+	return err
 }

+ 47 - 1
psiphon/upstreamproxy/go-ntlm/ntlm/message_negotiate.go

@@ -2,9 +2,25 @@
 
 package ntlm
 
+import (
+	"bytes"
+	"encoding/binary"
+)
+
+//Supported negotiate flags
+const (
+	NEGOTIATE_FLAG_REQUEST_NTLMv1           = 0x00000200
+	NEGOTIATE_FLAG_REQUEST_NTLM2_SESSION    = 0x00080000
+	NEGOTIATE_FLAG_REQUEST_VERSION          = 0x02000000
+	NEGOTIATE_FLAG_REQUEST_ALWAYS_SIGN      = 0x00008000
+	NEGOTIATE_FLAG_REQUEST_128BIT_KEY_EXCH  = 0x20000000
+	NEGOTIATE_FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000
+	NEGOTIATE_FLAG_REQUEST_UNICODE_ENCODING = 0x00000001
+)
+
 type NegotiateMessage struct {
 	// All bytes of the message
-	Bytes []byte
+	// Bytes []byte
 
 	// sig - 8 bytes
 	Signature []byte
@@ -25,3 +41,33 @@ type NegotiateMessage struct {
 	Payload       []byte
 	PayloadOffset int
 }
+
+func (nm *NegotiateMessage) Bytes() []byte {
+	//Domain and Workstation payload are not supported
+	messageLen := 40
+
+	messageBytes := make([]byte, 0, messageLen)
+	buffer := bytes.NewBuffer(messageBytes)
+
+	//Signature 8
+	buffer.Write(nm.Signature) //0
+	//MessageType 4
+	binary.Write(buffer, binary.LittleEndian, nm.MessageType) //8
+	//Flags 4
+	binary.Write(buffer, binary.LittleEndian, nm.NegotiateFlags) //12
+	//DomainLen 2
+	binary.Write(buffer, binary.LittleEndian, uint16(0))
+	//DomainMaxLen == DomainLen 2
+	binary.Write(buffer, binary.LittleEndian, uint16(0))
+	//DomainOffset 4
+	binary.Write(buffer, binary.LittleEndian, uint32(messageLen))
+	//WorkstationLen 2
+	binary.Write(buffer, binary.LittleEndian, uint16(0))
+	//WorkstationMaxLen == WorkstationLen 2
+	binary.Write(buffer, binary.LittleEndian, uint16(0))
+	//WorkstationOffset 4
+	binary.Write(buffer, binary.LittleEndian, uint32(40))
+	//VersionStruct  1 + 1 + 2 + 1 + 1 + 1 + 1 = 8
+	buffer.Write(nm.Version.Bytes())
+	return buffer.Bytes()
+}

+ 23 - 7
psiphon/upstreamproxy/go-ntlm/ntlm/ntlmv2.go

@@ -238,14 +238,13 @@ func (n *V2ServerSession) ProcessAuthenticateMessage(am *AuthenticateMessage) (e
 		return err
 	}
 
-
 	if am.Version == nil {
-        //UGH not entirely sure how this could possibly happen, going to put this in for now
-        //TODO investigate if this ever is really happening
-        am.Version = &VersionStruct{ProductMajorVersion: uint8(5), ProductMinorVersion: uint8(1), ProductBuild: uint16(2600), NTLMRevisionCurrent: uint8(15)}
+		//UGH not entirely sure how this could possibly happen, going to put this in for now
+		//TODO investigate if this ever is really happening
+		am.Version = &VersionStruct{ProductMajorVersion: uint8(5), ProductMinorVersion: uint8(1), ProductBuild: uint16(2600), NTLMRevisionCurrent: uint8(15)}
 
-        l4g.Error("Nil version in ntlmv2")
-    }
+		l4g.Error("Nil version in ntlmv2")
+	}
 
 	err = n.calculateKeys(am.Version.NTLMRevisionCurrent)
 	if err != nil {
@@ -289,7 +288,24 @@ type V2ClientSession struct {
 }
 
 func (n *V2ClientSession) GenerateNegotiateMessage() (nm *NegotiateMessage, err error) {
-	return nil, nil
+	nm = new(NegotiateMessage)
+	nm.Signature = []byte("NTLMSSP\x00")
+	nm.MessageType = uint32(1)
+	nm.NegotiateFlags = NEGOTIATE_FLAG_REQUEST_NTLMv1 |
+		NEGOTIATE_FLAG_REQUEST_NTLM2_SESSION |
+		NEGOTIATE_FLAG_REQUEST_VERSION |
+		NEGOTIATE_FLAG_REQUEST_ALWAYS_SIGN |
+		NEGOTIATE_FLAG_REQUEST_128BIT_KEY_EXCH |
+		NEGOTIATE_FLAG_REQUEST_56BIT_ENCRYPTION |
+		NEGOTIATE_FLAG_REQUEST_UNICODE_ENCODING
+
+	nm.Version = &VersionStruct{ProductMajorVersion: 0x05,
+		ProductMinorVersion: 0x01,
+		ProductBuild:        0x280a,
+		Reserved:            []byte{0x00, 0x00, 0x00},
+		NTLMRevisionCurrent: 0x0f,
+	}
+	return nm, nil
 }
 
 func (n *V2ClientSession) ProcessChallengeMessage(cm *ChallengeMessage) (err error) {