5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2015 Xamarin Inc. (http://www.xamarin.com)
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:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
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
27 #if MONO_FEATURE_NEW_TLS && SECURITY_DEP
28 #if MONO_SECURITY_ALIAS
29 extern alias MonoSecurity;
32 #if MONO_SECURITY_ALIAS
33 using MX = MonoSecurity::Mono.Security.X509;
34 using MonoSecurity::Mono.Security.Interface;
36 using MX = Mono.Security.X509;
37 using Mono.Security.Interface;
40 using System.Runtime.InteropServices;
41 using System.Security.Authentication.ExtendedProtection;
42 using System.Security.Cryptography.X509Certificates;
43 using MNS = Mono.Net.Security;
45 namespace System.Net.Security
47 internal class SSPIInterface
49 public IMonoTlsContext Context {
54 public IMonoTlsEventSink EventSink {
59 public SSPIInterface (IMonoTlsContext context, IMonoTlsEventSink eventSink)
62 EventSink = eventSink;
66 internal static class GlobalSSPI
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)
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);
83 * SSPIWrapper _is a _class that provides a managed implementation of the equivalent
84 * _class _in Microsofts .NET Framework.
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.
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.
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.
98 * The "internal" methods here are the API that is consumed by the class
101 internal static class SSPIWrapper
103 static void SetCredentials (SSPIInterface secModule, SafeFreeCredentials credentials)
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);
111 credentials.DangerousAddRef (ref success);
116 * @safecontext is null on the first use, but it will become non-null for invocations
117 * where the connection is being re-negotiated.
120 internal static int AcceptSecurityContext (SSPIInterface secModule, ref SafeFreeCredentials credentials, ref SafeDeleteContext safeContext, ContextFlags inFlags, Endianness endianness, SecurityBuffer inputBuffer, SecurityBuffer outputBuffer, ref ContextFlags outFlags)
122 if (endianness != Endianness.Native)
123 throw new NotSupportedException ();
125 if (safeContext == null) {
126 if (credentials == null || credentials.IsInvalid)
127 return (int)SecurityStatus.CredentialsNeeded;
129 secModule.Context.Initialize (secModule.EventSink);
130 safeContext = new SafeDeleteContext (secModule.Context);
133 SetCredentials (secModule, credentials);
135 var incoming = GetInputBuffer (inputBuffer);
136 IBufferOffsetSize outgoing;
138 var retval = (int)safeContext.Context.GenerateNextToken (incoming, out outgoing);
139 UpdateOutput (outgoing, outputBuffer);
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)
145 if (inputBuffer != null)
146 throw new InvalidOperationException ();
148 if (safeContext == null) {
149 secModule.Context.Initialize (secModule.EventSink);
150 safeContext = new SafeDeleteContext (secModule.Context);
153 return InitializeSecurityContext (secModule, credentials, ref safeContext, targetName, inFlags, endianness, null, outputBuffer, ref outFlags);
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)
158 if (endianness != Endianness.Native)
159 throw new NotSupportedException ();
161 SetCredentials (secModule, credentials);
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];
170 var incoming = GetInputBuffer (inputBuffer);
171 IBufferOffsetSize outgoing = null;
173 var retval = (int)safeContext.Context.GenerateNextToken (incoming, out outgoing);
174 UpdateOutput (outgoing, outputBuffer);
178 internal static int EncryptMessage (SSPIInterface secModule, SafeDeleteContext safeContext, SecurityBuffer securityBuffer, uint sequenceNumber)
180 var incoming = GetInputBuffer (securityBuffer);
181 var retval = (int)safeContext.Context.EncryptMessage (ref incoming);
182 UpdateOutput (incoming, securityBuffer);
186 internal static int DecryptMessage (SSPIInterface secModule, SafeDeleteContext safeContext, SecurityBuffer securityBuffer, uint sequenceNumber)
188 var incoming = GetInputBuffer (securityBuffer);
189 var retval = (int)safeContext.Context.DecryptMessage (ref incoming);
190 UpdateOutput (incoming, securityBuffer);
194 internal static byte[] CreateShutdownMessage (SSPIInterface secModule, SafeDeleteContext safeContext)
196 return safeContext.Context.CreateCloseNotify ();
199 internal static byte[] CreateHelloRequestMessage (SSPIInterface secModule, SafeDeleteContext safeContext)
201 return safeContext.Context.CreateHelloRequest ();
204 internal static bool IsClosed (SSPIInterface secModule, SafeDeleteContext safeContext)
206 return safeContext.Context.ReceivedCloseNotify;
209 internal static SafeFreeCredentials AcquireCredentialsHandle (SSPIInterface SecModule, string package, CredentialUse intent, SecureCredential scc)
211 return new SafeFreeCredentials (scc);
214 public static ChannelBinding QueryContextChannelBinding (SSPIInterface SecModule, SafeDeleteContext securityContext, ContextAttribute contextAttribute)
219 internal static X509Certificate2 GetRemoteCertificate (SafeDeleteContext safeContext, out X509Certificate2Collection remoteCertificateStore)
221 X509CertificateCollection monoCollection;
222 if (safeContext == null || safeContext.IsInvalid) {
223 remoteCertificateStore = null;
226 var monoCert = safeContext.Context.GetRemoteCertificate (out monoCollection);
227 if (monoCert == null) {
228 remoteCertificateStore = null;
232 remoteCertificateStore = new X509Certificate2Collection ();
233 foreach (var cert in monoCollection) {
234 remoteCertificateStore.Add (cert);
236 return (X509Certificate2)monoCert;
239 internal static bool CheckRemoteCertificate (SafeDeleteContext safeContext)
241 return safeContext.Context.VerifyRemoteCertificate ();
244 internal static MonoTlsConnectionInfo GetMonoConnectionInfo (SSPIInterface SecModule, SafeDeleteContext securityContext)
246 return securityContext.Context.GetConnectionInfo ();
249 internal static SslConnectionInfo GetConnectionInfo (SSPIInterface SecModule, SafeDeleteContext securityContext)
251 var info = securityContext.Context.GetConnectionInfo ();
255 return new SslConnectionInfo ((int)info.ProtocolVersion);
258 class InputBuffer : IBufferOffsetSize
260 public byte[] Buffer {
275 public InputBuffer (byte[] buffer, int offset, int size)
283 static IBufferOffsetSize GetInputBuffer (SecurityBuffer incoming)
285 return incoming != null ? new InputBuffer (incoming.token, incoming.offset, incoming.size) : null;
288 static void UpdateOutput (IBufferOffsetSize buffer, SecurityBuffer outputBuffer)
290 if (buffer != null) {
291 outputBuffer.token = buffer.Buffer;
292 outputBuffer.offset = buffer.Offset;
293 outputBuffer.size = buffer.Size;
294 outputBuffer.type = BufferType.Token;
296 outputBuffer.token = null;
297 outputBuffer.size = outputBuffer.offset = 0;
298 outputBuffer.type = BufferType.Empty;