I'm having a problem with a custom certificate validator when using TLS 1.2
I have set up a custom validator by inheriting from X509CertificateValidator
and implementing the Validate()
function.
However, for some reason Validate()
function never gets called, and my client gets the error:
The caller was not authenticated by the service
The inner exception:
The request for security token could not be satisfied because authentication failed.
This works fine with TLS 1.0 (with that enabled, I can set a breakpoint in Validate()
and it gets hit, but disabled, it doesn't.)
As advised by other questions, I have tried adding this both in the client and the server:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
...and this in the client's config file:
<AppContextSwitchOverrides value="Switch.System.ServiceModel.DisableUsingServicePointManagerSecurityProtocols=false;Switch.System.Net.DontEnableSchUseStrongCrypto=false;;Switch.System.Net.DontEnableSystemDefaultTlsVersions=false" />
... and this in the server's web.config file:
<add key="AppContext.SetSwitch:Switch.System.Net.DontEnableSchUseStrongCrypto" value="false" />
<add key="AppContext.SetSwitch:Switch.System.Net.DontEnableSystemDefaultTlsVersions" value="false" />
Here is the code that creates the custom validator:
protected override void ApplyConfiguration() // Overrides ServiceHost.ApplyConfiguration()
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
base.ApplyConfiguration();
var binding = new MyAppHttpBinding(); // Custom object inheriting from CustomBinding - See below...
AddServiceEndpoint(typeof(IMyService), binding);
Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
var configuration = WebConfigurationManager.OpenWebConfiguration("~");
var clientCertificate = configuration.GetCertificate("MyApp.ClientCertificate");
var serviceCertificate = configuration.GetCertificate("MyApp.ServerCertificate");
Credentials.ClientCertificate.Authentication.CustomCertificateValidator = new ThumbprintCertificateValidator(new[] { clientCertificate });
Credentials.ServiceCertificate.Certificate = serviceCertificate;
}
... and the Validate()
function...
(Doesn't appear to hit this with just TLS 1.2)
public void Validate(string thumbprint)
{
var valid = Thumbprints
.Contains(thumbprint);
if (!valid)
{
throw new SecurityTokenValidationException("Certificate thumbprint does not match any in certificate store.");
}
}
/// <summary>
/// Validates the certificate's thumbprint with those specified.
/// </summary>
public override void Validate(X509Certificate2 certificate)
{
var thumbprint = certificate.Thumbprint;
Validate(thumbprint);
}
Here is the initialisation code for MyAppHttpBinding
called from its constructor
var sslNegotiationBindingElement = SecurityBindingElement.CreateSslNegotiationBindingElement(true);
sslNegotiationBindingElement.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10;
var secureConversationBindingElement = SecurityBindingElement.CreateSecureConversationBindingElement(sslNegotiationBindingElement);
Elements.Add(new TransactionFlowBindingElement());
Elements.Add(secureConversationBindingElement);
Elements.Add(new TextMessageEncodingBindingElement());
Elements.Add(new HttpTransportBindingElement());
CodePudding user response: