Hi,

During WCF hacking I found that Mono.Security.Protocol.Ntlm looks
based on somewhat old analysis.

Currently the code does not look "version" aware. According to
http://davenport.sourceforge.net/ntlm.html , there seems three
ntlm versions and the message layout is diffrent for each version.
And WCF SSPI negotiation seems based on version3, which is not
what current code supports.

So I have created a patch to add support for every version of NTLM.
It is not a small, but the purpose is to handle "optional" fields
denoted in the document above.

This patch however breaks some NUnit tests. But as long as I see
the test buffers, they do not seem conformant to the document
above... how were those test buffers created?

(Also, existing message type1 looks based on version 2, while
message type2 and message type3 do not look so, but I'm not sure.
They hence resulted in weird default version mismatch in my patch...)

Atsushi Eno
Index: Mono.Security.Protocol.Ntlm/MessageBase.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/MessageBase.cs  (revision 74928)
+++ Mono.Security.Protocol.Ntlm/MessageBase.cs  (working copy)
@@ -4,9 +4,10 @@
 //
 // Author:
 //     Sebastien Pouliot  <[EMAIL PROTECTED]>
+//     Atsushi Enomoto <[EMAIL PROTECTED]>
 //
 // Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
 //
 // References
 // a.  NTLM Authentication Scheme for HTTP, Ronald Tschalär
@@ -40,15 +41,34 @@
 namespace Mono.Security.Protocol.Ntlm {
 
        public abstract class MessageBase {
+               static byte [] _current_os_version = GetOSVersion ();
 
+               static byte [] GetOSVersion ()
+               {
+                       Version v = Environment.OSVersion.Version;
+                       byte [] bytes = new byte [8];
+                       bytes [0] = (byte) v.Major;
+                       bytes [1] = (byte) v.Minor;
+                       bytes [2] = (byte) v.Build;
+                       bytes [3] = (byte) (v.Build >> 8);
+                       bytes [7] = 0xF;
+                       return bytes;
+               }
+
                static private byte[] header = { 0x4e, 0x54, 0x4c, 0x4d, 0x53, 
0x53, 0x50, 0x00 };
                
                private int _type;
                private NtlmFlags _flags;
+               private NtlmVersion _version;
+               private byte [] _osversion = _current_os_version;
 
-               protected MessageBase (int messageType) 
+               protected MessageBase (int messageType) : this (messageType, 
NtlmVersion.Version1)
                {
+               }
+               protected MessageBase (int messageType, NtlmVersion version) 
+               {
                        _type = messageType;
+                       _version = version;
                }
                
                public NtlmFlags Flags {
@@ -56,10 +76,19 @@
                        set { _flags = value; }
                }
 
+               public byte [] OSVersion {
+                       get { return (byte []) _osversion.Clone (); }
+                       set { _osversion = (byte []) value.Clone (); }
+               }
+
                public int Type { 
                        get { return _type; }
                }
 
+               public NtlmVersion Version {
+                       get { return _version; }
+               }
+
                protected byte[] PrepareMessage (int messageSize) 
                {
                        byte[] message = new byte [messageSize];
@@ -100,5 +129,12 @@
                }
 
                public abstract byte[] GetBytes ();
+
+               internal byte [] CreateSubArray (byte [] source, int offset, 
int length)
+               {
+                       byte [] ret = new byte [length];
+                       Array.Copy (source, offset, ret, 0, length);
+                       return ret;
+               }
        }
 }
Index: Mono.Security.Protocol.Ntlm/NtlmVersion.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/NtlmVersion.cs  (revision 0)
+++ Mono.Security.Protocol.Ntlm/NtlmVersion.cs  (revision 0)
@@ -0,0 +1,41 @@
+//
+// Mono.Security.Protocol.Ntlm.NtlmVersion
+//
+// Author:
+//     Atsushi Enomoto <[EMAIL PROTECTED]>
+//
+// (C) 2007 Novell, Inc. (http://www.novell.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+
+namespace Mono.Security.Protocol.Ntlm 
+{
+       public enum NtlmVersion
+       {
+               Version1,
+               Version2,
+               Version3
+       }
+}
Index: Mono.Security.Protocol.Ntlm/ChallengeResponse.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/ChallengeResponse.cs    (revision 74928)
+++ Mono.Security.Protocol.Ntlm/ChallengeResponse.cs    (working copy)
@@ -4,9 +4,10 @@
 //
 // Author:
 //     Sebastien Pouliot <[EMAIL PROTECTED]>
