*/
ValidationResult ValidateCertificate (string targetHost, bool serverMode, X509CertificateCollection certificates);
+ /*
+ * On OS X and Mobile, the @chain will be initialized with the @certificates, but not actually built.
+ */
bool InvokeSystemValidator (
string targetHost, bool serverMode, X509CertificateCollection certificates,
- ref MonoSslPolicyErrors errors, ref int status11);
+ X509Chain chain, ref MonoSslPolicyErrors errors, ref int status11);
}
public static class CertificateValidationHelper
/*
* If @serverMode is true, then we're a server and want to validate a certificate
* that we received from a client.
- *
+ *
+ * On OS X and Mobile, the @chain will be initialized with the @certificates, but not actually built.
+ *
* Returns `true` if certificate validation has been performed and `false` to invoke the
* default system validator.
*/
public virtual bool InvokeSystemCertificateValidator (
ICertificateValidator validator, string targetHost, bool serverMode,
- X509CertificateCollection certificates, out bool success,
+ X509CertificateCollection certificates, X509Chain chain, out bool success,
ref MonoSslPolicyErrors errors, ref int status11)
{
success = false;
#endif
#if MONO_X509_ALIAS
using XX509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
+using XX509Chain = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509Chain;
#else
using XX509CertificateCollection = System.Security.Cryptography.X509Certificates.X509CertificateCollection;
+using XX509Chain = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509Chain;
#endif
using System;
int status11 = 0; // Error code passed to the obsolete ICertificatePolicy callback
X509Chain chain = null;
+ bool wantsChain = SystemCertificateValidator.NeedsChain (settings);
+ if (!wantsChain && hasCallback) {
+ if (settings == null || settings.CallbackNeedsCertificateChain)
+ wantsChain = true;
+ }
+
+ if (wantsChain)
+ chain = SystemCertificateValidator.CreateX509Chain (certs);
+
+ if (wantsChain || SystemCertificateValidator.NeedsChain (settings))
+ SystemCertificateValidator.BuildX509Chain (certs, chain, ref errors, ref status11);
+
bool providerValidated = false;
if (provider != null && provider.HasCustomSystemCertificateValidator) {
- if (SystemCertificateValidator.NeedsChain (settings))
- throw new NotSupportedException ("Cannot use MonoTlsProvider.InvokeSystemCertificateValidator() when the X509Chain is required.");
var xerrors = (MonoSslPolicyErrors)errors;
- providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, out result, ref xerrors, ref status11);
+ var xchain = (XX509Chain)(object)chain;
+ providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, xchain, out result, ref xerrors, ref status11);
errors = (SslPolicyErrors)xerrors;
}
if (!providerValidated)
- result = SystemCertificateValidator.Evaluate (settings, host, certs, ref chain, ref errors, ref status11);
+ result = SystemCertificateValidator.Evaluate (settings, host, certs, chain, ref errors, ref status11);
if (policy != null && (!(policy is DefaultCertificatePolicy) || certValidationCallback == null)) {
ServicePoint sp = null;
return new ValidationResult (result, user_denied, status11, (MonoSslPolicyErrors)errors);
}
- public bool InvokeSystemValidator (string targetHost, bool serverMode, XX509CertificateCollection certificates, ref MonoSslPolicyErrors xerrors, ref int status11)
+ public bool InvokeSystemValidator (string targetHost, bool serverMode, XX509CertificateCollection certificates, XX509Chain xchain, ref MonoSslPolicyErrors xerrors, ref int status11)
{
- if (SystemCertificateValidator.NeedsChain (settings))
- throw new NotSupportedException ("Cannot use ICertificateValidator.InvokeSystemValidator() when the X509Chain is required.");
-
- X509Chain chain = null;
+ X509Chain chain = (X509Chain)(object)xchain;
var errors = (SslPolicyErrors)xerrors;
- var result = SystemCertificateValidator.Evaluate (settings, targetHost, certificates, ref chain, ref errors, ref status11);
+ var result = SystemCertificateValidator.Evaluate (settings, targetHost, certificates, chain, ref errors, ref status11);
xerrors = (MonoSslPolicyErrors)errors;
return result;
}
#endif
#if MONO_X509_ALIAS
using XX509CertificateCollection = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509CertificateCollection;
+using XX509Chain = PrebuiltSystem::System.Security.Cryptography.X509Certificates.X509Chain;
#else
using XX509CertificateCollection = System.Security.Cryptography.X509Certificates.X509CertificateCollection;
+using XX509Chain = System.Security.Cryptography.X509Certificates.X509Chain;
#endif
using System;
#endif
}
- static X509Chain ComputeX509Chain (XX509CertificateCollection certs, ref SslPolicyErrors errors, ref int status11)
+ public static X509Chain CreateX509Chain (XX509CertificateCollection certs)
{
-#if MOBILE
- return null;
-#else
- if (is_macosx)
- return null;
-
var chain = new X509Chain ();
chain.ChainPolicy = new X509ChainPolicy ();
+#if !MOBILE
chain.ChainPolicy.RevocationMode = revocation_mode;
+#endif
for (int i = 1; i < certs.Count; i++) {
chain.ChainPolicy.ExtraStore.Add (certs [i]);
}
+ return chain;
+ }
+
+ public static bool BuildX509Chain (XX509CertificateCollection certs, X509Chain chain, ref SslPolicyErrors errors, ref int status11)
+ {
+#if MOBILE
+ return true;
+#else
+ if (is_macosx)
+ return true;
+
var leaf = (X509Certificate2)certs [0];
+ bool ok;
try {
- if (!chain.Build (leaf))
+ ok = chain.Build (leaf);
+ if (!ok)
errors |= GetErrorsFromChain (chain);
} catch (Exception e) {
Console.Error.WriteLine ("ERROR building certificate chain: {0}", e);
errors |= SslPolicyErrors.RemoteCertificateChainErrors;
}
- status11 = GetStatusFromChain (chain);
+ try {
+ status11 = GetStatusFromChain (chain);
+ } catch {
+ status11 = 0x800B010B; // TRUST_E_FAIL - generic
+ }
return chain;
#endif
}
- static void CheckUsage (XX509CertificateCollection certs, string host, ref SslPolicyErrors errors, ref int status11)
+ static bool CheckUsage (XX509CertificateCollection certs, string host, ref SslPolicyErrors errors, ref int status11)
{
#if !MONOTOUCH
var leaf = (X509Certificate2)certs[0];
if (!CheckCertificateUsage (leaf)) {
errors |= SslPolicyErrors.RemoteCertificateChainErrors;
status11 = -2146762490; //CERT_E_PURPOSE 0x800B0106
+ return false;
}
if (host != null && !CheckServerIdentity (leaf, host)) {
errors |= SslPolicyErrors.RemoteCertificateNameMismatch;
status11 = -2146762481; // CERT_E_CN_NO_MATCH 0x800B010F
+ return false;
}
}
#endif
+ return true;
}
static bool EvaluateSystem (XX509CertificateCollection certs, XX509CertificateCollection anchors, string host, X509Chain chain, ref SslPolicyErrors errors, ref int status11)
public static bool Evaluate (
MonoTlsSettings settings, string host, XX509CertificateCollection certs,
- ref X509Chain chain, ref SslPolicyErrors errors, ref int status11)
+ X509Chain chain, ref SslPolicyErrors errors, ref int status11)
{
-#if !MOBILE
- if (NeedsChain (settings) && chain == null)
- chain = ComputeX509Chain (certs, ref errors, ref status11);
-#endif
-
- CheckUsage (certs, host, ref errors, ref status11);
+ if (!CheckUsage (certs, host, ref errors, ref status11))
+ return false;
if (settings != null && settings.SkipSystemValidators)
return false;