WCF custom certificate validation with BasicHttpBinding - c#

I have a WCF application hosted on IIS 6 that needs to
Have 2-way SSL authentication
Validate client certificate content with some client host information
Validate client certificate is issued by the valid subCA.
I was able to do 1) successfully. I am trying to achieve 2) and 3) by following this - basically creating a class that inherits X509CertificateValidator and overriding the Validate method with my own validation implementation(step 2 and 3). I followed the MSDN instructions exactly however, it seem that the Validate method is not being called. I purposely throw a SecurityAccessDeniedException in the overidden Validate method and no exception is thrown when I tried to access the service via my browser. I can still access my website with any client certificate.
I also read this thread but it didn't really help. Any help would be greatly appreciated!
Here's my configuration:
<system.serviceModel>
<services>
<service behaviorConfiguration="SimpleServiceBehavior"
name="SampleNameSpace.SampleClass">
<endpoint address=""
binding="basicHttpBinding"
bindingConfiguration="NewBinding0"
contract="SampleNameSpace.ISampleClass" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SimpleServiceBehavior">
<serviceMetadata httpsGetEnabled="true" policyVersion="Default" />
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="Custom" customCertificateValidatorType="SampleNameSpace.MyX509CertificateValidator, SampleAssembly"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="NewBinding0">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</basicHttpBinding>
</bindings>

You can also try to override certificate validation with this ServerCertificateValidationCallback
We are using it with WCF HttpBinding in such way:
System.Net.ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, policyErrors) =>
{
var isValid = false;
// some checking logic
return isValid;
};

Related

How to add user/pass authentication in WCF

I want to add some security to my WCF application service. I figured out how to add username/password authentication:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceMetadata httpGetEnabled="false" httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Changer.Service.Validation.ServiceAuthenticator, Changer.Service"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="MyBinding">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="Changer.Service.Request.RequestService" behaviorConfiguration="MyBehavior">
<endpoint address="/" binding="wsHttpBinding" contract="Changer.Service.Request.IRequestService" bindingConfiguration="MyBinding" />
</service>
</services>
</system.serviceModel>
This is my custom data validation:
public class ServiceAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
// Check the user name and password
if (userName != Authentication.Providers.Service.PasswordChanger.UserName ||
password != Authentication.Providers.Service.PasswordChanger.Password)
{
throw new System.IdentityModel.Tokens.SecurityTokenException("Unknown username or password.");
}
}
}
Unfortunelly I am getting error which is because I have no valid certificate. I tried following this tutorial:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-an-iis-hosted-wcf-service-with-ssl
But without success. It says, that certificate hosts is not matching site url I am visiting. On client side I am getting error:
Could not establish trust relationship for the SSL/TLS secure channel with authority 'foo'. The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. The remote certificate is invalid according to the validation procedure
I can solve this by adding to my client app:
System.Net.ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
Which is basically not solving my problem.. What can I do with that? I just want to have simple user/pass authentication.
I decided to get rid off SSL, then my code changed to:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="PasswordChanger.Service.Validation.ServiceAuthenticator, PasswordChanger.Service"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name ="NewBinding">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
And after that I got this error:
Error: Cannot obtain Metadata from http://localhost:53705/R.svc If this is a Windows (R) Communication Foundation service to which you have access, please check that you have enabled metadata publishing at the specified address. For help enabling metadata publishing, please refer to the MSDN documentation at www.WS-Metadata Exchange Error URI: http://localhost:53705/R.svc Metadata contains a reference that cannot be resolved: 'http://localhost:53705/R.svc'. Content Type application/soap+xml; charset=utf-8 was not supported by service http://localhost:53705/R.svc. The client and service bindings may be mismatched. The remote server returned an error: (415) Cannot process the message because the content type 'application/soap+xml; charset=utf-8' was not the expected type 'text/xml; charset=utf-8'..HTTP GET Error URI: http://localhost:53705/R.svc The HTML document does not contain Web service discovery information.
So I decided to add services tag to my web.config next to bindings
<services>
<service name="PasswordChanger.Service.Request.RequestService" behaviorConfiguration="MyBehavior">
<endpoint address="/" binding="wsHttpBinding" contract="PasswordChanger.Service.Request.IRequestService" bindingConfiguration="NewBinding" />
</service>
And I got another error:
The service certificate is not provided. Specify a service certificate in ServiceCredentials.
Whether we use the message security or transport layer security mode, we all need to provide a certificate to ensure that the username/password authentication mode is secure.
I have made an example related transport security mode. we need provide a certificate to ensure that the service is hosted successfully.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication customUserNamePasswordValidatorType="WcfService1.CustUserNamePasswordVal,WcfService1" userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding>
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<protocolMapping>
<add binding="wsHttpBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
If we don’t have a certificate, we could generate a self-signed certificate by using IIS Server Certificate Tool.
then we add https binding in the IIS website binding module so that the WCF service is hosted successfully.
Custom Authentication class. Based on the actual situation, configure this authentication class in the configuration file above.
internal class CustUserNamePasswordVal : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if (userName != "jack" || password != "123456")
{
throw new Exception("Username/Password is not correct");
}
}
}
<serviceCredentials>
<userNameAuthentication customUserNamePasswordValidatorType="WcfService1.CustUserNamePasswordVal,WcfService1" userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
Client.
//for validating the server certificate.
ServicePointManager.ServerCertificateValidationCallback += delegate
{
return true;
};
ServiceReference2.Service1Client client = new ServiceReference2.Service1Client();
client.ClientCredentials.UserName.UserName = "jack";
client.ClientCredentials.UserName.Password = "123456";
if we use the message security, we could set up the certificate by the following code.( Configure your actual certificate according to the actual situation)
<serviceCredentials>
<serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="869f82bd848519ff8f35cbb6b667b34274c8dcfe"/>
<userNameAuthentication customUserNamePasswordValidatorType="WcfService1.CustUserNamePasswordVal,WcfService1" userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
Refer to the below link.
WCF-TransportWithMessageCredential The HTTP request is unauthorized with client authentication scheme 'Anonymous'
WCF UserName & Password validation using wshttpbinding notworking
Feel free to let me know if there is anything I can help with.

