[sgen] Untag the vtable during concurrent mark
[mono.git] / mcs / class / System / ReferenceSources / SSPIWrapper.cs
1 //
2 // SSPIWrapper.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2015 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
27 #if MONO_FEATURE_NEW_TLS && SECURITY_DEP
28 #if MONO_SECURITY_ALIAS
29 extern alias MonoSecurity;
30 #endif
31
32 #if MONO_SECURITY_ALIAS
33 using MX = MonoSecurity::Mono.Security.X509;
34 using MonoSecurity::Mono.Security.Interface;
35 #else
36 using MX = Mono.Security.X509;
37 using Mono.Security.Interface;
38 #endif
39
40 using System.Runtime.InteropServices;
41 using System.Security.Authentication.ExtendedProtection;
42 using System.Security.Cryptography.X509Certificates;
43 using MNS = Mono.Net.Security;
44
45 namespace System.Net.Security
46 {
47         internal class SSPIInterface
48         {
49                 public IMonoTlsContext Context {
50                         get;
51                         private set;
52                 }
53
54                 public IMonoTlsEventSink EventSink {
55                         get;
56                         private set;
57                 }
58
59                 public SSPIInterface (IMonoTlsContext context, IMonoTlsEventSink eventSink)
60                 {
61                         Context = context;
62                         EventSink = eventSink;
63                 }
64         }
65
66         internal static class GlobalSSPI
67         {
68                 internal static SSPIInterface Create (string hostname, bool serverMode, SchProtocols protocolFlags, X509Certificate serverCertificate, X509CertificateCollection clientCertificates,
69                                                            bool remoteCertRequired, bool checkCertName, bool checkCertRevocationStatus, EncryptionPolicy encryptionPolicy,
70                                                            LocalCertSelectionCallback certSelectionDelegate, RemoteCertValidationCallback remoteValidationCallback, SSPIConfiguration userConfig)
71                 {
72                         if (userConfig.Settings != null && remoteValidationCallback != null)
73                                 throw new InvalidOperationException ();
74                         var context = userConfig.Provider.CreateTlsContext (
75                                 hostname, serverMode, (TlsProtocols)protocolFlags, serverCertificate, clientCertificates,
76                                 remoteCertRequired, checkCertName, checkCertRevocationStatus,
77                                 (MonoEncryptionPolicy)encryptionPolicy, userConfig.Settings);
78                         return new SSPIInterface (context, userConfig.EventSink);
79                 }
80         }
81
82         /*
83          * SSPIWrapper _is a _class that provides a managed implementation of the equivalent
84          * _class _in Microsofts .NET Framework.   
85          * 
86          * The SSPIWrapper class is used by the TLS/SSL stack to implement both the 
87          * protocol handshake as well as the encryption and decryption of messages.
88          * 
89          * Microsoft's implementation of this class is merely a P/Invoke wrapper
90          * around the native SSPI APIs on Windows.   This implementation instead, 
91          * provides a managed implementation that uses the cross platform Mono.Security 
92          * to provide the equivalent functionality.
93          * 
94          * Ideally, this should be abstracted with a different name, and decouple
95          * the naming from the SSPIWrapper name, but this allows Mono to reuse
96          * the .NET code with minimal changes.
97          * 
98          * The "internal" methods here are the API that is consumed by the class
99          * libraries.
100          */
101         internal static class SSPIWrapper
102         {
103                 static void SetCredentials (SSPIInterface secModule, SafeFreeCredentials credentials)
104                 {
105                         if (credentials != null && !credentials.IsInvalid) {
106                                 if (!secModule.Context.HasCredentials && credentials.Certificate != null) {
107                                         var cert = new X509Certificate2 (credentials.Certificate.RawData);
108                                         secModule.Context.SetCertificate (cert, credentials.Certificate.PrivateKey);
109                                 }
110                                 bool success = true;
111                                 credentials.DangerousAddRef (ref success);
112                         }
113                 }
114
115                 /*
116                  * @safecontext is null on the first use, but it will become non-null for invocations 
117                  * where the connection is being re-negotiated.
118                  * 
119                 */
120                 internal static int AcceptSecurityContext (SSPIInterface secModule, ref SafeFreeCredentials credentials, ref SafeDeleteContext safeContext, ContextFlags inFlags, Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlags outFlags)
121                 {
122                         if (endianness != Endianness.Native)
123                                 throw new NotSupportedException ();
124
125                         if (safeContext == null) {
126                                 if (credentials == null || credentials.IsInvalid)
127                                         return (int)SecurityStatus.CredentialsNeeded;
128
129                                 secModule.Context.Initialize (secModule.EventSink);
130                                 safeContext = new SafeDeleteContext (secModule.Context);
131                         }
132
133                         SetCredentials (secModule, credentials);
134
135                         var incoming = GetInputBuffer (inputBuffer);
136                         IBufferOffsetSize outgoing;
137
138                         var retval = (int)safeContext.Context.GenerateNextToken (incoming, out outgoing);
139                         UpdateOutput (outgoing, outputBuffer);
140                         return retval;
141                 }
142
143                 internal static int InitializeSecurityContext (SSPIInterface secModule, ref SafeFreeCredentials credentials, ref SafeDeleteContext safeContext, string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlags outFlags)
144                 {
145                         if (inputBuffer != null)
146                                 throw new InvalidOperationException ();
147
148                         if (safeContext == null) {
149                                 secModule.Context.Initialize (secModule.EventSink);
150                                 safeContext = new SafeDeleteContext (secModule.Context);
151                         }
152
153                         return InitializeSecurityContext (secModule, credentials, ref safeContext, targetName, inFlags, endianness, null, outputBuffer, ref outFlags);
154                 }
155
156                 internal static int InitializeSecurityContext (SSPIInterface secModule, SafeFreeCredentials credentials, ref SafeDeleteContext safeContext, string targetName, ContextFlags inFlags, Endianness endianness, SecurityBuffer[] inputBuffers, SecurityBuffer outputBuffer, ref ContextFlags outFlags)
157                 {
158                         if (endianness != Endianness.Native)
159                                 throw new NotSupportedException ();
160
161                         SetCredentials (secModule, credentials);
162
163                         SecurityBuffer inputBuffer = null;
164                         if (inputBuffers != null) {
165                                 if (inputBuffers.Length != 2 || inputBuffers [1].type != BufferType.Empty)
166                                         throw new NotSupportedException ();
167                                 inputBuffer = inputBuffers [0];
168                         }
169
170                         var incoming = GetInputBuffer (inputBuffer);
171                         IBufferOffsetSize outgoing = null;
172
173                         var retval = (int)safeContext.Context.GenerateNextToken (incoming, out outgoing);
174                         UpdateOutput (outgoing, outputBuffer);
175                         return retval;
176                 }
177
178                 internal static int EncryptMessage (SSPIInterface secModule, SafeDeleteContext safeContext, SecurityBuffer securityBuffer, uint sequenceNumber)
179                 {
180                         var incoming = GetInputBuffer (securityBuffer);
181                         var retval = (int)safeContext.Context.EncryptMessage (ref incoming);
182                         UpdateOutput (incoming, securityBuffer);
183                         return retval;
184                 }
185
186                 internal static int DecryptMessage (SSPIInterface secModule, SafeDeleteContext safeContext, SecurityBuffer securityBuffer, uint sequenceNumber)
187                 {
188                         var incoming = GetInputBuffer (securityBuffer);
189                         var retval = (int)safeContext.Context.DecryptMessage (ref incoming);
190                         UpdateOutput (incoming, securityBuffer);
191                         return retval;
192                 }
193
194                 internal static byte[] CreateShutdownMessage (SSPIInterface secModule, SafeDeleteContext safeContext)
195                 {
196                         return safeContext.Context.CreateCloseNotify ();
197                 }
198
199                 internal static byte[] CreateHelloRequestMessage (SSPIInterface secModule, SafeDeleteContext safeContext)
200                 {
201                         return safeContext.Context.CreateHelloRequest ();
202                 }
203
204                 internal static bool IsClosed (SSPIInterface secModule, SafeDeleteContext safeContext)
205                 {
206                         return safeContext.Context.ReceivedCloseNotify;
207                 }
208
209                 internal static SafeFreeCredentials AcquireCredentialsHandle (SSPIInterface SecModule, string package, CredentialUse intent, SecureCredential scc)
210                 {
211                         return new SafeFreeCredentials (scc);
212                 }
213
214                 public static ChannelBinding QueryContextChannelBinding (SSPIInterface SecModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute)
215                 {
216                         return null;
217                 }
218
219                 internal static X509Certificate2 GetRemoteCertificate (SafeDeleteContext safeContext, out X509Certificate2Collection remoteCertificateStore)
220                 {
221                         X509CertificateCollection monoCollection;
222                         if (safeContext == null || safeContext.IsInvalid) {
223                                 remoteCertificateStore = null;
224                                 return null;
225                         }
226                         var monoCert = safeContext.Context.GetRemoteCertificate (out monoCollection);
227                         if (monoCert == null) {
228                                 remoteCertificateStore = null;
229                                 return null;
230                         }
231
232                         remoteCertificateStore = new X509Certificate2Collection ();
233                         foreach (var cert in monoCollection) {
234                                 remoteCertificateStore.Add (cert);
235                         }
236                         return (X509Certificate2)monoCert;
237                 }
238
239                 internal static bool CheckRemoteCertificate (SafeDeleteContext safeContext)
240                 {
241                         return safeContext.Context.VerifyRemoteCertificate ();
242                 }
243
244                 internal static MonoTlsConnectionInfo GetMonoConnectionInfo (SSPIInterface SecModule, SafeDeleteContext securityContext)
245                 {
246                         return securityContext.Context.GetConnectionInfo ();
247                 }
248
249                 internal static SslConnectionInfo GetConnectionInfo (SSPIInterface SecModule, SafeDeleteContext securityContext)
250                 {
251                         var info = securityContext.Context.GetConnectionInfo ();
252                         if (info == null)
253                                 return null;
254
255                         return new SslConnectionInfo ((int)info.ProtocolVersion);
256                 }
257
258                 class InputBuffer : IBufferOffsetSize
259                 {
260                         public byte[] Buffer {
261                                 get;
262                                 private set;
263                         }
264
265                         public int Offset {
266                                 get;
267                                 private set;
268                         }
269
270                         public int Size {
271                                 get;
272                                 private set;
273                         }
274
275                         public InputBuffer (byte[] buffer, int offset, int size)
276                         {
277                                 Buffer = buffer;
278                                 Offset = offset;
279                                 Size = size;
280                         }
281                 }
282
283                 static IBufferOffsetSize GetInputBuffer (SecurityBuffer incoming)
284                 {
285                         return incoming != null ? new InputBuffer (incoming.token, incoming.offset, incoming.size) : null;
286                 }
287
288                 static void UpdateOutput (IBufferOffsetSize buffer, SecurityBuffer outputBuffer)
289                 {
290                         if (buffer != null) {
291                                 outputBuffer.token = buffer.Buffer;
292                                 outputBuffer.offset = buffer.Offset;
293                                 outputBuffer.size = buffer.Size;
294                                 outputBuffer.type = BufferType.Token;
295                         } else {
296                                 outputBuffer.token = null;
297                                 outputBuffer.size = outputBuffer.offset = 0;
298                                 outputBuffer.type = BufferType.Empty;
299                         }
300                 }
301         }
302 }
303 #endif