[runtime] Document mkbundle AOT options in man pages
[mono.git] / mcs / class / System / Mono.Btls / MonoBtlsProvider.cs
1 //
2 // MonoBtlsProvider.cs
3 //
4 // Author:
5 //       Martin Baulig <martin.baulig@xamarin.com>
6 //
7 // Copyright (c) 2016 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 #if SECURITY_DEP && MONO_FEATURE_BTLS
27 #if MONO_SECURITY_ALIAS
28 extern alias MonoSecurity;
29 #endif
30
31 using System;
32 using System.IO;
33 using System.Threading;
34 using System.Threading.Tasks;
35 using System.Net.Security;
36 using System.Security.Cryptography.X509Certificates;
37 using System.Security.Authentication;
38
39 #if MONO_SECURITY_ALIAS
40 using MonoSecurity::Mono.Security.Interface;
41 using MX = MonoSecurity::Mono.Security.X509;
42 #else
43 using Mono.Security.Interface;
44 using MX = Mono.Security.X509;
45 #endif
46
47 using MNS = Mono.Net.Security;
48
49 namespace Mono.Btls
50 {
51         class MonoBtlsProvider : MonoTlsProvider
52         {
53                 public override Guid ID {
54                         get { return MNS.MonoTlsProviderFactory.BtlsId; }
55                 }
56                 public override string Name {
57                         get { return "btls"; }
58                 }
59
60                 internal MonoBtlsProvider ()
61                 {
62                         if (!MNS.MonoTlsProviderFactory.IsBtlsSupported ())
63                                 throw new NotSupportedException ("BTLS is not supported in this runtime.");
64                 }
65
66                 public override bool SupportsSslStream {
67                         get { return true; }
68                 }
69
70                 public override bool SupportsMonoExtensions {
71                         get { return true; }
72                 }
73
74                 public override bool SupportsConnectionInfo {
75                         get { return true; }
76                 }
77
78                 public override SslProtocols SupportedProtocols {
79                         get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
80                 }
81
82                 public override IMonoSslStream CreateSslStream (
83                         Stream innerStream, bool leaveInnerStreamOpen,
84                         MonoTlsSettings settings = null)
85                 {
86                         return SslStream.CreateMonoSslStream (innerStream, leaveInnerStreamOpen, this, settings);
87                 }
88
89                 internal override IMonoSslStream CreateSslStreamInternal (
90                         SslStream sslStream, Stream innerStream, bool leaveInnerStreamOpen,
91                         MonoTlsSettings settings)
92                 {
93                         return new MonoBtlsStream (
94                                 innerStream, leaveInnerStreamOpen, sslStream, settings, this);
95                 }
96
97                 internal override bool HasNativeCertificates {
98                         get { return true; }
99                 }
100
101                 internal override X509Certificate2Impl GetNativeCertificate (
102                         byte[] data, string password, X509KeyStorageFlags flags)
103                 {
104                         var impl = new X509CertificateImplBtls (false);
105                         impl.Import (data, password, flags);
106                         return impl;
107                 }
108
109                 internal override X509Certificate2Impl GetNativeCertificate (
110                         X509Certificate certificate)
111                 {
112                         var impl = certificate.Impl as X509CertificateImplBtls;
113                         if (impl != null)
114                                 return (X509Certificate2Impl)impl.Clone ();
115
116                         var data = certificate.GetRawCertData ();
117                         return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER, false);
118                 }
119
120                 internal static MonoBtlsX509VerifyParam GetVerifyParam (MonoTlsSettings settings, string targetHost, bool serverMode)
121                 {
122                         MonoBtlsX509VerifyParam param;
123                         if (serverMode)
124                                 param = MonoBtlsX509VerifyParam.GetSslClient ();
125                         else
126                                 param = MonoBtlsX509VerifyParam.GetSslServer ();
127
128                         if (targetHost == null && settings?.CertificateValidationTime == null)
129                                 return param;
130
131                         try {
132                                 var copy = param.Copy ();
133                                 if (targetHost != null)
134                                         copy.SetHost (targetHost);
135                                 if (settings?.CertificateValidationTime != null)
136                                         copy.SetTime (settings.CertificateValidationTime.Value);
137                                 return copy;
138                         } finally {
139                                 param.Dispose ();
140                         }
141                 }
142
143                 internal override bool ValidateCertificate (
144                         ICertificateValidator2 validator, string targetHost, bool serverMode,
145                         X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
146                         ref MonoSslPolicyErrors errors, ref int status11)
147                 {
148                         if (chain != null) {
149                                 var chainImpl = (X509ChainImplBtls)chain.Impl;
150                                 var success = chainImpl.StoreCtx.VerifyResult == 1;
151                                 CheckValidationResult (
152                                         validator, targetHost, serverMode, certificates,
153                                         wantsChain, chain, chainImpl.StoreCtx,
154                                         success, ref errors, ref status11);
155                                 return success;
156                         }
157
158                         using (var store = new MonoBtlsX509Store ())
159                         using (var nativeChain = MonoBtlsProvider.GetNativeChain (certificates))
160                         using (var param = GetVerifyParam (validator.Settings, targetHost, serverMode))
161                         using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
162                                 SetupCertificateStore (store, validator.Settings, serverMode);
163
164                                 storeCtx.Initialize (store, nativeChain);
165
166                                 storeCtx.SetVerifyParam (param);
167
168                                 var ret = storeCtx.Verify ();
169
170                                 var success = ret == 1;
171
172                                 if (wantsChain && chain == null) {
173                                         chain = GetManagedChain (nativeChain);
174                                 }
175
176                                 CheckValidationResult (
177                                         validator, targetHost, serverMode, certificates,
178                                         wantsChain, null, storeCtx,
179                                         success, ref errors, ref status11);
180                                 return success;
181                         }
182                 }
183
184                 internal static bool ValidateCertificate (MonoBtlsX509Chain chain, MonoBtlsX509VerifyParam param)
185                 {
186                         using (var store = new MonoBtlsX509Store ())
187                         using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
188                                 /*
189                                  * We're called from X509Certificate2.Verify() via X509CertificateImplBtls.Verify().
190                                  *
191                                  * Use the default settings and assume client-mode.
192                                  */
193                                 SetupCertificateStore (store, MonoTlsSettings.DefaultSettings, false);
194
195                                 storeCtx.Initialize (store, chain);
196
197                                 if (param != null)
198                                         storeCtx.SetVerifyParam (param);
199
200                                 var ret = storeCtx.Verify ();
201
202                                 return ret == 1;
203                         }
204                 }
205
206                 void CheckValidationResult (
207                         ICertificateValidator validator, string targetHost, bool serverMode,
208                         X509CertificateCollection certificates, bool wantsChain,
209                         X509Chain chain, MonoBtlsX509StoreCtx storeCtx,
210                         bool success, ref MonoSslPolicyErrors errors, ref int status11)
211                 {
212                         if (!success) {
213                                 errors = MonoSslPolicyErrors.RemoteCertificateChainErrors;
214                                 status11 = unchecked((int)0x800B010B);
215                         }
216                 }
217
218                 internal static void SetupCertificateStore (MonoBtlsX509Store store, MonoTlsSettings settings, bool server)
219                 {
220                         /*
221                          * In server-mode, we only add certificates which are explicitly trusted via
222                          * MonoTlsSettings.TrustAnchors.
223                          * 
224                          * MonoTlsSettings.CertificateSearchPaths is ignored on Android.
225                          * 
226                          */
227
228 #if MONODROID
229                         AddTrustedRoots (store, settings, server);
230                         if (!server)
231                                 SetupDefaultCertificateStore (store);
232                         return;
233 #else
234                         if (server || settings?.CertificateSearchPaths == null) {
235                                 AddTrustedRoots (store, settings, server);
236                                 if (!server)
237                                         SetupDefaultCertificateStore (store);
238                                 return;
239                         }
240
241                         foreach (var path in settings.CertificateSearchPaths) {
242                                 switch (path) {
243                                 case "@default":
244                                         AddTrustedRoots (store, settings, server);
245                                         AddUserStore (store);
246                                         AddMachineStore (store);
247                                         break;
248                                 case "@trusted":
249                                         AddTrustedRoots (store, settings, server);
250                                         break;
251                                 case "@user":
252                                         AddUserStore (store);
253                                         break;
254                                 case "@machine":
255                                         AddMachineStore (store);
256                                         break;
257                                 default:
258                                         if (path.StartsWith ("@pem:")) {
259                                                 var realPath = path.Substring (5);
260                                                 if (Directory.Exists (realPath))
261                                                         store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.PEM);
262                                                 break;
263                                         } else if (path.StartsWith ("@der:")) {
264                                                 var realPath = path.Substring (5);
265                                                 if (Directory.Exists (realPath))
266                                                         store.AddDirectoryLookup (realPath, MonoBtlsX509FileType.ASN1);
267                                                 break;
268                                         }
269                                         throw new NotSupportedException (string.Format ("Invalid item `{0}' in MonoTlsSettings.CertificateSearchPaths.", path));
270                                 }
271                         }
272 #endif
273                 }
274
275                 static void SetupDefaultCertificateStore (MonoBtlsX509Store store)
276                 {
277 #if MONODROID
278                         store.SetDefaultPaths ();
279                         store.AddAndroidLookup ();
280 #else
281                         AddUserStore (store);
282                         AddMachineStore (store);
283 #endif
284                 }
285
286 #if !MONODROID
287                 static void AddUserStore (MonoBtlsX509Store store)
288                 {
289                         var userPath = MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.UserTrustedRoots);
290                         if (Directory.Exists (userPath))
291                                 store.AddDirectoryLookup (userPath, MonoBtlsX509FileType.PEM);
292                 }
293
294                 static void AddMachineStore (MonoBtlsX509Store store)
295                 {
296                         var machinePath = MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.MachineTrustedRoots);
297                         if (Directory.Exists (machinePath))
298                                 store.AddDirectoryLookup (machinePath, MonoBtlsX509FileType.PEM);
299                 }
300 #endif
301
302                 static void AddTrustedRoots (MonoBtlsX509Store store, MonoTlsSettings settings, bool server)
303                 {
304                         if (settings?.TrustAnchors == null)
305                                 return;
306                         var trust = server ? MonoBtlsX509TrustKind.TRUST_CLIENT : MonoBtlsX509TrustKind.TRUST_SERVER;
307                         store.AddCollection (settings.TrustAnchors, trust);
308                 }
309
310                 public static string GetSystemStoreLocation ()
311                 {
312 #if MONODROID
313                         return "/system/etc/security/cacerts";
314 #else
315                         return MonoBtlsX509StoreManager.GetStorePath (MonoBtlsX509StoreType.MachineTrustedRoots);
316 #endif
317                 }
318
319                 public static X509Certificate CreateCertificate (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
320                 {
321                         using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
322                                 return new X509Certificate (impl);
323                         }
324                 }
325
326                 public static X509Certificate2 CreateCertificate2 (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
327                 {
328                         using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
329                                 return new X509Certificate2 (impl);
330                         }
331                 }
332
333                 public static X509Certificate2 CreateCertificate2 (byte[] data, string password, bool disallowFallback = false)
334                 {
335                         using (var impl = new X509CertificateImplBtls (disallowFallback)) {
336                                 impl.Import (data, password, X509KeyStorageFlags.DefaultKeySet);
337                                 return new X509Certificate2 (impl);
338                         }
339                 }
340
341                 public static X509Certificate CreateCertificate (MonoBtlsX509 x509)
342                 {
343                         using (var impl = new X509CertificateImplBtls (x509, true))
344                                 return new X509Certificate (impl);
345                 }
346
347                 public static X509Chain CreateChain ()
348                 {
349                         using (var impl = new X509ChainImplBtls ())
350                                 return new X509Chain (impl);
351                 }
352
353                 public static X509Chain GetManagedChain (MonoBtlsX509Chain chain)
354                 {
355                         var impl = new X509ChainImplBtls (chain);
356                         return new X509Chain (impl);
357                 }
358
359                 public static MonoBtlsX509 GetBtlsCertificate (X509Certificate certificate)
360                 {
361                         var impl = certificate.Impl as X509CertificateImplBtls;
362                         if (impl != null)
363                                 return impl.X509.Copy ();
364
365                         return MonoBtlsX509.LoadFromData (certificate.GetRawCertData (), MonoBtlsX509Format.DER);
366                 }
367
368                 public static MonoBtlsX509Chain GetNativeChain (X509CertificateCollection certificates)
369                 {
370                         var chain = new MonoBtlsX509Chain ();
371                         try {
372                                 foreach (var cert in certificates) {
373                                         using (var x509 = GetBtlsCertificate (cert))
374                                                 chain.AddCertificate (x509);
375                                 }
376                                 return chain;
377                         } catch {
378                                 chain.Dispose ();
379                                 throw;
380                         }
381                 }
382         }
383 }
384 #endif