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;
53 using XX509CertificateCollection = System.Security.Cryptography.X509Certificates.X509CertificateCollection;
58 using System.Threading;
59 using System.Collections;
60 using System.Collections.Generic;
61 using System.Collections.Specialized;
62 using System.Configuration;
63 using System.Net.Configuration;
64 using System.Text.RegularExpressions;
65 using System.Security.Cryptography.X509Certificates;
67 using System.Globalization;
68 using System.Net.Security;
69 using System.Diagnostics;
71 namespace Mono.Net.Security
73 internal delegate bool ServerCertValidationCallbackWrapper (ServerCertValidationCallback callback, X509Certificate certificate, X509Chain chain, MonoSslPolicyErrors sslPolicyErrors);
75 internal class ChainValidationHelper : ICertificateValidator
77 readonly object sender;
78 readonly MonoTlsSettings settings;
79 readonly MonoTlsProvider provider;
80 readonly ServerCertValidationCallback certValidationCallback;
81 readonly LocalCertSelectionCallback certSelectionCallback;
82 readonly ServerCertValidationCallbackWrapper callbackWrapper;
83 readonly MonoTlsStream tlsStream;
84 readonly HttpWebRequest request;
86 static bool is_macosx;
87 static bool is_mobile;
89 static X509RevocationMode revocation_mode;
92 static ChainValidationHelper ()
101 is_macosx = System.IO.File.Exists (OSX509Certificates.SecurityLibrary);
106 revocation_mode = X509RevocationMode.NoCheck;
108 string str = Environment.GetEnvironmentVariable ("MONO_X509_REVOCATION_MODE");
109 if (String.IsNullOrEmpty (str))
111 revocation_mode = (X509RevocationMode)Enum.Parse (typeof(X509RevocationMode), str, true);
117 internal static ICertificateValidator GetDefaultValidator (MonoTlsProvider provider, MonoTlsSettings settings)
119 if (settings == null)
120 return new ChainValidationHelper (provider, null, false, null, null);
121 if (settings.CertificateValidator != null)
122 return settings.CertificateValidator;
123 return new ChainValidationHelper (provider, settings, false, null, null);
126 #region SslStream support
129 * This is a hack which is used in SslStream - see ReferenceSources/SslStream.cs for details.
131 internal static ChainValidationHelper CloneWithCallbackWrapper (MonoTlsProvider provider, ref MonoTlsSettings settings, ServerCertValidationCallbackWrapper wrapper)
133 var helper = (ChainValidationHelper)settings.CertificateValidator;
135 helper = new ChainValidationHelper (provider, settings, true, null, wrapper);
137 helper = new ChainValidationHelper (helper, provider, settings, wrapper);
138 settings = helper.settings;
142 internal static bool InvokeCallback (ServerCertValidationCallback callback, object sender, X509Certificate certificate, X509Chain chain, MonoSslPolicyErrors sslPolicyErrors)
144 return callback.Invoke (sender, certificate, chain, (SslPolicyErrors)sslPolicyErrors);
149 ChainValidationHelper (ChainValidationHelper other, MonoTlsProvider provider, MonoTlsSettings settings, ServerCertValidationCallbackWrapper callbackWrapper = null)
151 sender = other.sender;
152 certValidationCallback = other.certValidationCallback;
153 certSelectionCallback = other.certSelectionCallback;
154 tlsStream = other.tlsStream;
155 request = other.request;
157 this.provider = provider;
158 this.settings = settings = settings.CloneWithValidator (this);
159 this.callbackWrapper = callbackWrapper;
162 internal static ChainValidationHelper Create (MonoTlsProvider provider, ref MonoTlsSettings settings, MonoTlsStream stream)
164 var helper = new ChainValidationHelper (provider, settings, true, stream, null);
165 settings = helper.settings;
169 ChainValidationHelper (MonoTlsProvider provider, MonoTlsSettings settings, bool cloneSettings, MonoTlsStream stream, ServerCertValidationCallbackWrapper callbackWrapper)
172 settings = settings.CloneWithValidator (this);
174 this.provider = provider;
175 this.settings = settings;
176 this.tlsStream = stream;
177 this.callbackWrapper = callbackWrapper;
179 var fallbackToSPM = false;
181 if (settings != null) {
182 if (settings.RemoteCertificateValidationCallback != null) {
183 var callback = Private.CallbackHelpers.MonoToPublic (settings.RemoteCertificateValidationCallback);
184 certValidationCallback = new ServerCertValidationCallback (callback);
186 certSelectionCallback = Private.CallbackHelpers.MonoToInternal (settings.ClientCertificateSelectionCallback);
187 fallbackToSPM = settings.UseServicePointManagerCallback;
190 if (stream != null) {
191 this.request = stream.Request;
192 this.sender = request;
194 if (certValidationCallback == null)
195 certValidationCallback = request.ServerCertValidationCallback;
196 if (certSelectionCallback == null)
197 certSelectionCallback = new LocalCertSelectionCallback (DefaultSelectionCallback);
199 if (settings == null)
200 fallbackToSPM = true;
203 if (fallbackToSPM && certValidationCallback == null)
204 certValidationCallback = ServicePointManager.ServerCertValidationCallback;
207 static X509Certificate DefaultSelectionCallback (string targetHost, XX509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers)
209 X509Certificate clientCertificate;
210 if (localCertificates == null || localCertificates.Count == 0)
211 clientCertificate = null;
213 clientCertificate = localCertificates [0];
214 return clientCertificate;
217 public MonoTlsProvider Provider {
218 get { return provider; }
221 public MonoTlsSettings Settings {
222 get { return settings; }
225 public bool HasCertificateSelectionCallback {
226 get { return certSelectionCallback != null; }
229 public bool SelectClientCertificate (
230 string targetHost, XX509CertificateCollection localCertificates, X509Certificate remoteCertificate,
231 string[] acceptableIssuers, out X509Certificate clientCertificate)
233 if (certSelectionCallback == null) {
234 clientCertificate = null;
237 clientCertificate = certSelectionCallback (targetHost, localCertificates, remoteCertificate, acceptableIssuers);
241 internal X509Certificate SelectClientCertificate (
242 string targetHost, XX509CertificateCollection localCertificates, X509Certificate remoteCertificate,
243 string[] acceptableIssuers)
245 if (certSelectionCallback == null)
247 return certSelectionCallback (targetHost, localCertificates, remoteCertificate, acceptableIssuers);
250 internal bool ValidateClientCertificate (X509Certificate certificate, MonoSslPolicyErrors errors)
252 var certs = new XX509CertificateCollection ();
253 certs.Add (new X509Certificate2 (certificate.GetRawCertData ()));
255 var result = ValidateChain (string.Empty, true, certs, (SslPolicyErrors)errors);
259 return result.Trusted && !result.UserDenied;
262 public ValidationResult ValidateCertificate (string host, bool serverMode, XX509CertificateCollection certs)
265 var result = ValidateChain (host, serverMode, certs, 0);
266 if (tlsStream != null)
267 tlsStream.CertificateValidationFailed = result == null || !result.Trusted || result.UserDenied;
270 if (tlsStream != null)
271 tlsStream.CertificateValidationFailed = true;
276 ValidationResult ValidateChain (string host, bool server, XX509CertificateCollection certs, SslPolicyErrors errors)
278 // user_denied is true if the user callback is called and returns false
279 bool user_denied = false;
282 var hasCallback = certValidationCallback != null || callbackWrapper != null;
284 X509Certificate leaf;
285 if (certs == null || certs.Count == 0)
290 if (tlsStream != null)
291 request.ServicePoint.SetServerCertificate (leaf);
294 errors |= SslPolicyErrors.RemoteCertificateNotAvailable;
296 if (callbackWrapper != null)
297 result = callbackWrapper.Invoke (certValidationCallback, leaf, null, (MonoSslPolicyErrors)errors);
299 result = certValidationCallback.Invoke (sender, leaf, null, errors);
300 user_denied = !result;
302 return new ValidationResult (result, user_denied, 0, (MonoSslPolicyErrors)errors);
305 ICertificatePolicy policy = ServicePointManager.GetLegacyCertificatePolicy ();
307 int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
308 X509Chain chain = null;
310 bool providerValidated = false;
311 if (provider != null && provider.HasCustomSystemCertificateValidator) {
312 if (SystemCertificateValidator.NeedsChain (settings))
313 throw new NotSupportedException ("Cannot use MonoTlsProvider.InvokeSystemCertificateValidator() when the X509Chain is required.");
314 var xerrors = (MonoSslPolicyErrors)errors;
315 providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, out result, ref xerrors, ref status11);
316 errors = (SslPolicyErrors)xerrors;
319 if (!providerValidated)
320 result = SystemCertificateValidator.Evaluate (settings, host, certs, ref chain, ref errors, ref status11);
322 if (policy != null && (!(policy is DefaultCertificatePolicy) || certValidationCallback == null)) {
323 ServicePoint sp = null;
325 sp = request.ServicePointNoLock;
326 if (status11 == 0 && errors != 0) {
328 status11 = unchecked ((int)0x800B010B);
332 result = policy.CheckValidationResult (sp, leaf, request, status11);
333 user_denied = !result && !(policy is DefaultCertificatePolicy);
335 // If there's a 2.0 callback, it takes precedence
337 if (callbackWrapper != null)
338 result = callbackWrapper.Invoke (certValidationCallback, leaf, chain, (MonoSslPolicyErrors)errors);
340 result = certValidationCallback.Invoke (sender, leaf, chain, errors);
341 user_denied = !result;
343 return new ValidationResult (result, user_denied, status11, (MonoSslPolicyErrors)errors);
346 public bool InvokeSystemValidator (string targetHost, bool serverMode, XX509CertificateCollection certificates, ref MonoSslPolicyErrors xerrors, ref int status11)
348 if (SystemCertificateValidator.NeedsChain (settings))
349 throw new NotSupportedException ("Cannot use ICertificateValidator.InvokeSystemValidator() when the X509Chain is required.");
351 X509Chain chain = null;
352 var errors = (SslPolicyErrors)xerrors;
353 var result = SystemCertificateValidator.Evaluate (settings, targetHost, certificates, ref chain, ref errors, ref status11);
354 xerrors = (MonoSslPolicyErrors)errors;