Merge pull request #2803 from BrzVlad/feature-conc-pinned-scan
[mono.git] / mcs / class / System / Mono.Net.Security / MonoTlsProviderFactory.cs
1 //
2 // MonoTlsProviderFactory.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2015 Xamarin, Inc.
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 SECURITY_DEP
28 #if MONO_SECURITY_ALIAS
29 extern alias MonoSecurity;
30 using MSI = MonoSecurity::Mono.Security.Interface;
31 using MX = MonoSecurity::Mono.Security.X509;
32 #else
33 using MSI = Mono.Security.Interface;
34 using MX = Mono.Security.X509;
35 #endif
36 using System.Security.Cryptography.X509Certificates;
37 #endif
38
39 using System;
40 using System.Net;
41 using System.Collections.Generic;
42
43 #if !MOBILE
44 using System.Reflection;
45 #endif
46
47 namespace Mono.Net.Security
48 {
49         /*
50          * Keep in sync with Mono.Security/Mono.Security.Interface/MonoTlsProvider.cs.
51          *
52          */
53         static partial class MonoTlsProviderFactory
54         {
55                 #region Internal API
56
57                 /*
58                  * APIs in this section are for consumption within System.dll only - do not access via
59                  * reflection or from friend assemblies.
60                  * 
61                  * @IMonoTlsProvider is defined as empty interface outside 'SECURITY_DEP', so we don't need
62                  * this conditional here.
63                  */
64
65                 internal static IMonoTlsProvider GetProviderInternal ()
66                 {
67                         lock (locker) {
68                                 if (currentProvider != null)
69                                         return currentProvider;
70
71                                 try {
72                                         defaultProvider = GetDefaultProviderInternal ();
73                                 } catch (Exception ex) {
74                                         throw new NotSupportedException ("TLS Support not available.", ex);
75                                 }
76
77                                 if (defaultProvider == null)
78                                         throw new NotSupportedException ("TLS Support not available.");
79
80                                 currentProvider = defaultProvider;
81                                 return currentProvider;
82                         }
83                 }
84
85                 internal static IMonoTlsProvider GetDefaultProviderInternal ()
86                 {
87                         lock (locker) {
88                                 if (defaultProvider != null)
89                                         return defaultProvider;
90
91                                 try {
92                                         defaultProvider = CreateDefaultProvider ();
93                                 } catch (Exception ex) {
94                                         throw new NotSupportedException ("TLS Support not available.", ex);
95                                 }
96
97                                 if (defaultProvider == null)
98                                         throw new NotSupportedException ("TLS Support not available.");
99
100                                 return defaultProvider;
101                         }
102                 }
103
104 #if MONO_FEATURE_NEW_SYSTEM_SOURCE || (!MONOTOUCH && !XAMMAC)
105                 static IMonoTlsProvider CreateDefaultProvider ()
106                 {
107 #if SECURITY_DEP
108 #if MONO_FEATURE_NEW_SYSTEM_SOURCE
109                         /*
110                          * This is a hack, which is used in the Mono.Security.Providers.NewSystemSource
111                          * assembly, which will provide a "fake" System.dll.  Use the public Mono.Security
112                          * API to get the "real" System.dll's provider via reflection, then wrap it with
113                          * the "fake" version's perceived view.
114                          *
115                          * NewSystemSource needs to compile MonoTlsProviderFactory.cs, IMonoTlsProvider.cs,
116                          * MonoTlsProviderWrapper.cs and CallbackHelpers.cs from this directory and only these.
117                          */
118                         var userProvider = MSI.MonoTlsProviderFactory.GetProvider ();
119                         return new Private.MonoTlsProviderWrapper (userProvider);
120 #else
121                         return CreateDefaultProviderImpl ();
122 #endif
123 #else
124                         return null;
125 #endif
126                 }
127 #endif
128
129                 static object locker = new object ();
130                 static IMonoTlsProvider defaultProvider;
131                 static IMonoTlsProvider currentProvider;
132
133                 #endregion
134
135 #if SECURITY_DEP && !MONO_FEATURE_NEW_SYSTEM_SOURCE
136
137                 static Dictionary<string,string> providerRegistration;
138
139                 static Type LookupProviderType (string name, bool throwOnError)
140                 {
141                         lock (locker) {
142                                 InitializeProviderRegistration ();
143                                 string typeName;
144                                 if (!providerRegistration.TryGetValue (name, out typeName)) {
145                                         if (throwOnError)
146                                                 throw new NotSupportedException (string.Format ("No such TLS Provider: `{0}'.", name));
147                                         return null;
148                                 }
149                                 var type = Type.GetType (typeName, false);
150                                 if (type == null && throwOnError)
151                                         throw new NotSupportedException (string.Format ("Could not find TLS Provider: `{0}'.", typeName));
152                                 return type;
153                         }
154                 }
155
156                 static MSI.MonoTlsProvider LookupProvider (string name, bool throwOnError)
157                 {
158                         var type = LookupProviderType (name, throwOnError);
159                         if (type == null)
160                                 return null;
161
162                         try {
163                                 return (MSI.MonoTlsProvider)Activator.CreateInstance (type);
164                         } catch (Exception ex) {
165                                 throw new NotSupportedException (string.Format ("Unable to instantiate TLS Provider `{0}'.", type), ex);
166                         }
167                 }
168
169                 static void InitializeProviderRegistration ()
170                 {
171                         lock (locker) {
172                                 if (providerRegistration != null)
173                                         return;
174                                 providerRegistration = new Dictionary<string,string> ();
175                                 providerRegistration.Add ("newtls", "Mono.Security.Providers.NewTls.NewTlsProvider, Mono.Security.Providers.NewTls, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756");
176                                 providerRegistration.Add ("oldtls", "Mono.Security.Providers.OldTls.OldTlsProvider, Mono.Security.Providers.OldTls, Version=4.0.0.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756");
177                                 providerRegistration.Add ("boringtls", "Xamarin.BoringTls.BoringTlsProvider, Xamarin.BoringTls, Version=4.0.0.0, Culture=neutral, PublicKeyToken=672c06b0b8f05406");
178                                 X509Helper2.Initialize ();
179                         }
180                 }
181
182 #if !MOBILE
183                 static IMonoTlsProvider TryDynamicLoad ()
184                 {
185                         var variable = Environment.GetEnvironmentVariable ("MONO_TLS_PROVIDER");
186                         if (variable == null)
187                                 return null;
188
189                         if (string.Equals (variable, "default", StringComparison.OrdinalIgnoreCase))
190                                 return null;
191
192                         var provider = LookupProvider (variable, true);
193
194                         return new Private.MonoTlsProviderWrapper (provider);
195                 }
196 #endif
197
198                 static IMonoTlsProvider CreateDefaultProviderImpl ()
199                 {
200 #if !MOBILE
201                         var provider = TryDynamicLoad ();
202                         if (provider != null)
203                                 return provider;
204 #endif
205
206                         return new Private.MonoDefaultTlsProvider ();
207                 }
208
209                 #region Mono.Security visible API
210
211                 /*
212                  * "Public" section, intended to be consumed via reflection.
213                  * 
214                  * Mono.Security.dll provides a public wrapper around these.
215                  */
216
217                 internal static MSI.MonoTlsProvider GetProvider ()
218                 {
219                         var provider = GetProviderInternal ();
220                         if (provider == null)
221                                 throw new NotSupportedException ("No TLS Provider available.");
222
223                         return provider.Provider;
224                 }
225
226                 internal static MSI.MonoTlsProvider GetDefaultProvider ()
227                 {
228                         var provider = GetDefaultProviderInternal ();
229                         if (provider == null)
230                                 throw new NotSupportedException ("No TLS Provider available.");
231
232                         return provider.Provider;
233                 }
234
235                 internal static MSI.MonoTlsProvider GetProvider (string name)
236                 {
237                         return LookupProvider (name, false);
238                 }
239
240                 internal static bool HasProvider {
241                         get {
242                                 lock (locker) {
243                                         return currentProvider != null;
244                                 }
245                         }
246                 }
247
248                 internal static void SetDefaultProvider (string name)
249                 {
250                         lock (locker) {
251                                 var provider = LookupProvider (name, true);
252                                 currentProvider = new Private.MonoTlsProviderWrapper (provider);
253                         }
254                 }
255
256                 internal static HttpWebRequest CreateHttpsRequest (Uri requestUri, MSI.MonoTlsProvider provider, MSI.MonoTlsSettings settings)
257                 {
258                         lock (locker) {
259                                 var internalProvider = provider != null ? new Private.MonoTlsProviderWrapper (provider) : null;
260                                 return new HttpWebRequest (requestUri, internalProvider, settings);
261                         }
262                 }
263
264                 internal static HttpListener CreateHttpListener (X509Certificate certificate, MSI.MonoTlsProvider provider, MSI.MonoTlsSettings settings)
265                 {
266                         lock (locker) {
267                                 var internalProvider = provider != null ? new Private.MonoTlsProviderWrapper (provider) : null;
268                                 return new HttpListener (certificate, internalProvider, settings);
269                         }
270                 }
271                 #endregion
272
273 #endif
274
275         }
276 }
277