Wait for the native thread to die in Thread.Join() on Windows
[mono.git] / mcs / class / Mono.Security / Mono.Security.Interface / TlsBuffer.cs
1 //
2 // TlsBuffer.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2014-2016 Xamarin Inc. (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
15 //
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
18 //
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 // THE SOFTWARE.
26 using System;
27
28 namespace Mono.Security.Interface
29 {
30         public class TlsBuffer : SecretParameters
31         {
32                 public int Position {
33                         get; set;
34                 }
35
36                 public int Remaining {
37                         get { return Size - (Position - Offset); }
38                 }
39
40                 public byte[] Buffer {
41                         get { return innerBuffer.Buffer; }
42                 }
43
44                 public int Offset {
45                         get { return innerBuffer.Offset; }
46                 }
47
48                 public int Size {
49                         get { return innerBuffer.Size; }
50                 }
51
52                 public int EndOffset {
53                         get { return Offset + Size; }
54                 }
55
56                 IBufferOffsetSize innerBuffer;
57
58                 protected TlsBuffer ()
59                         : this (null, 0, 0)
60                 {
61                 }
62
63                 public TlsBuffer (IBufferOffsetSize bos)
64                 {
65                         innerBuffer = bos;
66                         Position = bos.Offset;
67                 }
68
69                 public TlsBuffer (byte[] buffer, int offset, int size)
70                         : this (new BufferOffsetSize (buffer, offset, size))
71                 {
72                 }
73
74                 public TlsBuffer (byte[] buffer)
75                         : this (buffer, 0, buffer.Length)
76                 {
77                 }
78
79                 public TlsBuffer (int size)
80                         : this (new byte [size], 0, size)
81                 {
82                 }
83
84                 public byte ReadByte ()
85                 {
86                         if (Position >= EndOffset)
87                                 throw new TlsException (AlertDescription.DecodeError, "Buffer overflow");
88                         return Buffer [Position++];
89                 }
90
91                 public short ReadInt16 ()
92                 {
93                         if (Position + 1 >= EndOffset)
94                                 throw new TlsException (AlertDescription.DecodeError, "Buffer overflow");
95                         var retval = (short)(Buffer [Position] << 8 | Buffer [Position + 1]);
96                         Position += 2;
97                         return retval;
98                 }
99
100                 public int ReadInt24 ()
101                 {
102                         if (Position + 2 >= EndOffset)
103                                 throw new TlsException (AlertDescription.DecodeError, "Buffer overflow");
104                         var retval = ((Buffer [Position] << 16) | (Buffer [Position+1] << 8) | Buffer [Position+2]);
105                         Position += 3;
106                         return retval;
107                 }
108
109                 public int ReadInt32 ()
110                 {
111                         if (Position + 3 >= EndOffset)
112                                 throw new TlsException (AlertDescription.DecodeError, "Buffer overflow");
113                         var retval = ((Buffer [Position] << 24) | (Buffer [Position+1] << 16) | (Buffer [Position+2] << 8) | Buffer [Position+3]);
114                         Position += 4;
115                         return retval;
116                 }
117
118                 public TlsBuffer ReadBuffer (int length)
119                 {
120                         if (Position + length > EndOffset)
121                                 throw new TlsException (AlertDescription.DecodeError, "Buffer overflow");
122                         var retval = new TlsBuffer (Buffer, Position, length);
123                         Position += length;
124                         return retval;
125                 }
126
127                 public IBufferOffsetSize GetRemaining ()
128                 {
129                         return new BufferOffsetSize (Buffer, Position, Remaining);
130                 }
131
132                 protected virtual void MakeRoomInternal (int size)
133                 {
134                         if (Position + size > EndOffset)
135                                 throw new TlsException (AlertDescription.DecodeError, "Buffer overflow");
136                 }
137
138                 public void Write (byte value)
139                 {
140                         MakeRoomInternal (1);
141                         Buffer [Position++] = value;
142                 }
143
144                 public void Write (short value)
145                 {
146                         MakeRoomInternal (2);
147                         WriteInt16 (Buffer, Position, value);
148                         Position += 2;
149                 }
150
151                 public static void WriteInt16 (byte[] buffer, int offset, short value)
152                 {
153                         buffer[offset] = ((byte)(value >> 8));
154                         buffer[offset+1] = ((byte)value);
155                 }
156
157                 public void Write (int value)
158                 {
159                         MakeRoomInternal (4);
160                         WriteInt32 (Buffer, Position, value);
161                         Position += 4;
162                 }
163
164                 public void WriteInt24 (int value)
165                 {
166                         MakeRoomInternal (3);
167                         WriteInt24 (Buffer, Position, value);
168                         Position += 3;
169                 }
170
171                 #pragma warning disable 3001
172                 public void Write (ulong value)
173                 #pragma warning restore 3001
174                 {
175                         MakeRoomInternal (8);
176                         WriteInt64 (Buffer, Position, value);
177                         Position += 8;
178                 }
179
180                 public static void WriteInt24 (byte[] buffer, int offset, int value)
181                 {
182                         buffer[offset] = ((byte)(value >> 16));
183                         buffer[offset+1] = ((byte)(value >> 8));
184                         buffer[offset+2] = ((byte)value);
185                 }
186
187                 public static void WriteInt32 (byte[] buffer, int offset, int value)
188                 {
189                         buffer[offset] = ((byte)(value >> 24));
190                         buffer[offset+1] = ((byte)(value >> 16));
191                         buffer[offset+2] = ((byte)(value >> 8));
192                         buffer[offset+3] = ((byte)value);
193                 }
194
195                 #pragma warning disable 3001
196                 public static void WriteInt64 (byte[] buffer, int offset, ulong value)
197                 #pragma warning restore 3001
198                 {
199                         buffer[offset] = (byte) (value >> 56);
200                         buffer[offset+1] = (byte) (value >> 48);
201                         buffer[offset+2] = (byte) (value >> 40);
202                         buffer[offset+3] = (byte) (value >> 32);
203                         buffer[offset+4] = (byte) (value >> 24);
204                         buffer[offset+5] = (byte) (value >> 16);
205                         buffer[offset+6] = (byte) (value >> 8);
206                         buffer[offset+7] = (byte) value;
207                 }
208
209                 public void Write (byte[] buffer)
210                 {
211                         Write (buffer, 0, buffer.Length);
212                 }
213
214                 public void Write (byte[] buffer, int offset, int size)
215                 {
216                         MakeRoomInternal (size);
217                         Array.Copy (buffer, offset, Buffer, Position, size);
218                         Position += size;
219                 }
220
221                 public void Write (IBufferOffsetSize buffer)
222                 {
223                         Write (buffer.Buffer, buffer.Offset, buffer.Size);
224                 }
225
226                 public SecureBuffer ReadSecureBuffer (int count)
227                 {
228                         return new SecureBuffer (ReadBytes (count));
229                 }
230
231                 public byte[] ReadBytes (int count)
232                 {
233                         if (Position + count > EndOffset)
234                                 throw new TlsException (AlertDescription.DecodeError, "Buffer overflow");
235                         var retval = new byte [count];
236                         Array.Copy (Buffer, Position, retval, 0, count);
237                         Position += count;
238                         return retval;
239                 }
240
241                 internal static bool Compare (SecureBuffer buffer1, SecureBuffer buffer2)
242                 {
243                         if (buffer1 == null || buffer2 == null)
244                                 return false;
245
246                         if (buffer1.Size != buffer2.Size)
247                                 return false;
248
249                         for (int i = 0; i < buffer1.Size; i++) {
250                                 if (buffer1.Buffer [i] != buffer2.Buffer [i])
251                                         return false;
252                         }
253                         return true;
254                 }
255
256                 public static bool Compare (IBufferOffsetSize buffer1, IBufferOffsetSize buffer2)
257                 {
258                         if (buffer1 == null || buffer2 == null)
259                                 return false;
260
261                         if (buffer1.Size != buffer2.Size)
262                                 return false;
263
264                         for (int i = 0; i < buffer1.Size; i++) {
265                                 if (buffer1.Buffer [buffer1.Offset + i] != buffer2.Buffer [buffer2.Offset + i])
266                                         return false;
267                         }
268                         return true;
269                 }
270
271                 public static bool Compare (byte[] buffer1, byte[] buffer2)
272                 {
273                         if (buffer1 == null || buffer2 == null)
274                                 return false;
275
276                         return Compare (buffer1, 0, buffer1.Length, buffer2, 0, buffer2.Length);
277                 }
278
279                 public static bool Compare (byte[] buffer1, int offset1, int size1, byte[] buffer2, int offset2, int size2)
280                 {
281                         if (buffer1 == null || buffer2 == null)
282                                 return false;
283
284                         if (size1 != size2)
285                                 return false;
286
287                         for (int i = 0; i < size1; i++) {
288                                 if (buffer1 [offset1 + i] != buffer2 [offset2 + i])
289                                         return false;
290                         }
291                         return true;
292
293                 }
294
295                 public static int ConstantTimeCompare (byte[] buffer1, int offset1, int size1, byte[] buffer2, int offset2, int size2)
296                 {
297                         int status = 0;
298                         int effectiveSize;
299                         if (size1 < size2) {
300                                 status--;
301                                 effectiveSize = size1;
302                         } else if (size2 < size1) {
303                                 status--;
304                                 effectiveSize = size2;
305                         } else {
306                                 effectiveSize = size1;
307                         }
308
309                         for (int i = 0; i < effectiveSize; i++) {
310                                 if (buffer1 [offset1 + i] != buffer2 [offset2 + i])
311                                         status--;
312                         }
313
314                         return status;
315                 }
316
317                 protected void SetBuffer (byte[] buffer, int offset, int size)
318                 {
319                         innerBuffer = new BufferOffsetSize (buffer, offset, size);
320                 }
321
322                 protected override void Clear ()
323                 {
324                         var disposable = innerBuffer as IDisposable;
325                         if (disposable != null)
326                                 disposable.Dispose ();
327                         innerBuffer = null;
328                         Position = 0;
329                 }
330
331                 public static readonly byte[] EmptyArray = new byte [0];
332         }
333 }
334