Unable to access the WCF Service metadata when custom validator is introduced

I have a web service(using wsHttpBinding and SSL) developed in Visual Studio 2017. Whenever i introduce the following line, the Web Service just fails and it goes into the "faulted" state.
<authentication certificateValidationMode="Custom" customCertificateValidatorType="SampleProject.SampleService.AuthenticationCertificateValidator, SampleProject.SampleService"/>
The error message when attempting to "Add Service Reference" on the client side i recieve the following error:
There was an error downloading 'https://localhost/SampleService/service'.
The request failed with HTTP status 404: Not Found.
Metadata contains a reference that cannot be resolved:
'https://localhost/SampleService/service'.
There was no endpoint listening at https://localhost/SampleService/service
that could accept the message. This is often caused by an incorrect address
or SOAP action. See InnerException, if present, for more details.
The remote server returned an error: (404) Not Found.
If the service is defined in the current solution, try building the
solution and adding the service reference again.
Here is the code relating to the validator.
public class AuthenticationCertificateValidator : X509CertificateValidator
{
string allowedIssuerName;
public AuthenticationCertificateValidator(string allowedIssuerName)
{
if (allowedIssuerName == null)
{
throw new ArgumentNullException("allowedIssuerName");
}
this.allowedIssuerName = allowedIssuerName;
}
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
// Check that the certificate issuer matches the configured issuer.
if (allowedIssuerName != certificate.IssuerName.Name)
{
throw new SecurityTokenValidationException
("Certificate was not issued by a trusted issuer");
}
}
}
However the service works fine when i only have the "ChainTrust" line enabled as shown below:
<!--certificateValidationMode="Custom"
customCertificateValidatorType
="SampleProject.SampleService.AuthenticationCertificateValidator,
SampleProject.SampleService"/>-->
<authentication certificateValidationMode="ChainTrust" />
Ideally i want my service and client to use ChainTrust and also use the custom validator class if that's possible?
Therefore what am i doing wrong regarding configuration? Am i missing something from the config file?
Here is the full Service config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="SampleProject.SampleService.SampleService"
behaviorConfiguration="SampleService_Behavior">
<endpoint
address="https://localhost/SampleService/service"
binding="wsHttpBinding"
bindingConfiguration="SampleService_Binding"
contract="SampleProject.SampleService.ISampleService" />
<endpoint
address="https://localhost/SampleService/service/mex"
binding="mexHttpsBinding"
contract="IMetadataExchange" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="SampleService_Binding"
maxReceivedMessageSize="2147483647"
maxBufferPoolSize="2147483647" >
<readerQuotas
maxDepth="2147483647"
maxStringContentLength="2147483646"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647"/>
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" proxyCredentialType="None" realm="" />
<message clientCredentialType="Certificate" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SampleService_Behavior">
<!--Service metadata is needed for when you have an mex endpoint exposed-->
<serviceMetadata httpsGetEnabled="true" httpsGetUrl="https://localhost/SampleService/service/mex"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
<!--The serviceCredentials behavior defines a service certificate
which is used by the service to authenticate itself to its
clients and to provide message protection. -->
<serviceCredentials>
<serviceCertificate
findValue="SampleServer"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
<clientCertificate>
<!--<authentication certificateValidationMode="ChainTrust" />-->
<authentication
certificateValidationMode="Custom"
customCertificateValidatorType
="SampleProject.SampleService.AuthenticationCertificateValidator,
SampleProject.SampleService"/>
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehaviour">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
if someone could assist me that would be much appreciated.