+//     Atsushi Enomoto <[EMAIL PROTECTED]>
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
+// (C) 2004, 2007 Novell (http://www.novell.com)
 //
 // References
 // a.  NTLM Authentication Scheme for HTTP, Ronald Tschalär
@@ -156,6 +157,29 @@
                        }
                }
 
+               public byte [] LMSessionKey {
+                       get {
+                               if (_disposed)
+                                       throw new ObjectDisposedException ("too 
late");
+
+                               byte[] lm = LM;
+                               byte[] pwd = new byte [14];
+                               Buffer.BlockCopy (lm, 0, pwd, 0, 8);
+                               for (int i = 8; i < 14; i++)
+                                       pwd [i] = 0xBD;
+                               byte[] response = new byte [16];
+                               DES des = DES.Create ();
+                               des.Mode = CipherMode.ECB;
+                               des.Key = PrepareDESKey (pwd, 0);
+                               ICryptoTransform ct = des.CreateEncryptor ();
+                               ct.TransformBlock (lm, 0, 8, response, 0);
+                               des.Key = PrepareDESKey (pwd, 7);
+                               ct = des.CreateEncryptor ();
+                               ct.TransformBlock (lm, 0, 8, response, 8);
+                               return response;
+                       }
+               }
+
                // IDisposable method
 
                public void Dispose () 
Index: Mono.Security.Protocol.Ntlm/NtlmFlags.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/NtlmFlags.cs    (revision 74928)
+++ Mono.Security.Protocol.Ntlm/NtlmFlags.cs    (working copy)
@@ -3,9 +3,10 @@
 //
 // Author:
 //     Sebastien Pouliot <[EMAIL PROTECTED]>
+//     Atsushi Enomoto <[EMAIL PROTECTED]>
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// (C) 2004 Novell (http://www.novell.com)
+// (C) 2004, 2007 Novell (http://www.novell.com)
 //
 // References
 // a.  NTLM Authentication Scheme for HTTP, Ronald Tschalär
@@ -47,8 +48,18 @@
                NegotiateOem = 0x00000002,
                // This requests that the server send the authentication target 
with the Type 2 reply.
                RequestTarget = 0x00000004,
+               // Negotiate Sign
+               NegotiateSign = 0x00000010,
+               // Negotiate Seal
+               NegotiateSeal = 0x00000020,
+               // Negotiate DatagramStyle
+               NegotiateDatagramStyle = 0x00000040,
+               // Negotiate Lan Manager Key
+               NegotiateLm = 0x00000080,
                // Indicates that NTLM authentication is supported.
                NegotiateNtlm = 0x00000200,
+               // Indicates that NTLM authentication is supported.
+               NegotiateAnonymous = 0x00000800,
                // When set, the client will send with the message the name of 
the domain in which the workstation has membership.
                NegotiateDomainSupplied = 0x00001000,
                // Indicates that the client is sending its workstation name 
with the message.  
@@ -59,6 +70,8 @@
                NegotiateNtlm2Key = 0x00080000,
                // Indicates that this client supports strong (128-bit) 
encryption.
                Negotiate128 = 0x20000000,
+               // Negotiate Key Exchange
+               NegotiateKeyExchange = 0x40000000,
                // Indicates that this client supports medium (56-bit) 
encryption.
                Negotiate56 = (unchecked ((int) 0x80000000))
        }
Index: Mono.Security.Protocol.Ntlm/Type1Message.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/Type1Message.cs (revision 74928)
+++ Mono.Security.Protocol.Ntlm/Type1Message.cs (working copy)
@@ -3,9 +3,10 @@
 //
 // Author:
 //     Sebastien Pouliot <[EMAIL PROTECTED]>
+//     Atsushi Enomoto <[EMAIL PROTECTED]>
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
 //
 // References
 // a.  NTLM Authentication Scheme for HTTP, Ronald Tschalär
@@ -44,16 +45,24 @@
                private string _host;
                private string _domain;
 
-               public Type1Message () : base (1)
+               public Type1Message () : this (NtlmVersion.Version2)
                {
+               }
+
+               public Type1Message (NtlmVersion version) : base (1, version)
+               {
                        // default values
                        _domain = Environment.UserDomainName;
                        _host = Environment.MachineName;
                        Flags = (NtlmFlags) 0xb203;
                }
 
