Merge pull request #5714 from alexischr/update_bockbuild
[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
29 #if MONO_SECURITY_ALIAS
30 extern alias MonoSecurity;
31 using MSI = MonoSecurity::Mono.Security.Interface;
32 using MX = MonoSecurity::Mono.Security.X509;
33 #else
34 using MSI = Mono.Security.Interface;
35 using MX = Mono.Security.X509;
36 #endif
37 using System.Security.Cryptography.X509Certificates;
38
39 using System;
40 using System.Net;
41 using System.Diagnostics;
42 using System.Collections.Generic;
43 using System.Runtime.CompilerServices;
44
45 #if MONO_FEATURE_BTLS
46 using Mono.Btls;
47 #endif
48
49 #if MONO_FEATURE_APPLETLS
50 using Mono.AppleTls;
51 #endif
52
53 #if !MOBILE
54 using System.Reflection;
55 #endif
56
57 namespace Mono.Net.Security
58 {
59         /*
60          * Keep in sync with Mono.Security/Mono.Security.Interface/MonoTlsProvider.cs.
61          *
62          */
63         static partial class MonoTlsProviderFactory
64         {
65 #region Internal API
66
67                 /*
68                  * APIs in this section are for consumption within System.dll only - do not access via
69                  * reflection or from friend assemblies.
70                  * 
71                  */
72
73                 internal static MSI.MonoTlsProvider GetProviderInternal ()
74                 {
75                         lock (locker) {
76                                 InitializeInternal ();
77                                 return defaultProvider;
78                         }
79                 }
80
81                 internal static void InitializeInternal ()
82                 {
83                         lock (locker) {
84                                 if (initialized)
85                                         return;
86
87                                 InitializeProviderRegistration ();
88
89                                 MSI.MonoTlsProvider provider;
90                                 try {
91                                         provider = CreateDefaultProviderImpl ();
92                                 } catch (Exception ex) {
93                                         throw new NotSupportedException ("TLS Support not available.", ex);
94                                 }
95
96                                 if (provider == null)
97                                         throw new NotSupportedException ("TLS Support not available.");
98
99                                 if (!providerCache.ContainsKey (provider.ID))
100                                         providerCache.Add (provider.ID, provider);
101
102                                 X509Helper2.Initialize ();
103
104                                 defaultProvider = provider;
105                                 initialized = true;
106                         }
107                 }
108
109                 internal static void InitializeInternal (string provider) 
110                 {
111                         lock (locker) {
112                                 if (initialized)
113                                         throw new NotSupportedException ("TLS Subsystem already initialized.");
114
115                                 defaultProvider = LookupProvider (provider, true);
116
117                                 X509Helper2.Initialize ();
118                                 initialized = true;
119                         }
120                 }
121
122                 static object locker = new object ();
123                 static bool initialized;
124
125                 static MSI.MonoTlsProvider defaultProvider;
126
127                 /*
128                  * @providerRegistration maps provider names to a tuple containing its ID and full type name.
129                  * On non-reflection enabled systems (such as XI and XM), we can use the Guid to uniquely
130                  * identify the provider.
131                  *
132                  * @providerCache maps the provider's Guid to the MSI.MonoTlsProvider instance.
133                  *
134                  */
135                 static Dictionary<string,Tuple<Guid,string>> providerRegistration;
136                 static Dictionary<Guid,MSI.MonoTlsProvider> providerCache;
137
138 #if !ONLY_APPLETLS && !MONOTOUCH && !XAMMAC
139                 static Type LookupProviderType (string name, bool throwOnError)
140                 {
141                         lock (locker) {
142                                 InitializeProviderRegistration ();
143                                 Tuple<Guid,string> entry;
144                                 if (!providerRegistration.TryGetValue (name, out entry)) {
145                                         if (throwOnError)
146                                                 throw new NotSupportedException (string.Format ("No such TLS Provider: `{0}'.", name));
147                                         return null;
148                                 }
149                                 var type = Type.GetType (entry.Item2, false);
150                                 if (type == null && throwOnError)
151                                         throw new NotSupportedException (string.Format ("Could not find TLS Provider: `{0}'.", entry.Item2));
152                                 return type;
153                         }
154                 }
155 #endif
156
157                 static MSI.MonoTlsProvider LookupProvider (string name, bool throwOnError)
158                 {
159                         lock (locker) {
160                                 InitializeProviderRegistration ();
161                                 Tuple<Guid,string> entry;
162                                 if (!providerRegistration.TryGetValue (name, out entry)) {
163                                         if (throwOnError)
164                                                 throw new NotSupportedException (string.Format ("No such TLS Provider: `{0}'.", name));
165                                         return null;
166                                 }
167
168                                 // Check cache before doing the reflection lookup.
169                                 MSI.MonoTlsProvider provider;
170                                 if (providerCache.TryGetValue (entry.Item1, out provider))
171                                         return provider;
172
173 #if !ONLY_APPLETLS && !MONOTOUCH && !XAMMAC
174                                 var type = Type.GetType (entry.Item2, false);
175                                 if (type == null && throwOnError)
176                                         throw new NotSupportedException (string.Format ("Could not find TLS Provider: `{0}'.", entry.Item2));
177
178                                 try {
179                                         provider = (MSI.MonoTlsProvider)Activator.CreateInstance (type, true);
180                                 } catch (Exception ex) {
181                                         throw new NotSupportedException (string.Format ("Unable to instantiate TLS Provider `{0}'.", type), ex);
182                                 }
183 #endif
184
185                                 if (provider == null) {
186                                         if (throwOnError)
187                                                 throw new NotSupportedException (string.Format ("No such TLS Provider: `{0}'.", name));
188                                         return null;
189                                 }
190
191                                 providerCache.Add (entry.Item1, provider);
192                                 return provider;
193                         }
194                 }
195
196                 static bool enableDebug;
197
198                 [Conditional ("MONO_TLS_DEBUG")]
199                 static void InitializeDebug ()
200                 {
201                         if (Environment.GetEnvironmentVariable ("MONO_TLS_DEBUG") != null)
202                                 enableDebug = true;
203                 }
204
205                 [Conditional ("MONO_TLS_DEBUG")]
206                 internal static void Debug (string message, params object[] args)
207                 {
208                         if (enableDebug)
209                                 Console.Error.WriteLine (message, args);
210                 }
211
212 #endregion
213
214                 internal static readonly Guid AppleTlsId = new Guid ("981af8af-a3a3-419a-9f01-a518e3a17c1c");
215                 internal static readonly Guid BtlsId = new Guid ("432d18c9-9348-4b90-bfbf-9f2a10e1f15b");
216                 internal static readonly Guid LegacyId = new Guid ("809e77d5-56cc-4da8-b9f0-45e65ba9cceb");
217
218                 static void InitializeProviderRegistration ()
219                 {
220                         lock (locker) {
221                                 if (providerRegistration != null)
222                                         return;
223
224                                 InitializeDebug ();
225
226                                 providerRegistration = new Dictionary<string,Tuple<Guid,string>> ();
227                                 providerCache = new Dictionary<Guid,MSI.MonoTlsProvider> ();
228
229                                 var appleTlsEntry = new Tuple<Guid,String> (AppleTlsId, "Mono.AppleTls.AppleTlsProvider");
230
231 #if ONLY_APPLETLS || MONOTOUCH || XAMMAC
232                                 providerRegistration.Add ("default", appleTlsEntry);
233                                 providerRegistration.Add ("apple", appleTlsEntry);
234 #else
235                                 var legacyEntry = new Tuple<Guid,String> (LegacyId, "Mono.Net.Security.LegacyTlsProvider");
236                                 providerRegistration.Add ("legacy", legacyEntry);
237
238                                 Tuple<Guid,String> btlsEntry = null;
239 #if MONO_FEATURE_BTLS
240                                 if (IsBtlsSupported ()) {
241                                         btlsEntry = new Tuple<Guid,String> (BtlsId, "Mono.Btls.MonoBtlsProvider");
242                                         providerRegistration.Add ("btls", btlsEntry);
243                                 }
244 #endif
245
246                                 if (Platform.IsMacOS)
247                                         providerRegistration.Add ("default", appleTlsEntry);
248                                 else if (btlsEntry != null)
249                                         providerRegistration.Add ("default", btlsEntry);
250                                 else
251                                         providerRegistration.Add ("default", legacyEntry);
252
253                                 providerRegistration.Add ("apple", appleTlsEntry);
254 #endif
255                         }
256                 }
257
258 #region Platform-Specific code
259
260 #if MONO_FEATURE_BTLS
261                 [MethodImpl (MethodImplOptions.InternalCall)]
262                 internal extern static bool IsBtlsSupported ();
263 #endif
264
265 #if MONODROID
266                 static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
267                 {
268                         MSI.MonoTlsProvider provider = null;
269                         var type = Environment.GetEnvironmentVariable ("XA_TLS_PROVIDER");
270                         switch (type) {
271                         case null:
272                         case "default":
273                         case "legacy":
274                                 return new LegacyTlsProvider ();
275 #if MONO_FEATURE_BTLS
276                         case "btls":
277                                 if (!IsBtlsSupported ())
278                                         throw new NotSupportedException ("BTLS in not supported!");
279                                 return new MonoBtlsProvider ();
280 #endif
281                         default:
282                                 throw new NotSupportedException (string.Format ("Invalid TLS Provider: `{0}'.", provider));
283                         }
284                 }
285 #elif ONLY_APPLETLS || MONOTOUCH || XAMMAC
286                 static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
287                 {
288                         return new AppleTlsProvider ();
289                 }
290 #else
291                 static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
292                 {
293                         var variable = Environment.GetEnvironmentVariable ("MONO_TLS_PROVIDER");
294                         if (string.IsNullOrEmpty (variable))
295                                 variable = "default";
296
297                         return LookupProvider (variable, true);
298                 }
299 #endif
300
301 #endregion
302
303 #region Mono.Security visible API
304
305                 /*
306                  * "Public" section, intended to be consumed via reflection.
307                  * 
308                  * Mono.Security.dll provides a public wrapper around these.
309                  */
310
311                 internal static MSI.MonoTlsProvider GetProvider ()
312                 {
313                         var provider = GetProviderInternal ();
314                         if (provider == null)
315                                 throw new NotSupportedException ("No TLS Provider available.");
316
317                         return provider;
318                 }
319
320                 internal static bool IsProviderSupported (string name)
321                 {
322                         lock (locker) {
323                                 InitializeProviderRegistration ();
324                                 return providerRegistration.ContainsKey (name);
325                         }
326                 }
327
328                 internal static MSI.MonoTlsProvider GetProvider (string name)
329                 {
330                         return LookupProvider (name, false);
331                 }
332
333                 internal static bool IsInitialized {
334                         get {
335                                 lock (locker) {
336                                         return initialized;
337                                 }
338                         }
339                 }
340
341                 internal static void Initialize ()
342                 {
343                         InitializeInternal ();
344                 }
345
346                 internal static void Initialize (string provider)
347                 {
348                         InitializeInternal (provider);
349                 }
350 #endregion
351         }
352 }
353 #endif