2 // System.Net.ServicePointManager
5 // Lawrence Pit (loz@cable.a2000.nl)
6 // Gonzalo Paniagua Javier (gonzalo@novell.com)
8 // Copyright (c) 2003-2010 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 #if MONO_SECURITY_ALIAS
35 extern alias MonoSecurity;
38 extern alias PrebuiltSystem;
41 #if MONO_SECURITY_ALIAS
42 using MonoSecurity::Mono.Security.Interface;
43 using MSX = MonoSecurity::Mono.Security.X509;
44 using MonoSecurity::Mono.Security.X509.Extensions;
46 using Mono.Security.Interface;
47 using MSX = Mono.Security.X509;
48 using Mono.Security.X509.Extensions;
51 using XX509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
52 using XX509Chain = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509Chain;
54 using XX509CertificateCollection = System.Security.Cryptography.X509Certificates.X509CertificateCollection;
55 using XX509Chain = System.Security.Cryptography.X509Certificates.X509Chain;
60 using System.Threading;
61 using System.Collections;
62 using System.Collections.Generic;
63 using System.Collections.Specialized;
64 using System.Configuration;
65 using System.Net.Configuration;
66 using System.Text.RegularExpressions;
67 using System.Security.Cryptography.X509Certificates;
69 using System.Globalization;
70 using System.Net.Security;
71 using System.Diagnostics;
73 namespace Mono.Net.Security
75 internal delegate bool ServerCertValidationCallbackWrapper (ServerCertValidationCallback callback, X509Certificate certificate, X509Chain chain, MonoSslPolicyErrors sslPolicyErrors);
77 internal class ChainValidationHelper : ICertificateValidator
79 readonly object sender;
80 readonly MonoTlsSettings settings;
81 readonly MonoTlsProvider provider;
82 readonly ServerCertValidationCallback certValidationCallback;
83 readonly LocalCertSelectionCallback certSelectionCallback;
84 readonly ServerCertValidationCallbackWrapper callbackWrapper;
85 readonly MonoTlsStream tlsStream;
86 readonly HttpWebRequest request;
88 static bool is_macosx;
89 static bool is_mobile;
91 static X509RevocationMode revocation_mode;
94 static ChainValidationHelper ()
103 is_macosx = System.IO.File.Exists (OSX509Certificates.SecurityLibrary);
108 revocation_mode = X509RevocationMode.NoCheck;
110 string str = Environment.GetEnvironmentVariable ("MONO_X509_REVOCATION_MODE");
111 if (String.IsNullOrEmpty (str))
113 revocation_mode = (X509RevocationMode)Enum.Parse (typeof(X509RevocationMode), str, true);
119 internal static ICertificateValidator GetDefaultValidator (MonoTlsProvider provider, MonoTlsSettings settings)
121 if (settings == null)
122 return new ChainValidationHelper (provider, null, false, null, null);
123 if (settings.CertificateValidator != null)
124 return settings.CertificateValidator;
125 return new ChainValidationHelper (provider, settings, false, null, null);
128 #region SslStream support
131 * This is a hack which is used in SslStream - see ReferenceSources/SslStream.cs for details.
133 internal static ChainValidationHelper CloneWithCallbackWrapper (MonoTlsProvider provider, ref MonoTlsSettings settings, ServerCertValidationCallbackWrapper wrapper)
135 var helper = (ChainValidationHelper)settings.CertificateValidator;
137 helper = new ChainValidationHelper (provider, settings, true, null, wrapper);
139 helper = new ChainValidationHelper (helper, provider, settings, wrapper);
140 settings = helper.settings;
144 internal static bool InvokeCallback (ServerCertValidationCallback callback, object sender, X509Certificate certificate, X509Chain chain, MonoSslPolicyErrors sslPolicyErrors)
146 return callback.Invoke (sender, certificate, chain, (SslPolicyErrors)sslPolicyErrors);
151 ChainValidationHelper (ChainValidationHelper other, MonoTlsProvider provider, MonoTlsSettings settings, ServerCertValidationCallbackWrapper callbackWrapper = null)
153 sender = other.sender;
154 certValidationCallback = other.certValidationCallback;
155 certSelectionCallback = other.certSelectionCallback;
156 tlsStream = other.tlsStream;
157 request = other.request;
159 if (settings == null)
160 settings = MonoTlsSettings.DefaultSettings;
162 this.provider = provider;
163 this.settings = settings.CloneWithValidator (this);
164 this.callbackWrapper = callbackWrapper;
167 internal static ChainValidationHelper Create (MonoTlsProvider provider, ref MonoTlsSettings settings, MonoTlsStream stream)
169 var helper = new ChainValidationHelper (provider, settings, true, stream, null);
170 settings = helper.settings;
174 ChainValidationHelper (MonoTlsProvider provider, MonoTlsSettings settings, bool cloneSettings, MonoTlsStream stream, ServerCertValidationCallbackWrapper callbackWrapper)
176 if (settings == null)
177 settings = MonoTlsSettings.CopyDefaultSettings ();
179 settings = settings.CloneWithValidator (this);
181 this.provider = provider;
182 this.settings = settings;
183 this.tlsStream = stream;
184 this.callbackWrapper = callbackWrapper;
186 var fallbackToSPM = false;
188 if (settings != null) {
189 if (settings.RemoteCertificateValidationCallback != null) {
190 var callback = Private.CallbackHelpers.MonoToPublic (settings.RemoteCertificateValidationCallback);
191 certValidationCallback = new ServerCertValidationCallback (callback);
193 certSelectionCallback = Private.CallbackHelpers.MonoToInternal (settings.ClientCertificateSelectionCallback);
194 fallbackToSPM = settings.UseServicePointManagerCallback;
197 if (stream != null) {
198 this.request = stream.Request;
199 this.sender = request;
201 if (certValidationCallback == null)
202 certValidationCallback = request.ServerCertValidationCallback;
203 if (certSelectionCallback == null)
204 certSelectionCallback = new LocalCertSelectionCallback (DefaultSelectionCallback);
206 if (settings == null)
207 fallbackToSPM = true;
210 if (fallbackToSPM && certValidationCallback == null)
211 certValidationCallback = ServicePointManager.ServerCertValidationCallback;
214 static X509Certificate DefaultSelectionCallback (string targetHost, XX509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
216 X509Certificate clientCertificate;
217 if (localCertificates == null || localCertificates.Count == 0)
218 clientCertificate = null;
220 clientCertificate = localCertificates [0];
221 return clientCertificate;
224 public MonoTlsProvider Provider {
225 get { return provider; }
228 public MonoTlsSettings Settings {
229 get { return settings; }
232 public bool HasCertificateSelectionCallback {
233 get { return certSelectionCallback != null; }
236 public bool SelectClientCertificate (
237 string targetHost, XX509CertificateCollection localCertificates, X509Certificate remoteCertificate,
238 string[] acceptableIssuers, out X509Certificate clientCertificate)
240 if (certSelectionCallback == null) {
241 clientCertificate = null;
244 clientCertificate = certSelectionCallback (targetHost, localCertificates, remoteCertificate, acceptableIssuers);
248 internal X509Certificate SelectClientCertificate (
249 string targetHost, XX509CertificateCollection localCertificates, X509Certificate remoteCertificate,
250 string[] acceptableIssuers)
252 if (certSelectionCallback == null)
254 return certSelectionCallback (targetHost, localCertificates, remoteCertificate, acceptableIssuers);
257 internal bool ValidateClientCertificate (X509Certificate certificate, MonoSslPolicyErrors errors)
259 var certs = new XX509CertificateCollection ();
260 certs.Add (new X509Certificate2 (certificate.GetRawCertData ()));
262 var result = ValidateChain (string.Empty, true, certs, (SslPolicyErrors)errors);
266 return result.Trusted && !result.UserDenied;
269 public ValidationResult ValidateCertificate (string host, bool serverMode, XX509CertificateCollection certs)
272 var result = ValidateChain (host, serverMode, certs, 0);
273 if (tlsStream != null)
274 tlsStream.CertificateValidationFailed = result == null || !result.Trusted || result.UserDenied;
277 if (tlsStream != null)
278 tlsStream.CertificateValidationFailed = true;
283 ValidationResult ValidateChain (string host, bool server, XX509CertificateCollection certs, SslPolicyErrors errors)
285 // user_denied is true if the user callback is called and returns false
286 bool user_denied = false;
289 var hasCallback = certValidationCallback != null || callbackWrapper != null;
291 X509Certificate leaf;
292 if (certs == null || certs.Count == 0)
297 if (tlsStream != null)
298 request.ServicePoint.SetServerCertificate (leaf);
301 errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
303 if (callbackWrapper != null)
304 result = callbackWrapper.Invoke (certValidationCallback, leaf, null, (MonoSslPolicyErrors)errors);
306 result = certValidationCallback.Invoke (sender, leaf, null, errors);
307 user_denied = !result;
309 return new ValidationResult (result, user_denied, 0, (MonoSslPolicyErrors)errors);
312 ICertificatePolicy policy = ServicePointManager.GetLegacyCertificatePolicy ();
314 int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
315 X509Chain chain = null;
317 bool wantsChain = SystemCertificateValidator.NeedsChain (settings);
318 if (!wantsChain && hasCallback) {
319 if (settings == null || settings.CallbackNeedsCertificateChain)
324 chain = SystemCertificateValidator.CreateX509Chain (certs);
326 if (wantsChain || SystemCertificateValidator.NeedsChain (settings))
327 SystemCertificateValidator.BuildX509Chain (certs, chain, ref errors, ref status11);
329 bool providerValidated = false;
330 if (provider != null && provider.HasCustomSystemCertificateValidator) {
331 var xerrors = (MonoSslPolicyErrors)errors;
332 var xchain = (XX509Chain)(object)chain;
333 providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, xchain, out result, ref xerrors, ref status11);
334 errors = (SslPolicyErrors)xerrors;
337 if (!providerValidated)
338 result = SystemCertificateValidator.Evaluate (settings, host, certs, chain, ref errors, ref status11);
340 if (policy != null && (!(policy is DefaultCertificatePolicy) || certValidationCallback == null)) {
341 ServicePoint sp = null;
343 sp = request.ServicePointNoLock;
344 if (status11 == 0 && errors != 0) {
346 status11 = unchecked ((int)0x800B010B);
350 result = policy.CheckValidationResult (sp, leaf, request, status11);
351 user_denied = !result && !(policy is DefaultCertificatePolicy);
353 // If there's a 2.0 callback, it takes precedence
355 if (callbackWrapper != null)
356 result = callbackWrapper.Invoke (certValidationCallback, leaf, chain, (MonoSslPolicyErrors)errors);
358 result = certValidationCallback.Invoke (sender, leaf, chain, errors);
359 user_denied = !result;
361 return new ValidationResult (result, user_denied, status11, (MonoSslPolicyErrors)errors);
364 public bool InvokeSystemValidator (string targetHost, bool serverMode, XX509CertificateCollection certificates, XX509Chain xchain, ref MonoSslPolicyErrors xerrors, ref int status11)
366 X509Chain chain = (X509Chain)(object)xchain;
367 var errors = (SslPolicyErrors)xerrors;
368 var result = SystemCertificateValidator.Evaluate (settings, targetHost, certificates, chain, ref errors, ref status11);
369 xerrors = (MonoSslPolicyErrors)errors;