-               public Type1Message (byte[] message) : base (1)
+               public Type1Message (byte[] message) : this (message, 
NtlmVersion.Version2)
                {
+               }
+
+               public Type1Message (byte[] message, NtlmVersion version) : 
base (1, version)
+               {
                        Decode (message);
                }
 
@@ -76,28 +85,44 @@
                        base.Decode (message);
 
                        Flags = (NtlmFlags) BitConverterLE.ToUInt32 (message, 
12);
+                       if (Version == NtlmVersion.Version1)
+                               return;
 
                        int dom_len = BitConverterLE.ToUInt16 (message, 16);
                        int dom_off = BitConverterLE.ToUInt16 (message, 20);
                        _domain = Encoding.ASCII.GetString (message, dom_off, 
dom_len);
 
                        int host_len = BitConverterLE.ToUInt16 (message, 24);
-                       _host = Encoding.ASCII.GetString (message, 32, 
host_len);
+                       int host_off = BitConverterLE.ToUInt16 (message, 28);
+                       _host = Encoding.ASCII.GetString (message, host_off, 
host_len);
+
+                       if (Version != NtlmVersion.Version3)
+                               return;
+                       OSVersion = CreateSubArray (message, 32, 8);
                }
 
                public override byte[] GetBytes () 
                {
-                       short dom_len = (short) _domain.Length;
-                       short host_len = (short) _host.Length;
+                       short dom_len = 0, host_len = 0;
+                       if (Version != NtlmVersion.Version1) {
+                               dom_len = (short) _domain.Length;
+                               host_len = (short) _host.Length;
+                       }
 
-                       byte[] data = PrepareMessage (32 + dom_len + host_len);
+                       int headSize = (Version == NtlmVersion.Version3 ? 40 : 
32);
 
+                       byte[] data = PrepareMessage (headSize + dom_len + 
host_len);
+
+                       // v1 contains only the flags.
+                       if (Version == NtlmVersion.Version1)
+                               return data;
+
                        data [12] = (byte) Flags;
                        data [13] = (byte)((uint)Flags >> 8);
                        data [14] = (byte)((uint)Flags >> 16);
                        data [15] = (byte)((uint)Flags >> 24);
 
-                       short dom_off = (short)(32 + host_len);
+                       short dom_off = (short) (headSize + host_len);
 
                        data [16] = (byte) dom_len;
                        data [17] = (byte)(dom_len >> 8);
@@ -113,8 +138,11 @@
                        data [28] = 0x20;
                        data [29] = 0x00;
 
+                       if (Version == NtlmVersion.Version3)
+                               Buffer.BlockCopy (OSVersion, 0, data, 32, 
OSVersion.Length);
+
                        byte[] host = Encoding.ASCII.GetBytes (_host.ToUpper 
(CultureInfo.InvariantCulture));
-                       Buffer.BlockCopy (host, 0, data, 32, host.Length);
+                       Buffer.BlockCopy (host, 0, data, headSize, host.Length);
 
                        byte[] domain = Encoding.ASCII.GetBytes 
(_domain.ToUpper (CultureInfo.InvariantCulture));
                        Buffer.BlockCopy (domain, 0, data, dom_off, 
domain.Length);
Index: Mono.Security.Protocol.Ntlm/NtlmTargetInformation.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/NtlmTargetInformation.cs        (revision 0)
+++ Mono.Security.Protocol.Ntlm/NtlmTargetInformation.cs        (revision 0)
@@ -0,0 +1,103 @@
+//
+// Mono.Security.Protocol.Ntlm.NtlmTargetInformation
+//
+// Author:
+//     Atsushi Enomoto  <[EMAIL PROTECTED]>
+//
+// (C) 2007 Novell, Inc. (http://www.novell.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.IO;
+using System.Text;
+
+namespace Mono.Security.Protocol.Ntlm {
+       public class NtlmTargetInformation {
+               string _server, _domain, _dns_host, _dns_domain;
+
+               public string ServerName {
+                       get { return _server; }
+                       set { _server = value; }
+               }
+
+               public string DomainName {
+                       get { return _domain; }
+                       set { _domain = value; }
+               }
+
+               public string DnsHostName {
+                       get { return _dns_host; }
+                       set { _dns_host = value; }
+               }
+
+               public string DnsDomainName {
+                       get { return _dns_domain; }
+                       set { _dns_domain = value; }
+               }
+
+               public void Decode (byte [] bytes, int length, int offset)
+               {
+                       int end = offset + length;
+                       for (int pos = offset; pos < end;) {
+                               short type = BitConverterLE.ToInt16 (bytes, 
pos); // reader.ReadInt16 ();
+                               short blen = BitConverterLE.ToInt16 (bytes, pos 
+ 2); // reader.ReadInt16 ();
+                               string s = Encoding.Unicode.GetString (bytes, 
pos + 4, blen);
+                               pos += blen + 4;
+                               switch (type) {
+                               case 0: break; // terminator
+                               case 1: ServerName = s; break;
+                               case 2: DomainName = s; break;
+                               case 3: DnsHostName = s; break;
+                               case 4: DnsDomainName = s; break;
+                               default:
+                                       throw new ArgumentException 
(String.Format ("Invalid SSPI message type 2 subblock type: {0}", type));
+                               }
+                               if (type == 0)
+                                       break; // terminator subblock
+                       }
+               }
+
+               public byte [] ToBytes ()
+               {
+                       MemoryStream ms = new MemoryStream ();
+                       BinaryWriter bw = new BinaryWriter (ms);
+
+                       WriteName (bw, 1, ServerName);
+                       WriteName (bw, 2, DomainName);
+                       WriteName (bw, 3, DnsHostName);
+                       WriteName (bw, 4, DnsDomainName);
+                       bw.Close ();
+                       return ms.ToArray ();
+               }
+
+               private void WriteName (BinaryWriter bw, short type, string 
value)
+               {
+                       if (value == null)
+                               return;
+                       byte [] bytes = Encoding.Unicode.GetBytes (value);
+                       bw.Write (type);
+                       bw.Write ((short) bytes.Length);
+                       bw.Write (bytes);
+               }
+       }
+}
Index: Mono.Security.Protocol.Ntlm/Type2Message.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/Type2Message.cs (revision 74928)
+++ Mono.Security.Protocol.Ntlm/Type2Message.cs (working copy)
@@ -3,9 +3,10 @@
 //
 // Author:
 //     Sebastien Pouliot <[EMAIL PROTECTED]>
+//     Atsushi Enomoto <[EMAIL PROTECTED]>
 //
 // Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
 //
 // References
 // a.  NTLM Authentication Scheme for HTTP, Ronald Tschalär
@@ -35,24 +36,40 @@
 
 using System;
 using System.Security.Cryptography;
+using System.Text;
 
 namespace Mono.Security.Protocol.Ntlm {
 
        public class Type2Message : MessageBase {
 
                private byte[] _nonce;
+               private byte[] _context;
+               private NtlmTargetInformation _target;
+               private string _target_name;
 
-               public Type2Message () : base (2)
+               public Type2Message () : this (NtlmVersion.Version1)
                {
+               }
+
+               public Type2Message (NtlmVersion version) : base (2, version)
+               {
                        _nonce = new byte [8];
                        RandomNumberGenerator rng = 
RandomNumberGenerator.Create ();
                        rng.GetBytes (_nonce);
                        // default values
                        Flags = (NtlmFlags) 0x8201;
+                       if (Version != NtlmVersion.Version1) {
+                               _context = new byte [8];
+                               _target = new NtlmTargetInformation ();
+                       }
                }
 
-               public Type2Message (byte[] message) : base (2)
+               public Type2Message (byte[] message) : this (message, 
NtlmVersion.Version1)
                {
+               }
+
+               public Type2Message (byte[] message, NtlmVersion version) : 
base (2, version)
+               {
                        _nonce = new byte [8];
                        Decode (message);
                }
@@ -65,6 +82,19 @@
 
                // properties
 
+               public byte[] Context {
+                       get { return (byte[]) _context.Clone (); }
+                       set { 
+                               if (value == null)
+                                       throw new ArgumentNullException 
("Nonce");
+                               if (value.Length != 8) {
+                                       string msg = Locale.GetText ("Invalid 
Nonce Length (should be 8 bytes).");
+                                       throw new ArgumentException (msg, 
"Nonce");
+                               }
+                               _context = (byte[]) value.Clone (); 
+                       }
+               }
+
                public byte[] Nonce {
                        get { return (byte[]) _nonce.Clone (); }
                        set { 
@@ -78,26 +108,76 @@
                        }
                }
 
+               public NtlmTargetInformation Target {
+                       get { return _target; }
+               }
+
+               public string TargetName {
+                       get { return _target_name; }
+                       set { _target_name = value; }
+               }
+
                // methods
 
                protected override void Decode (byte[] message) 
                {
                        base.Decode (message);
 
+                       short targetNameSize = BitConverterLE.ToInt16 (message, 
12);
+                       int targetNameOffset = BitConverterLE.ToInt32 (message, 
16);
+
                        Flags = (NtlmFlags) BitConverterLE.ToUInt32 (message, 
20);
 
                        Buffer.BlockCopy (message, 24, _nonce, 0, 8);
+
+                       if (Version == NtlmVersion.Version1)
+                               return;
+
+                       Buffer.BlockCopy (message, 32, _context, 0, 8);
+                       short targetInfoSize = BitConverterLE.ToInt16 (message, 
40);
+                       int targetInfoOffset = BitConverterLE.ToInt32 (message, 
44);
+
+                       if (Version == NtlmVersion.Version3)
+                               Buffer.BlockCopy (OSVersion, 0, message, 48, 
OSVersion.Length);
+
+                       Encoding enc = (Flags & NtlmFlags.NegotiateUnicode) != 
0 ? Encoding.Unicode : Encoding.UTF8;
+                       if (targetNameSize > 0)
+                               TargetName = enc.GetString (message, 
targetNameOffset, targetNameSize);
+
+                       _target.Decode (message, targetInfoOffset, 
targetInfoSize);
                }
 
                public override byte[] GetBytes ()
                {
-                       byte[] data = PrepareMessage (40);
+                       byte [] name_bytes = null, target = null;
+                       short name_len = 0, target_len = 0;
+                       if (TargetName != null) {
+                               Encoding enc = (Flags & 
NtlmFlags.NegotiateUnicode) != 0 ? Encoding.Unicode : Encoding.UTF8;
+                               name_bytes = enc.GetBytes (TargetName);
+                               name_len = (short) name_bytes.Length;
+                       }
+                       if (Version != NtlmVersion.Version1) {
+                               target = _target.ToBytes ();
+                               target_len = (short) target.Length;
+                       }
 
-                       // message length
-                       short msg_len = (short)data.Length;
-                       data [16] = (byte) msg_len;
-                       data [17] = (byte)(msg_len >> 8);
+                       uint name_offset = (uint) (Version == 
NtlmVersion.Version3 ? 56 : 48);
 
+                       int size = (int) name_offset +
+                                  (name_len > 0 ? name_len + 8 : 0) +
+                                  (target_len > 0 ? target_len + 8 : 0);
+                       byte[] data = PrepareMessage (size);
+
+                       // target name
+                       data [12] = (byte) name_len;
+                       data [13] = (byte) (name_len >> 8);
+                       data [14] = data [12];
+                       data [15] = data [13];
+                       data [16] = (byte) name_offset;
+                       data [17] = (byte) (name_offset >> 8);
+                       data [18] = (byte) (name_offset >> 16);
+                       data [19] = (byte) (name_offset >> 24);
+
                        // flags
                        data [20] = (byte) Flags;
                        data [21] = (byte)((uint)Flags >> 8);
@@ -105,6 +185,30 @@
                        data [23] = (byte)((uint)Flags >> 24);
 
                        Buffer.BlockCopy (_nonce, 0, data, 24, _nonce.Length);
+
+                       if (Version == NtlmVersion.Version1)
+                               return data;
+
+                       // context
+                       Buffer.BlockCopy (_context, 0, data, 32, 8);
+
+                       // target information
+                       data [40] = (byte) target_len;
+                       data [41] = (byte) (target_len >> 8);
+                       data [42] = data [40];
+                       data [43] = data [41];
+                       uint info_offset = (uint) (name_offset + 
name_bytes.Length);
+                       data [44] = (byte) info_offset;
+                       data [45] = (byte) (info_offset >> 8);
+                       data [46] = (byte) (info_offset >> 16);
+                       data [47] = (byte) (info_offset >> 24);
+
+                       if (Version == NtlmVersion.Version3)
+                               Buffer.BlockCopy (OSVersion, 0, data, 48, 
OSVersion.Length);
+
+                       Buffer.BlockCopy (name_bytes, 0, data, (int) 
name_offset, name_len);
+                       Buffer.BlockCopy (target, 0, data, (int) info_offset, 
target.Length);
+
                        return data;
                }
        }
Index: Mono.Security.Protocol.Ntlm/Type3Message.cs
===================================================================
--- Mono.Security.Protocol.Ntlm/Type3Message.cs (revision 74928)
+++ Mono.Security.Protocol.Ntlm/Type3Message.cs (working copy)
@@ -3,9 +3,10 @@
 //
 // Author:
 //     Sebastien Pouliot <[EMAIL PROTECTED]>
+//     Atsushi Enomoto <[EMAIL PROTECTED]>
 //
 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
 //
 // References
 // a.  NTLM Authentication Scheme for HTTP, Ronald Tschalär
@@ -35,6 +36,7 @@
 
 using System;
 using System.Globalization;
+using System.Security.Cryptography;
 using System.Text;
 
 namespace Mono.Security.Protocol.Ntlm {
@@ -48,18 +50,30 @@
                private string _password;
                private byte[] _lm;
                private byte[] _nt;
+               private byte[] _nonce;
 
-               public Type3Message () : base (3)
+               public Type3Message () : this (NtlmVersion.Version1)
                {
+               }
+
+               public Type3Message (NtlmVersion version) : base (3, version)
+               {
                        // default values
                        _domain = Environment.UserDomainName;
                        _host = Environment.MachineName;
                        _username = Environment.UserName;
                        Flags = (NtlmFlags) 0x8201;
+                       _nonce = new byte [8];
+                       RandomNumberGenerator rng = 
RandomNumberGenerator.Create ();
+                       rng.GetBytes (_nonce);
                }
 
-               public Type3Message (byte[] message) : base (3)
+               public Type3Message (byte[] message) : this (message, 
NtlmVersion.Version1)
                {
+               }
+
+               public Type3Message (byte[] message, NtlmVersion version) : 
base (3, version)
+               {
                        Decode (message);
                }
 
@@ -125,15 +139,17 @@
                {
                        base.Decode (message);
 
+/*
                        if (BitConverterLE.ToUInt16 (message, 56) != 
message.Length) {
                                string msg = Locale.GetText ("Invalid Type3 
message length.");
                                throw new ArgumentException (msg, "message");
                        }
+*/
 
                        _password = null;
 
                        int dom_len = BitConverterLE.ToUInt16 (message, 28);
-                       int dom_off = 64;
+                       int dom_off = BitConverterLE.ToUInt16 (message, 32);
                        _domain = Encoding.Unicode.GetString (message, dom_off, 
dom_len);
 
                        int host_len = BitConverterLE.ToUInt16 (message, 44);
@@ -162,60 +178,89 @@
                        byte[] user = Encoding.Unicode.GetBytes (_username);
                        byte[] host = Encoding.Unicode.GetBytes (_host.ToUpper 
(CultureInfo.InvariantCulture));
 
-                       byte[] data = PrepareMessage (64 + domain.Length + 
user.Length + host.Length + 24 + 24);
+                       int fixed_size = Version == NtlmVersion.Version3 ? 72 : 
64;
+                       short skey_len = (short) (Version != 
NtlmVersion.Version1 ? 16 : 0);
+                       int skey_off = 0;
 
+                       byte[] data = PrepareMessage (fixed_size + 
domain.Length + user.Length + host.Length + 24 + 24 + skey_len);
+
                        // LM response
-                       short lmresp_off = (short)(64 + domain.Length + 
user.Length + host.Length);
+                       int lmresp_off = fixed_size + domain.Length + 
user.Length + host.Length;
                        data [12] = (byte) 0x18;
                        data [13] = (byte) 0x00;
                        data [14] = (byte) 0x18;
                        data [15] = (byte) 0x00;
                        data [16] = (byte) lmresp_off;
                        data [17] = (byte)(lmresp_off >> 8);
+                       data [18] = (byte)(lmresp_off >> 16);
+                       data [19] = (byte)(lmresp_off >> 24);
 
                        // NT response
-                       short ntresp_off = (short)(lmresp_off + 24);
+                       int ntresp_off = lmresp_off + 24;
                        data [20] = (byte) 0x18;
                        data [21] = (byte) 0x00;
                        data [22] = (byte) 0x18;
                        data [23] = (byte) 0x00;
                        data [24] = (byte) ntresp_off;
                        data [25] = (byte)(ntresp_off >> 8);
+                       data [26] = (byte)(ntresp_off >> 16);
+                       data [27] = (byte)(ntresp_off >> 24);
 
                        // domain
                        short dom_len = (short)domain.Length;
-                       short dom_off = 64;
+                       int dom_off = (short)fixed_size;
                        data [28] = (byte) dom_len;
                        data [29] = (byte)(dom_len >> 8);
                        data [30] = data [28];
                        data [31] = data [29];
                        data [32] = (byte) dom_off;
                        data [33] = (byte)(dom_off >> 8);
+                       data [34] = (byte)(dom_off >> 16);
+                       data [35] = (byte)(dom_off >> 24);
 
                        // username
                        short uname_len = (short)user.Length;
-                       short uname_off = (short)(dom_off + dom_len);
+                       int uname_off = dom_off + dom_len;
                        data [36] = (byte) uname_len;
                        data [37] = (byte)(uname_len >> 8);
                        data [38] = data [36];
                        data [39] = data [37];
                        data [40] = (byte) uname_off;
                        data [41] = (byte)(uname_off >> 8);
+                       data [42] = (byte)(uname_off >> 16);
+                       data [43] = (byte)(uname_off >> 24);
 
                        // host
                        short host_len = (short)host.Length;
-                       short host_off = (short)(uname_off + uname_len);
+                       int host_off = uname_off + uname_len;
                        data [44] = (byte) host_len;
                        data [45] = (byte)(host_len >> 8);
                        data [46] = data [44];
                        data [47] = data [45];
                        data [48] = (byte) host_off;
                        data [49] = (byte)(host_off >> 8);
+                       data [50] = (byte)(host_off >> 16);
+                       data [51] = (byte)(host_off >> 24);
 
+                       // session key
+                       if (Version != NtlmVersion.Version1) {
+                               skey_off = (short)(data.Length - skey_len);
+                               data [52] = (byte) skey_len;
+                               data [53] = (byte)(skey_len >> 8);
+                               data [54] = data [52];
+                               data [55] = data [53];
+                               data [56] = (byte) skey_off;
+                               data [57] = (byte)(skey_off >> 8);
+                               data [58] = (byte)(skey_off >> 16);
+                               data [59] = (byte)(skey_off >> 24);
+                       }
+
+/*
                        // message length
                        short msg_len = (short)data.Length;
                        data [56] = (byte) msg_len;
                        data [57] = (byte)(msg_len >> 8);
+*/
 
                        // options flags
                        data [60] = (byte) Flags;
@@ -223,6 +268,10 @@
                        data [62] = (byte)((uint)Flags >> 16);
                        data [63] = (byte)((uint)Flags >> 24);
 
+                       // osversion
+                       if (Version == NtlmVersion.Version3)
+                               Buffer.BlockCopy (OSVersion, 0, data, 64, 
OSVersion.Length);
+
                        Buffer.BlockCopy (domain, 0, data, dom_off, 
domain.Length);
                        Buffer.BlockCopy (user, 0, data, uname_off, 
user.Length);
                        Buffer.BlockCopy (host, 0, data, host_off, host.Length);
@@ -230,7 +279,12 @@
                        using (ChallengeResponse ntlm = new ChallengeResponse 
(_password, _challenge)) {
                                Buffer.BlockCopy (ntlm.LM, 0, data, lmresp_off, 
24);
                                Buffer.BlockCopy (ntlm.NT, 0, data, ntresp_off, 
24);
+
+                               if (Version != NtlmVersion.Version1)
+                                       // session key
+                                       Buffer.BlockCopy (ntlm.LMSessionKey, 0, 
data, skey_off, 16);
                        }
+
                        return data;
                }
        }
Index: Mono.Security.dll.sources
===================================================================
--- Mono.Security.dll.sources   (revision 74928)
+++ Mono.Security.dll.sources   (working copy)
@@ -68,6 +68,8 @@
 ./Mono.Security.Protocol.Ntlm/ChallengeResponse.cs
 ./Mono.Security.Protocol.Ntlm/MessageBase.cs
 ./Mono.Security.Protocol.Ntlm/NtlmFlags.cs
+./Mono.Security.Protocol.Ntlm/NtlmTargetInformation.cs
+./Mono.Security.Protocol.Ntlm/NtlmVersion.cs
 ./Mono.Security.Protocol.Ntlm/Type1Message.cs
 ./Mono.Security.Protocol.Ntlm/Type2Message.cs
 ./Mono.Security.Protocol.Ntlm/Type3Message.cs
_______________________________________________
Mono-devel-list mailing list
Mono-devel-list@lists.ximian.com
http://lists.ximian.com/mailman/listinfo/mono-devel-list

Reply via email to