Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / System.ServiceModel / Mono.Security.Protocol.Ntlm / Type2Message.cs
1 //
2 // Mono.Security.Protocol.Ntlm.Type2Message - Challenge
3 //
4 // Author:
5 //      Sebastien Pouliot <sebastien@ximian.com>
6 //      Atsushi Enomoto <atsushi@ximian.com>
7 //
8 // Copyright (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
10 //
11 // References
12 // a.   NTLM Authentication Scheme for HTTP, Ronald Tschalär
13 //      http://www.innovation.ch/java/ntlm.html
14 // b.   The NTLM Authentication Protocol, Copyright © 2003 Eric Glass
15 //      http://davenport.sourceforge.net/ntlm.html
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using System;
38 using System.Security.Cryptography;
39 using System.Text;
40
41 namespace Mono.Security.Protocol.Ntlm {
42
43         public class Type2Message : MessageBase {
44
45                 private byte[] _nonce;
46                 private byte[] _context;
47                 private NtlmTargetInformation _target;
48                 private string _target_name;
49
50                 public Type2Message () : this (NtlmVersion.Version1)
51                 {
52                 }
53
54                 public Type2Message (NtlmVersion version) : base (2, version)
55                 {
56                         _nonce = new byte [8];
57                         RandomNumberGenerator rng = RandomNumberGenerator.Create ();
58                         rng.GetBytes (_nonce);
59                         // default values
60                         Flags = (NtlmFlags) 0x8201;
61                         if (Version != NtlmVersion.Version1) {
62                                 _context = new byte [8];
63                                 _target = new NtlmTargetInformation ();
64                         }
65                 }
66
67                 public Type2Message (byte[] message) : this (message, NtlmVersion.Version1)
68                 {
69                 }
70
71                 public Type2Message (byte[] message, NtlmVersion version) : base (2, version)
72                 {
73                         _nonce = new byte [8];
74                         Decode (message);
75                 }
76
77                 ~Type2Message () 
78                 {
79                         if (_nonce != null)
80                                 Array.Clear (_nonce, 0, _nonce.Length);
81                 }
82
83                 // properties
84
85                 public byte[] Context {
86                         get { return (byte[]) _context.Clone (); }
87                         set { 
88                                 if (value == null)
89                                         throw new ArgumentNullException ("Nonce");
90                                 if (value.Length != 8) {
91                                         string msg = Locale.GetText ("Invalid Nonce Length (should be 8 bytes).");
92                                         throw new ArgumentException (msg, "Nonce");
93                                 }
94                                 _context = (byte[]) value.Clone (); 
95                         }
96                 }
97
98                 public byte[] Nonce {
99                         get { return (byte[]) _nonce.Clone (); }
100                         set { 
101                                 if (value == null)
102                                         throw new ArgumentNullException ("Nonce");
103                                 if (value.Length != 8) {
104                                         string msg = Locale.GetText ("Invalid Nonce Length (should be 8 bytes).");
105                                         throw new ArgumentException (msg, "Nonce");
106                                 }
107                                 _nonce = (byte[]) value.Clone (); 
108                         }
109                 }
110
111                 public NtlmTargetInformation Target {
112                         get { return _target; }
113                 }
114
115                 public string TargetName {
116                         get { return _target_name; }
117                         set { _target_name = value; }
118                 }
119
120                 // methods
121
122                 protected override void Decode (byte[] message) 
123                 {
124                         base.Decode (message);
125
126                         short targetNameSize = BitConverterLE.ToInt16 (message, 12);
127                         int targetNameOffset = BitConverterLE.ToInt32 (message, 16);
128
129                         Flags = (NtlmFlags) BitConverterLE.ToUInt32 (message, 20);
130
131                         Buffer.BlockCopy (message, 24, _nonce, 0, 8);
132
133                         if (Version == NtlmVersion.Version1)
134                                 return;
135
136                         Buffer.BlockCopy (message, 32, _context, 0, 8);
137                         short targetInfoSize = BitConverterLE.ToInt16 (message, 40);
138                         int targetInfoOffset = BitConverterLE.ToInt32 (message, 44);
139
140                         if (Version == NtlmVersion.Version3)
141                                 Buffer.BlockCopy (OSVersion, 0, message, 48, OSVersion.Length);
142
143                         Encoding enc = (Flags & NtlmFlags.NegotiateUnicode) != 0 ? Encoding.Unicode : Encoding.UTF8;
144                         if (targetNameSize > 0)
145                                 TargetName = enc.GetString (message, targetNameOffset, targetNameSize);
146
147                         _target.Decode (message, targetInfoOffset, targetInfoSize);
148                 }
149
150                 public override byte[] GetBytes ()
151                 {
152                         byte [] name_bytes = null, target = null;
153                         short name_len = 0, target_len = 0;
154                         if (TargetName != null) {
155                                 Encoding enc = (Flags & NtlmFlags.NegotiateUnicode) != 0 ? Encoding.Unicode : Encoding.UTF8;
156                                 name_bytes = enc.GetBytes (TargetName);
157                                 name_len = (short) name_bytes.Length;
158                         }
159                         if (Version != NtlmVersion.Version1) {
160                                 target = _target.ToBytes ();
161                                 target_len = (short) target.Length;
162                         }
163
164                         uint name_offset = (uint) (Version == NtlmVersion.Version3 ? 56 : 40);
165
166                         int size = (int) name_offset +
167                                    (name_len > 0 ? name_len + 8 : 0) +
168                                    (target_len > 0 ? target_len + 8 : 0);
169                         byte[] data = PrepareMessage (size);
170
171                         // target name
172                         data [12] = (byte) name_len;
173                         data [13] = (byte) (name_len >> 8);
174                         data [14] = data [12];
175                         data [15] = data [13];
176                         data [16] = (byte) name_offset;
177                         data [17] = (byte) (name_offset >> 8);
178                         data [18] = (byte) (name_offset >> 16);
179                         data [19] = (byte) (name_offset >> 24);
180
181                         // flags
182                         data [20] = (byte) Flags;
183                         data [21] = (byte)((uint)Flags >> 8);
184                         data [22] = (byte)((uint)Flags >> 16);
185                         data [23] = (byte)((uint)Flags >> 24);
186
187                         Buffer.BlockCopy (_nonce, 0, data, 24, _nonce.Length);
188
189                         if (Version == NtlmVersion.Version1)
190                                 return data;
191
192                         // context
193                         Buffer.BlockCopy (_context, 0, data, 32, 8);
194
195                         // target information
196                         data [40] = (byte) target_len;
197                         data [41] = (byte) (target_len >> 8);
198                         data [42] = data [40];
199                         data [43] = data [41];
200                         uint info_offset = (uint) (name_offset + name_bytes.Length);
201                         data [44] = (byte) info_offset;
202                         data [45] = (byte) (info_offset >> 8);
203                         data [46] = (byte) (info_offset >> 16);
204                         data [47] = (byte) (info_offset >> 24);
205
206                         if (Version == NtlmVersion.Version3)
207                                 Buffer.BlockCopy (OSVersion, 0, data, 48, OSVersion.Length);
208
209                         Buffer.BlockCopy (name_bytes, 0, data, (int) name_offset, name_len);
210                         Buffer.BlockCopy (target, 0, data, (int) info_offset, target.Length);
211
212                         return data;
213                 }
214         }
215 }