4 using System.Net.NetworkInformation;
5 using System.Security.Cryptography;
8 using Mono.Security.Protocol.Ntlm;
10 namespace System.ServiceModel.Security
12 internal abstract class SspiSession
14 internal static readonly byte [] NtlmSSP = new byte [] {
15 0x4E, 0x54, 0x4C, 0x4D, 0x53, 0x53, 0x50, 0x00};
17 public long Challenge, Context, ClientOSVersion, ServerOSVersion;
18 public string ServerName, DomainName, DnsHostName, DnsDomainName;
20 public bool Verify (byte [] expected, byte [] actual, int offset, int length)
22 if (expected.Length != length)
24 for (int i = 0; i < length; i++)
25 if (expected [i] != actual [i + offset])
30 public SspiSecurityBufferStruct ReadSecurityBuffer (BinaryReader reader)
32 return new SspiSecurityBufferStruct (
39 internal struct SspiSecurityBufferStruct
41 public SspiSecurityBufferStruct (short length, short allocatedSpace, int offset)
44 AllocatedSpace = allocatedSpace;
48 public readonly short Length;
49 public readonly short AllocatedSpace;
50 public readonly int Offset;
53 internal class SspiClientSession : SspiSession
63 // Class(30) { OID,OID,OID} },
64 // Class(A2) { OctetStream } } } }
65 public byte [] ProcessSpnegoInitialContextTokenRequest ()
67 Type1Message type1 = new Type1Message (NtlmVersion.Version3);
68 type1.Flags = unchecked ((NtlmFlags) 0xE21882B7);
69 type1.Domain = "WORKGROUP"; // FIXME: remove it
71 ASN1 asn = new ASN1 (0x60);
72 ASN1 asn2 = new ASN1 (0xA0);
73 ASN1 asn21 = new ASN1 (0x30);
74 ASN1 asn211 = new ASN1 (0xA0);
75 ASN1 asn2111 = new ASN1 (0x30);
77 asn2111.Add (ASN1Convert.FromOid (Constants.OidNtlmSsp));
78 asn2111.Add (ASN1Convert.FromOid (Constants.OidKerberos5));
79 asn2111.Add (ASN1Convert.FromOid (Constants.OidMIT));
80 ASN1 asn212 = new ASN1 (0xA2);
81 ASN1 asn2121 = new ASN1 (0x4);
82 asn2121.Value = type1.GetBytes ();
87 asn.Add (ASN1Convert.FromOid (Constants.OidSpnego));
89 return asn.GetBytes ();
95 // A10C 060A2B06010401823702020A
97 // NTLM = 4E544C4D53535000 0200000004000400 3800000035829AE2
98 // 0D1A7FF0F171F339 0000000000000000 2C002C003C000000
99 // 0501280A0000000F 5000430002000400 5000430001000400
100 // 5000430004000400 5000430003000400 5000430006000400
102 public void ProcessSpnegoInitialContextTokenResponse (byte [] raw)
104 ASN1 asn1 = new ASN1 (raw);
105 // FIXME: check OIDs and structure
106 ProcessMessageType2 (asn1 [0] [2] [0].Value);
109 // Class { Class { Class { OctetStream } } }
110 public byte [] ProcessSpnegoProcessContextToken (string user, string pass)
112 ASN1 asn = new ASN1 (0xA1);
113 ASN1 asn2 = new ASN1 (0x30);
114 ASN1 asn3 = new ASN1 (0xA2);
115 asn3.Add (new ASN1 (0x04, ProcessMessageType3 (user, pass)));
118 return asn.GetBytes ();
121 public byte [] ProcessMessageType1 ()
123 Type1Message type1 = new Type1Message (NtlmVersion.Version3);
124 type1.Flags = unchecked ((NtlmFlags) 0xE21882B7);
125 return type1.GetBytes ();
130 public void ProcessMessageType2 (byte [] raw)
132 type2 = new Type2Message (raw);
135 public byte [] ProcessMessageType3 (string user, string password)
137 TargetName = Environment.MachineName;
138 ServerName = Environment.MachineName;
140 DomainName = ServerName;// IPGlobalProperties.GetIPGlobalProperties ().DomainName;
141 DnsHostName = Dns.GetHostName ();
142 DnsDomainName = DnsHostName; // FIXME
144 type3 = new Type3Message (NtlmVersion.Version3);
145 type3.Flags = (NtlmFlags) (unchecked ((int) 0xE2188235));
146 type3.Domain = DomainName;
147 type3.Host = DnsHostName;
148 type3.Challenge = type2.Nonce;
149 type3.Username = user;
150 type3.Password = password;
152 return type3.GetBytes ();
156 internal class SspiServerSession : SspiSession
158 public string TargetName;
159 public long SuppliedDomain, SuppliedWorkstation;
165 // 6069 0606 2B0601050502 A05F 305D A024 3022
166 // 060A 2B06010401823702020A
167 // 0609 2A864882F712010202
168 // 0609 2A864886F712010202
170 // NTLM = 4E544C4D53535000 01000000 B7B218E2 090009002A000000
171 // 0200020028000000 0501280A0000000F 5043 574F524B47524F5550
172 public void ProcessSpnegoInitialContextTokenRequest (byte [] raw)
174 ASN1 asn1 = new ASN1 (raw);
176 ProcessMessageType1 (asn1 [1] [0] [1] [0].Value);
182 // Class { OID(NTLMSSP) },
183 // Class { OctetStream } } }
184 public byte [] ProcessSpnegoInitialContextTokenResponse ()
186 ASN1 top = new ASN1 (0xA1);
187 ASN1 asn = new ASN1 (0x30);
188 ASN1 asn1 = new ASN1 (0xA0);
189 // FIXME: what is this enum?
190 asn1.Add (new ASN1 (0x0A, new byte [] {1})); // Enum whatever
191 ASN1 asn2 = new ASN1 (0xA1);
192 asn2.Add (ASN1Convert.FromOid (Constants.OidNtlmSsp));
193 ASN1 asn3 = new ASN1 (0xA2);
194 asn3.Add (new ASN1 (0x04, ProcessMessageType2 ()));
199 return top.GetBytes ();
207 // 4E544C4D53535000 03000000
208 // 180018005E000000 1800180076000000 0400040048000000
209 // 0E000E004C000000 040004005A000000 100010008E000000
210 // 358218E2 0501280A0000000F
211 // 50004300 6100740073007500730068006900 50004300
212 // [8 bytes LM] [16 bytes of 0s]
213 // [24 bytes of NTLM]
214 // C94EE2ADE7E32244 BD60D3B33609C167
215 public void ProcessSpnegoProcessContextToken (byte [] raw)
217 ASN1 asn1 = new ASN1 (raw);
218 // FIXME: check structure
219 ProcessMessageType3 (asn1 [0] [0] [0].Value);
222 public void ProcessMessageType1 (byte [] raw)
224 type1 = new Type1Message (raw, NtlmVersion.Version3);
227 public byte [] ProcessMessageType2 ()
229 byte [] bytes = new byte [8];
230 RandomNumberGenerator.Create ().GetNonZeroBytes (bytes);
231 Challenge = bytes [0] << 24 + bytes [1] << 16 + bytes [2] << 8 + bytes [3];
232 Context = 0; // FIXME
233 ServerOSVersion = 0x0F00000A28010500; // FIXME
234 TargetName = Environment.MachineName;
235 ServerName = Environment.MachineName;
237 DomainName = ServerName;// IPGlobalProperties.GetIPGlobalProperties ().DomainName;
238 DnsHostName = Dns.GetHostName ();
239 DnsDomainName = DnsHostName; // FIXME
241 type2 = new Type2Message (NtlmVersion.Version3);
242 type2.Flags = (NtlmFlags) (unchecked ((int) 0xE21882B7));
243 type2.TargetName = TargetName;
244 type2.Target.ServerName = ServerName;
245 type2.Target.DomainName = DomainName;
246 type2.Target.DnsHostName = DnsHostName;
247 type2.Target.DnsDomainName = DnsDomainName;
248 return type2.GetBytes ();
251 public void ProcessMessageType3 (byte [] raw)
254 MemoryStream ms = new MemoryStream (raw);
255 if (!Verify (NtlmSSP, raw, 0, 8))
256 throw new SecurityNegotiationException ("Expected NTLM SSPI header not found");
257 BinaryReader reader = new BinaryReader (ms);
258 reader.ReadInt64 (); // skip 8 bytes
259 if (reader.ReadInt32 () != 3)
260 throw new SecurityNegotiationException ("SSPI type 3 message is expected");
261 SspiSecurityBufferStruct lmResInfo = ReadSecurityBuffer (reader);
262 SspiSecurityBufferStruct ntlmResInfo = ReadSecurityBuffer (reader);
263 SspiSecurityBufferStruct targetNameInfo = ReadSecurityBuffer (reader);
264 SspiSecurityBufferStruct userNameInfo = ReadSecurityBuffer (reader);
265 SspiSecurityBufferStruct wsNameInfo = ReadSecurityBuffer (reader);
266 SspiSecurityBufferStruct sessionKeyInfo = ReadSecurityBuffer (reader);
267 int flags = reader.ReadInt32 ();
268 ServerOSVersion = reader.ReadInt64 ();
270 type3 = new Type3Message (raw, NtlmVersion.Version3);