5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2016 Xamarin Inc. (http://www.xamarin.com)
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
27 #if MONO_SECURITY_ALIAS
28 extern alias MonoSecurity;
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;
39 #if MONO_SECURITY_ALIAS
40 using MonoSecurity::Mono.Security.Interface;
41 using MX = MonoSecurity::Mono.Security.X509;
43 using Mono.Security.Interface;
44 using MX = Mono.Security.X509;
47 using MNS = Mono.Net.Security;
51 class MonoBtlsProvider : MonoTlsProvider
53 static readonly Guid id = new Guid ("432d18c9-9348-4b90-bfbf-9f2a10e1f15b");
55 public override Guid ID {
58 public override string Name {
59 get { return "btls"; }
62 [MethodImpl (MethodImplOptions.InternalCall)]
63 public extern static bool IsSupported ();
65 internal MonoBtlsProvider ()
68 throw new NotSupportedException ("BTLS is not supported in this runtime.");
71 public override bool SupportsSslStream {
75 public override bool SupportsMonoExtensions {
79 public override bool SupportsConnectionInfo {
83 public override SslProtocols SupportedProtocols {
84 get { return SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls; }
87 public override IMonoSslStream CreateSslStream (
88 Stream innerStream, bool leaveInnerStreamOpen,
89 MonoTlsSettings settings = null)
91 return new MonoBtlsStream (
92 innerStream, leaveInnerStreamOpen, settings, this);
95 internal override bool HasNativeCertificates {
99 internal override X509Certificate2Impl GetNativeCertificate (
100 byte[] data, string password, X509KeyStorageFlags flags)
102 var impl = new X509CertificateImplBtls (true);
103 impl.Import (data, password, flags);
107 internal override X509Certificate2Impl GetNativeCertificate (
108 X509Certificate certificate)
110 var impl = certificate.Impl as X509CertificateImplBtls;
112 return (X509Certificate2Impl)impl.Clone ();
114 var data = certificate.GetRawCertData ();
115 return new X509CertificateImplBtls (data, MonoBtlsX509Format.DER, false);
118 internal static MonoBtlsX509VerifyParam GetVerifyParam (string targetHost, bool serverMode)
120 MonoBtlsX509VerifyParam param;
122 param = MonoBtlsX509VerifyParam.GetSslClient ();
124 param = MonoBtlsX509VerifyParam.GetSslServer ();
126 if (string.IsNullOrEmpty (targetHost))
130 var copy = param.Copy ();
131 copy.SetHost (targetHost);
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)
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);
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 ();
160 storeCtx.Initialize (store, nativeChain);
162 storeCtx.SetVerifyParam (param);
164 var ret = storeCtx.Verify ();
166 var success = ret == 1;
168 if (wantsChain && chain == null) {
169 chain = GetManagedChain (nativeChain);
172 CheckValidationResult (
173 validator, targetHost, serverMode, certificates,
174 wantsChain, null, storeCtx,
175 success, ref errors, ref status11);
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)
187 errors = MonoSslPolicyErrors.RemoteCertificateChainErrors;
188 status11 = unchecked((int)0x800B010B);
192 public static string GetSystemStoreLocation ()
195 return "/system/etc/security/cacerts";
197 var appData = Environment.GetFolderPath (Environment.SpecialFolder.ApplicationData);
198 var path = Path.Combine (appData, ".mono", "certs", "NewTrust");
203 public static X509Certificate CreateCertificate (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
205 using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
206 return new X509Certificate (impl);
210 public static X509Certificate2 CreateCertificate2 (byte[] data, MonoBtlsX509Format format, bool disallowFallback = false)
212 using (var impl = new X509CertificateImplBtls (data, format, disallowFallback)) {
213 return new X509Certificate2 (impl);
217 public static X509Certificate2 CreateCertificate2 (byte[] data, string password, bool disallowFallback = false)
219 using (var impl = new X509CertificateImplBtls (disallowFallback)) {
220 impl.Import (data, password, X509KeyStorageFlags.DefaultKeySet);
221 return new X509Certificate2 (impl);
225 public static X509Certificate CreateCertificate (MonoBtlsX509 x509)
227 using (var impl = new X509CertificateImplBtls (x509, true))
228 return new X509Certificate (impl);
231 public static X509Chain CreateChain ()
233 using (var impl = new X509ChainImplBtls ())
234 return new X509Chain (impl);
237 public static X509Chain GetManagedChain (MonoBtlsX509Chain chain)
239 var impl = new X509ChainImplBtls (chain);
240 return new X509Chain (impl);
243 public static MonoBtlsX509 GetBtlsCertificate (X509Certificate certificate)
245 var impl = certificate.Impl as X509CertificateImplBtls;
247 return impl.X509.Copy ();
249 return MonoBtlsX509.LoadFromData (certificate.GetRawCertData (), MonoBtlsX509Format.DER);
252 public static MonoBtlsX509Chain GetNativeChain (X509CertificateCollection certificates)
254 var chain = new MonoBtlsX509Chain ();
256 foreach (var cert in certificates) {
257 using (var x509 = GetBtlsCertificate (cert))
258 chain.AddCertificate (x509);