Fix symbolicate tests stack trace diff on Windows
[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
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.Runtime.CompilerServices;
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                 static readonly Guid id = new Guid ("432d18c9-9348-4b90-bfbf-9f2a10e1f15b");
54
55                 public override Guid ID {
56                         get { return id; }
57                 }
58                 public override string Name {
59                         get { return "btls"; }
60                 }
61
62                 [MethodImpl (MethodImplOptions.InternalCall)]
63                 public extern static bool IsSupported ();
64
65                 internal MonoBtlsProvider ()
66                 {
67                         if (!IsSupported ())
68                                 throw new NotSupportedException ("BTLS is not supported in this runtime.");
69                 }
70
71                 public override bool SupportsSslStream {
72                         get { return true; }
73                 }
74
75                 public override bool SupportsMonoExtensions {
76                         get { return true; }
77                 }
78
79                 public override bool SupportsConnectionInfo {
80                         get { return true; }
81                 }
82
83                 public override SslProtocols SupportedProtocols {
84                         get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
85                 }
86
87                 public override IMonoSslStream CreateSslStream (
88                         Stream innerStream, bool leaveInnerStreamOpen,
89                         MonoTlsSettings settings = null)
90                 {
91                         return new MonoBtlsStream (
92                                 innerStream, leaveInnerStreamOpen, settings, this);
93                 }
94
95                 internal override bool HasNativeCertificates {
96                         get { return true; }
97                 }
98
99                 internal override X509Certificate2Impl GetNativeCertificate (
100                         byte[] data, string password, X509KeyStorageFlags flags)
101                 {
102                         var impl = new X509CertificateImplBtls (true);
103                         impl.Import (data, password, flags);
104                         return impl;
105                 }
106
107                 internal override X509Certificate2Impl GetNativeCertificate (
108                         X509Certificate certificate)
109                 {
110                         var impl = certificate.Impl as X509CertificateImplBtls;
111                         if (impl != null)
112                                 return (X509Certificate2Impl)impl.Clone ();
113
114                         var data = certificate.GetRawCertData ();
115                         return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER, false);
116                 }
117
118                 internal static MonoBtlsX509VerifyParam GetVerifyParam (string targetHost, bool serverMode)
119                 {
120                         MonoBtlsX509VerifyParam param;
121                         if (serverMode)
122                                 param = MonoBtlsX509VerifyParam.GetSslClient ();
123                         else
124                                 param = MonoBtlsX509VerifyParam.GetSslServer ();
125
126                         if (string.IsNullOrEmpty (targetHost))
127                                 return param;
128
129                         try {
130                                 var copy = param.Copy ();
131                                 copy.SetHost (targetHost);
132                                 return copy;
133                         } finally {
134                                 param.Dispose ();
135                         }
136                 }
137
138                 internal override bool ValidateCertificate (
139                         ICertificateValidator2 validator, string targetHost, bool serverMode,
140                         X509CertificateCollection certificates, bool wantsChain, ref X509Chain chain,
141                         ref MonoSslPolicyErrors errors, ref int status11)
142                 {
143                         if (chain != null) {
144                                 var chainImpl = (X509ChainImplBtls)chain.Impl;
145                                 var success = chainImpl.StoreCtx.VerifyResult == 1;
146                                 CheckValidationResult (
147                                         validator, targetHost, serverMode, certificates,
148                                         wantsChain, chain, chainImpl.StoreCtx,
149                                         success, ref errors, ref status11);
150                                 return success;
151                         }
152
153                         using (var store = new MonoBtlsX509Store ())
154                         using (var nativeChain = MonoBtlsProvider.GetNativeChain (certificates))
155                         using (var param = GetVerifyParam (targetHost, serverMode))
156                         using (var storeCtx = new MonoBtlsX509StoreCtx ()) {
157                                 store.LoadLocations (null, GetSystemStoreLocation ());
158                                 store.SetDefaultPaths ();
159
160                                 storeCtx.Initialize (store, nativeChain);
161
162                                 storeCtx.SetVerifyParam (param);
163
164                                 var ret = storeCtx.Verify ();
165
166                                 var success = ret == 1;
167
168                                 if (wantsChain && chain == null) {
169                                         chain = GetManagedChain (nativeChain);
170                                 }
171
172                                 CheckValidationResult (
173                                         validator, targetHost, serverMode, certificates,
174                                         wantsChain, null, storeCtx,
175                                         success, ref errors, ref status11);
176                                 return success;
177                         }
178                 }
179
180                 void CheckValidationResult (
181                         ICertificateValidator validator, string targetHost, bool serverMode,
182                         X509CertificateCollection certificates, bool wantsChain,
183                         X509Chain chain, MonoBtlsX509StoreCtx storeCtx,
184                         bool success, ref MonoSslPolicyErrors errors, ref int status11)
185                 {
186                         if (!success) {
187                                 errors = MonoSslPolicyErrors.RemoteCertificateChainErrors;
188                                 status11 = unchecked((int)0x800B010B);
189                         }
190                 }
191
192                 public static string GetSystemStoreLocation ()
193                 {
194 #if ANDROID
195                         return "/system/etc/security/cacerts";
196 #else
197                         var appData = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
198                         var path = Path.Combine (appData, ".mono", "certs", "NewTrust");
199                         return path;
200 #endif
201                 }
202
203                 public static X509Certificate CreateCertificate (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
204                 {
205                         using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
206                                 return new X509Certificate (impl);
207                         }
208                 }
209
210                 public static X509Certificate2 CreateCertificate2 (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
211                 {
212                         using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
213                                 return new X509Certificate2 (impl);
214                         }
215                 }
216
217                 public static X509Certificate2 CreateCertificate2 (byte[] data, string password, bool disallowFallback = false)
218                 {
219                         using (var impl = new X509CertificateImplBtls (disallowFallback)) {
220                                 impl.Import (data, password, X509KeyStorageFlags.DefaultKeySet);
221                                 return new X509Certificate2 (impl);
222                         }
223                 }
224
225                 public static X509Certificate CreateCertificate (MonoBtlsX509 x509)
226                 {
227                         using (var impl = new X509CertificateImplBtls (x509, true))
228                                 return new X509Certificate (impl);
229                 }
230
231                 public static X509Chain CreateChain ()
232                 {
233                         using (var impl = new X509ChainImplBtls ())
234                                 return new X509Chain (impl);
235                 }
236
237                 public static X509Chain GetManagedChain (MonoBtlsX509Chain chain)
238                 {
239                         var impl = new X509ChainImplBtls (chain);
240                         return new X509Chain (impl);
241                 }
242
243                 public static MonoBtlsX509 GetBtlsCertificate (X509Certificate certificate)
244                 {
245                         var impl = certificate.Impl as X509CertificateImplBtls;
246                         if (impl != null)
247                                 return impl.X509.Copy ();
248
249                         return MonoBtlsX509.LoadFromData (certificate.GetRawCertData (), MonoBtlsX509Format.DER);
250                 }
251
252                 public static MonoBtlsX509Chain GetNativeChain (X509CertificateCollection certificates)
253                 {
254                         var chain = new MonoBtlsX509Chain ();
255                         try {
256                                 foreach (var cert in certificates) {
257                                         using (var x509 = GetBtlsCertificate (cert))
258                                                 chain.AddCertificate (x509);
259                                 }
260                                 return chain;
261                         } catch {
262                                 chain.Dispose ();
263                                 throw;
264                         }
265                 }
266         }
267 }
268 #endif