WCF / wsHttpBinding / Message Security - BadTokenRequest

So got an older WCF service / client I'm working on. Added a new (static) logging system to it, actually and now doing some load testing.
Getting some really annoying sporadic issues now - claiming "Secure channel cannot be opened because security negotiation with the remote endpoint has failed". I noticed I get a CommunicationException with a fault name of Sender and subcode of BadContextToken.
Weird thing is, I'll get 2-4 correct responses, then a flurry of these exceptions, then start getting good responses again.
This is my first real foray into WCF, and not loving it so far :)
Service web.config:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="MyNamespace.MyService">
<endpoint address="" binding="wsHttpBinding" contract="MyNamespace.IMyService" bindingConfiguration="wsMessage">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="false" />
<serviceCredentials>
<serviceCertificate findValue="MyValue" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="MyNamespace.UserNamePassValidator, MyNamespace" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
And on the client side, the client is instantiated as such:
var binding = new WSHttpBinding();
binding.Name = "WSHttpBinding_IMyService";
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
var client = new MyService(binding, "http://myserver:8080/myapp/service.svc");
var endpointIdentity = new DnsEndpointIdentity("MyValue"); // Match the certificate name used by the server
client.Endpoint.Address = new EndpointAddress(new Uri("http://myserver:8080/myapp/service.svc"), endpointIdentity, client.Endpoint.Address.Headers);
var creds = client.ClientCredentials;
creds.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
creds.UserName.UserName = "myuser";
creds.UserName.Password = "mypassword";
string retVal = client.SendRequest(); // SendRequest == one of the methods on my IMyService, returns a string. This is also where I sporadically see my error when load testing.
I would appreciate any pointers to help me out with this WCF setup!
These might be useful additions to your web.config:
<behaviors>
<serviceBehaviors>
<behavior name="CalculatorServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="False" />
<serviceMetadata httpGetEnabled="True"/>
<serviceThrottling maxConcurrentCalls="20" maxConcurrentInstances="100"/>
</behavior>
</serviceBehaviors>
</behaviors>
<binding name="basicHttp" allowCookies="true" maxReceivedMessageSize="1048576" maxBufferSize="1048576" maxBufferPoolSize="1048576">
<readerQuotas maxDepth="32" maxArrayLength="1048576" maxStringContentLength="1048576"/>
</binding>
Usually this kind of "random" behaviour might depend on:
Timeouts (probably not your case, since you'd get a different exception)
Too many connections: if you client opens too many connections (and "forgets" to close them), you'll exceed the default allowed maximum (depending on context, it might be 10 connections).
You can act on this if you alter your web.config, editing maxConcurrentCalls and maxConcurrentInstances
Perhaps those errors are not random, but specific to some message; if so, that might be due to its size (i.e. it's too large): again, alter your web.config setting maxReceivedMessageSize, maxBufferSize, maxBufferPoolSize and readerQuotas
Of course you will get more info if you turn on WCF tracing.

BTS 2013 - The message has a bad message signature

I've a problem with BizTalk Server 2013 and a WCF Service. BizTalk needs to consume the WCF Service. BizTalk needs to sign the message with a X509 certificate and I receive the following error message:
There was a failure executing the send pipeline: "BizTalkUtilities.SignPipeline,
BizTalkUtilities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d749e81ab815db56" Source:
"MIME/SMIME encoder" Send Port: "SndPort_Sign_V2" URI: "http://XXXX/DemoServiceSigned
/DemoService.svc" Reason: The message has a bad message signature.
First I've created the service without security, everything works. Once I've setup my security (message security, Sign) it didn't work anymore. To be sure my service was fine, I've created a test WCF client which consumes the service with the security - no problem.
The message needs to be signed using a X509 certificate. All the certificates are in the correct place. I followed the info stated on MSDN.
Service config:
<bindings>
<wsHttpBinding>
<binding name="clientSignConfig">
<security mode="Message">
<message clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service name="SignServiceBL.DemoService" behaviorConfiguration="DemoServiceBehavior">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="clientSignConfig"
contract="SignServiceBL.IDemoService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DemoServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"/>
</clientCertificate>
<serviceCertificate findValue="CN=DemoServiceServerCertificate"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
Client config (this works for a WCF Client, but doesn't work in BizTalk)
<bindings>
<customBinding>
<binding name="demoService_CustomBinding">
<transactionFlow />
<security authenticationMode="SecureConversation" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10">
<secureConversationBootstrap authenticationMode="MutualSslNegotiated" messageSecurityVersion="WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10" />
</security>
<textMessageEncoding />
<httpTransport />
</binding>
</customBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="signingBehavior">
<clientCredentials>
<clientCertificate findValue="CN=DemoServiceSigning"
storeLocation="CurrentUser" storeName="My"/>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="LocalMachine"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://XXXX/DemoServiceSigned/DemoService.svc"
binding="customBinding" bindingConfiguration="demoService_CustomBinding" behaviorConfiguration="signingBehavior"
contract="DemoService.IDemoService" name="WSHttpBinding_IDemoService">
<identity>
<dns value="DemoServiceServerCertificate"/>
</identity>
</endpoint>
</client>
I've setup tracing, but BizTalk isn't even sending a message to my service. It's like the sendpipeline is blocking my request.
Any ideas?
EDIT
You don't need the pipeline with a MIME/SMIME encoder to sign WCF messages. You should use this pipeline if you need to sign emails... See the first sentence of MSDN
BizTalk Server supports signing outbound messages and signature verification for inbound Secure Multipurpose Internet Mail Extensions (S/MIME) messages
Once I remove the pipeline, BizTalk sends a message to the service. The problem now is that it's signed and encrypted. I am figuring out how to tell BizTalk to only sign the message. If you have any ideas, feel free to post them. If I find it, I will post it ;-)
It wasn't easy, but I was able to solve my issue :-)
I wrote a blogpost about it, because it's a bit to complicated to create an answer here.
So check it out!

How do I programatically assign WCF ClientCredentials ServiceCertificate property?

I have a WCF service being hosted over https with a self-signed certificate. I'm having trouble programatically creating the binding: specifically the portion of the endpoint behavior.
My Service config looks like this:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpsGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="DisableServiceCertificateValidation">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="None"
revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="ContactEmail.Web.EmailService.customBinding0">
<binaryMessageEncoding />
<httpsTransport/>
</binding>
</customBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
<services>
<service name="ContactEmail.Web.EmailService">
<endpoint address="https://xxxxxxxxxxxxxx/EmailService/EmailService.svc" binding="customBinding" bindingConfiguration="ContactEmail.Web.EmailService.customBinding0" contract="ContactEmail.Web.EmailService" behaviorConfiguration="DisableServiceCertificateValidation" />
<endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
And when I use the "Add Service Reference" feature, the generated client works as expected. Given that I call set up a Cert Validation Callback like this:
System.Net.ServicePointManager.ServerCertificateValidationCallback = ((sender, certificate, chain, sslPolicyErrors) => true);
However, rather than feed the service configuration through a config file on the client, I need to set it programmatically, because the call will be part of a commonly shared library. So, I'm trying to do this by providing my own parameters to the client constructor like:
var myClient = new EmailServiceClient(GetBinding(), new EndpointAddress(Strings.EmailServiceEndpointAddress));
In GetBinding(), I create CustomBinding with BindingElements like HttpsTransportBindingElement, BinaryMessageEncodingBindingElement and SecurityBindingElement.CreateSecureConversationBindingElement(SecurityBindingElement.CreateUserNameOverTransportBindingElement()).
Do you know how I can specify things like certificateValidationMode="None" and revocationMode="NoCheck" or if I'm doing anything wrong?
SecureConversation is implementation of WS-SecureConversation => advanced message level security where special security token is created during first call to the service (authenticated by the message security mode passed as parameter to the binding element creation) and this token is used to secure subsequent messages. This security also forms something know as security context or security session.
Your current binding in config file is not using SecureConversation so your binding defined in code is not compatible with your service.
You should have a Credentials property (of type ClientCredentials) (http://msdn.microsoft.com/en-us/library/ms733836.aspx) on your ClientBase (EmailServiceClient)...and that should have a ServiceCertificate property:
http://msdn.microsoft.com/en-us/library/system.servicemodel.description.clientcredentials.servicecertificate.aspx

Categories