2 // MonoTlsProviderFactory.cs
5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2015 Xamarin, Inc.
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
29 #if MONO_SECURITY_ALIAS
30 extern alias MonoSecurity;
31 using MSI = MonoSecurity::Mono.Security.Interface;
32 using MX = MonoSecurity::Mono.Security.X509;
34 using MSI = Mono.Security.Interface;
35 using MX = Mono.Security.X509;
37 using System.Security.Cryptography.X509Certificates;
41 using System.Diagnostics;
42 using System.Collections.Generic;
43 using System.Runtime.CompilerServices;
49 #if MONO_FEATURE_APPLETLS
54 using System.Reflection;
57 namespace Mono.Net.Security
60 * Keep in sync with Mono.Security/Mono.Security.Interface/MonoTlsProvider.cs.
63 static partial class MonoTlsProviderFactory
68 * APIs in this section are for consumption within System.dll only - do not access via
69 * reflection or from friend assemblies.
73 internal static MSI.MonoTlsProvider GetProviderInternal ()
76 InitializeInternal ();
77 return defaultProvider;
81 internal static void InitializeInternal ()
87 InitializeProviderRegistration ();
89 MSI.MonoTlsProvider provider;
91 provider = CreateDefaultProviderImpl ();
92 } catch (Exception ex) {
93 throw new NotSupportedException ("TLS Support not available.", ex);
97 throw new NotSupportedException ("TLS Support not available.");
99 if (!providerCache.ContainsKey (provider.ID))
100 providerCache.Add (provider.ID, provider);
102 X509Helper2.Initialize ();
104 defaultProvider = provider;
109 internal static void InitializeInternal (string provider)
113 throw new NotSupportedException ("TLS Subsystem already initialized.");
115 defaultProvider = LookupProvider (provider, true);
117 X509Helper2.Initialize ();
122 static object locker = new object ();
123 static bool initialized;
125 static MSI.MonoTlsProvider defaultProvider;
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.
132 * @providerCache maps the provider's Guid to the MSI.MonoTlsProvider instance.
135 static Dictionary<string,Tuple<Guid,string>> providerRegistration;
136 static Dictionary<Guid,MSI.MonoTlsProvider> providerCache;
138 #if !ONLY_APPLETLS && !MONOTOUCH && !XAMMAC
139 static Type LookupProviderType (string name, bool throwOnError)
142 InitializeProviderRegistration ();
143 Tuple<Guid,string> entry;
144 if (!providerRegistration.TryGetValue (name, out entry)) {
146 throw new NotSupportedException (string.Format ("No such TLS Provider: `{0}'.", name));
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));
157 static MSI.MonoTlsProvider LookupProvider (string name, bool throwOnError)
160 InitializeProviderRegistration ();
161 Tuple<Guid,string> entry;
162 if (!providerRegistration.TryGetValue (name, out entry)) {
164 throw new NotSupportedException (string.Format ("No such TLS Provider: `{0}'.", name));
168 // Check cache before doing the reflection lookup.
169 MSI.MonoTlsProvider provider;
170 if (providerCache.TryGetValue (entry.Item1, out provider))
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));
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);
185 if (provider == null) {
187 throw new NotSupportedException (string.Format ("No such TLS Provider: `{0}'.", name));
191 providerCache.Add (entry.Item1, provider);
196 static bool enableDebug;
198 [Conditional ("MONO_TLS_DEBUG")]
199 static void InitializeDebug ()
201 if (Environment.GetEnvironmentVariable ("MONO_TLS_DEBUG") != null)
205 [Conditional ("MONO_TLS_DEBUG")]
206 internal static void Debug (string message, params object[] args)
209 Console.Error.WriteLine (message, args);
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");
218 static void InitializeProviderRegistration ()
221 if (providerRegistration != null)
226 providerRegistration = new Dictionary<string,Tuple<Guid,string>> ();
227 providerCache = new Dictionary<Guid,MSI.MonoTlsProvider> ();
229 var appleTlsEntry = new Tuple<Guid,String> (AppleTlsId, "Mono.AppleTls.AppleTlsProvider");
231 #if ONLY_APPLETLS || MONOTOUCH || XAMMAC
232 providerRegistration.Add ("default", appleTlsEntry);
233 providerRegistration.Add ("apple", appleTlsEntry);
235 var legacyEntry = new Tuple<Guid,String> (LegacyId, "Mono.Net.Security.LegacyTlsProvider");
236 providerRegistration.Add ("legacy", legacyEntry);
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);
246 if (Platform.IsMacOS)
247 providerRegistration.Add ("default", appleTlsEntry);
248 else if (btlsEntry != null)
249 providerRegistration.Add ("default", btlsEntry);
251 providerRegistration.Add ("default", legacyEntry);
253 providerRegistration.Add ("apple", appleTlsEntry);
258 #region Platform-Specific code
260 #if MONO_FEATURE_BTLS
261 [MethodImpl (MethodImplOptions.InternalCall)]
262 internal extern static bool IsBtlsSupported ();
266 static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
268 MSI.MonoTlsProvider provider = null;
269 var type = Environment.GetEnvironmentVariable ("XA_TLS_PROVIDER");
274 return new LegacyTlsProvider ();
275 #if MONO_FEATURE_BTLS
277 if (!IsBtlsSupported ())
278 throw new NotSupportedException ("BTLS in not supported!");
279 return new MonoBtlsProvider ();
282 throw new NotSupportedException (string.Format ("Invalid TLS Provider: `{0}'.", provider));
285 #elif ONLY_APPLETLS || MONOTOUCH || XAMMAC
286 static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
288 return new AppleTlsProvider ();
291 static MSI.MonoTlsProvider CreateDefaultProviderImpl ()
293 var variable = Environment.GetEnvironmentVariable ("MONO_TLS_PROVIDER");
294 if (string.IsNullOrEmpty (variable))
295 variable = "default";
297 return LookupProvider (variable, true);
303 #region Mono.Security visible API
306 * "Public" section, intended to be consumed via reflection.
308 * Mono.Security.dll provides a public wrapper around these.
311 internal static MSI.MonoTlsProvider GetProvider ()
313 var provider = GetProviderInternal ();
314 if (provider == null)
315 throw new NotSupportedException ("No TLS Provider available.");
320 internal static bool IsProviderSupported (string name)
323 InitializeProviderRegistration ();
324 return providerRegistration.ContainsKey (name);
328 internal static MSI.MonoTlsProvider GetProvider (string name)
330 return LookupProvider (name, false);
333 internal static bool IsInitialized {
341 internal static void Initialize ()
343 InitializeInternal ();
346 internal static void Initialize (string provider)
348 InitializeInternal (provider);