github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/upstreamproxy/go-ntlm/ntlm/ntlmv2_test.go (about)

     1  //Copyright 2013 Thomson Reuters Global Resources. BSD License please see License file for more information
     2  
     3  package ntlm
     4  
     5  import (
     6  	"bytes"
     7  	"encoding/base64"
     8  	"encoding/hex"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  func checkV2Value(t *testing.T, name string, value []byte, expected string, err error) {
    15  	if err != nil {
    16  		t.Errorf("NTLMv2 %s received error: %s", name, err)
    17  	} else {
    18  		expectedBytes, _ := hex.DecodeString(expected)
    19  		if !bytes.Equal(expectedBytes, value) {
    20  			t.Errorf("NTLMv2 %s is not correct got %s expected %s", name, hex.EncodeToString(value), expected)
    21  		}
    22  	}
    23  }
    24  
    25  func TestNTOWFv2(t *testing.T) {
    26  	result := ntowfv2("User", "Password", "Domain")
    27  	// Sample value from 4.2.4.1.1 in MS-NLMP
    28  	expected, _ := hex.DecodeString("0c868a403bfd7a93a3001ef22ef02e3f")
    29  	if !bytes.Equal(result, expected) {
    30  		t.Errorf("NTOWFv2 is not correct got %s expected %s", hex.EncodeToString(result), "0c868a403bfd7a93a3001ef22ef02e3f")
    31  	}
    32  }
    33  
    34  func TestNTLMv2(t *testing.T) {
    35  	flags := uint32(0)
    36  	flags = NTLMSSP_NEGOTIATE_KEY_EXCH.Set(flags)
    37  	flags = NTLMSSP_NEGOTIATE_56.Set(flags)
    38  	flags = NTLMSSP_NEGOTIATE_128.Set(flags)
    39  	flags = NTLMSSP_NEGOTIATE_VERSION.Set(flags)
    40  	flags = NTLMSSP_NEGOTIATE_TARGET_INFO.Set(flags)
    41  	flags = NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY.Set(flags)
    42  	flags = NTLMSSP_TARGET_TYPE_SERVER.Set(flags)
    43  	flags = NTLMSSP_NEGOTIATE_ALWAYS_SIGN.Set(flags)
    44  	flags = NTLMSSP_NEGOTIATE_NTLM.Set(flags)
    45  	flags = NTLMSSP_NEGOTIATE_SEAL.Set(flags)
    46  	flags = NTLMSSP_NEGOTIATE_SIGN.Set(flags)
    47  	flags = NTLM_NEGOTIATE_OEM.Set(flags)
    48  	flags = NTLMSSP_NEGOTIATE_UNICODE.Set(flags)
    49  
    50  	//	n := new(V2Session)
    51  	//	n.SetUserInfo("User","Password","Domain")
    52  	//	n.NegotiateFlags = flags
    53  	//	n.responseKeyNT, _ = hex.DecodeString("0c868a403bfd7a93a3001ef22ef02e3f")
    54  	//	n.responseKeyLM = n.responseKeyNT
    55  	//	n.clientChallenge, _ = hex.DecodeString("aaaaaaaaaaaaaaaa")
    56  	//	n.serverChallenge, _ = hex.DecodeString("0123456789abcdef")
    57  
    58  	// Encrypted Random Session key
    59  	//c5 da d2 54 4f c9 79 90 94 ce 1c e9 0b c9 d0 3e
    60  
    61  	// Challenge message
    62  	client := new(V2ClientSession)
    63  	client.SetUserInfo("User", "Password", "Domain")
    64  
    65  	challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000")
    66  	challengeMessage, err := ParseChallengeMessage(challengeMessageBytes)
    67  	if err == nil {
    68  		challengeMessage.String()
    69  	} else {
    70  		t.Errorf("Could not parse challenge message: %s", err)
    71  	}
    72  
    73  	err = client.ProcessChallengeMessage(challengeMessage)
    74  	if err != nil {
    75  		t.Errorf("Could not process challenge message: %s", err)
    76  	}
    77  
    78  	server := new(V2ServerSession)
    79  	server.SetUserInfo("User", "Password", "Domain")
    80  	server.serverChallenge = challengeMessage.ServerChallenge
    81  
    82  	// Authenticate message
    83  	r := strings.NewReplacer("\n", "", "\t", "", " ", "")
    84  	authenticateMessageBytes, _ := hex.DecodeString(r.Replace(`
    85  		4e544c4d535350000300000018001800
    86  		6c00000054005400840000000c000c00
    87  		48000000080008005400000010001000
    88  		5c00000010001000d8000000358288e2
    89  		0501280a0000000f44006f006d006100
    90  		69006e00550073006500720043004f00
    91  		4d005000550054004500520086c35097
    92  		ac9cec102554764a57cccc19aaaaaaaa
    93  		aaaaaaaa68cd0ab851e51c96aabc927b
    94  		ebef6a1c010100000000000000000000
    95  		00000000aaaaaaaaaaaaaaaa00000000
    96  		02000c0044006f006d00610069006e00
    97  		01000c00530065007200760065007200
    98  		0000000000000000c5dad2544fc97990
    99  		94ce1ce90bc9d03e`))
   100  
   101  	authenticateMessage, err := ParseAuthenticateMessage(authenticateMessageBytes, 2)
   102  	if err == nil {
   103  		authenticateMessage.String()
   104  	} else {
   105  		t.Errorf("Could not parse authenticate message: %s", err)
   106  	}
   107  
   108  	err = server.ProcessAuthenticateMessage(authenticateMessage)
   109  	if err != nil {
   110  		t.Errorf("Could not process authenticate message: %s", err)
   111  	}
   112  
   113  	checkV2Value(t, "SessionBaseKey", server.sessionBaseKey, "8de40ccadbc14a82f15cb0ad0de95ca3", nil)
   114  	checkV2Value(t, "NTChallengeResponse", server.ntChallengeResponse[0:16], "68cd0ab851e51c96aabc927bebef6a1c", nil)
   115  	checkV2Value(t, "LMChallengeResponse", server.lmChallengeResponse, "86c35097ac9cec102554764a57cccc19aaaaaaaaaaaaaaaa", nil)
   116  
   117  	checkV2Value(t, "client seal key", server.ClientSealingKey, "59f600973cc4960a25480a7c196e4c58", nil)
   118  	checkV2Value(t, "client signing key", server.ClientSigningKey, "4788dc861b4782f35d43fd98fe1a2d39", nil)
   119  
   120  	// Have the server generate an initial challenge message
   121  	challenge, err := server.GenerateChallengeMessage()
   122  	challenge.String()
   123  
   124  	// Have the client process this server challenge message
   125  	client = new(V2ClientSession)
   126  	client.SetUserInfo("User", "Password", "Domain")
   127  	err = client.ProcessChallengeMessage(challenge)
   128  	if err != nil {
   129  		t.Errorf("Could not process server generated challenge message: %s", err)
   130  	}
   131  	// TODO: we should be able to use the ntlm library end to end to make sure
   132  	// that Mac, VerifyMac
   133  
   134  	// // the client should be able to verify the server's mac
   135  	// sig := "<NTLM><foo><bar>"
   136  	// mac, err := server.Mac([]byte(sig), 100)
   137  	// if err != nil {
   138  	// 	t.Errorf("Could not generate a mac for %s", sig)
   139  	// }
   140  	// matches, err := client.VerifyMac([]byte(sig), mac, 100)
   141  	// if err != nil {
   142  	// 	t.Errorf("Could not verify mac for %s (mac = %v)", sig, mac)
   143  	// }
   144  	// if !matches {
   145  	// 	t.Errorf("Server's Mac couldn't be verified by client")
   146  	// }
   147  
   148  	// mac, err = client.Mac([]byte(sig), 100)
   149  	// if err != nil {
   150  	// 	t.Errorf("Could not generate a mac for %s", sig)
   151  	// }
   152  	// matches, err = server.VerifyMac([]byte(sig), mac, 100)
   153  	// if err != nil {
   154  	// 	t.Errorf("Could not verify mac for %s (mac = %v)", sig, mac)
   155  	// }
   156  	// if !matches {
   157  	// 	t.Errorf("Client's Mac couldn't be verified by server")
   158  	// }
   159  }
   160  
   161  func TestNTLMv2WithDomain(t *testing.T) {
   162  	authenticateMessage := "TlRMTVNTUAADAAAAGAAYALYAAADSANIAzgAAADQANABIAAAAIAAgAHwAAAAaABoAnAAAABAAEACgAQAAVYKQQgUCzg4AAAAPYQByAHIAYQB5ADEAMgAuAG0AcwBnAHQAcwB0AC4AcgBlAHUAdABlAHIAcwAuAGMAbwBtAHUAcwBlAHIAcwB0AHIAZQBzAHMAMQAwADAAMAAwADgATgBZAEMAVgBBADEAMgBTADIAQwBNAFMAQQBPYrLjU4h0YlWZeEoNvTJtBQMnnJuAeUwsP+vGmAHNRBpgZ+4ChQLqAQEAAAAAAACPFEIFjx7OAQUDJ5ybgHlMAAAAAAIADgBSAEUAVQBUAEUAUgBTAAEAHABVAEsAQgBQAC0AQwBCAFQAUgBNAEYARQAwADYABAAWAFIAZQB1AHQAZQByAHMALgBuAGUAdAADADQAdQBrAGIAcAAtAGMAYgB0AHIAbQBmAGUAMAA2AC4AUgBlAHUAdABlAHIAcwAuAG4AZQB0AAUAFgBSAGUAdQB0AGUAcgBzAC4AbgBlAHQAAAAAAAAAAAANuvnqD3K88ZpjkLleL0NW"
   163  
   164  	server := new(V2ServerSession)
   165  	server.SetUserInfo("blahblah", "Welcome1", "blahblah")
   166  
   167  	authenticateData, _ := base64.StdEncoding.DecodeString(authenticateMessage)
   168  	a, _ := ParseAuthenticateMessage(authenticateData, 2)
   169  
   170  	serverChallenge, _ := hex.DecodeString("3d74b2d04ebe1eb3")
   171  	server.SetServerChallenge(serverChallenge)
   172  
   173  	err := server.ProcessAuthenticateMessage(a)
   174  	if err != nil {
   175  		t.Errorf("Could not process authenticate message: %s\n", err)
   176  	}
   177  }
   178  
   179  func TestWindowsTimeConversion(t *testing.T) {
   180  	// From http://davenport.sourceforge.net/ntlm.html#theType3Message
   181  	// Next, the blob is constructed. The timestamp is the most tedious part of this; looking at the clock on my desk,
   182  	// it's about 6:00 AM EDT on June 17th, 2003. In Unix time, that would be 1055844000 seconds after the Epoch.
   183  	// Adding 11644473600 will give us seconds after January 1, 1601 (12700317600). Multiplying by 107 (10000000)
   184  	// will give us tenths of a microsecond (127003176000000000). As a little-endian 64-bit value, this is
   185  	// "0x0090d336b734c301" (in hexadecimal).
   186  	unix := time.Unix(1055844000, 0)
   187  	result := timeToWindowsFileTime(unix)
   188  	checkV2Value(t, "Timestamp", result, "0090d336b734c301", nil)
   189  }