Unable to create a client with separate X.509 cetificates for message and transport security
- Dominant language
- C#
- Stars
- 1.8k
- Forks
- 576
- Avg merge
- 6d 9h
- Merged PRs (30d)
- 2
Description
I am unable to migrate a .NET Framework 4.8 WCF client to .NET Core (or .NET 5+) because the service expects two different certificates for transport and message security. Our current implementation uses a custom `System.ServiceModel.ClientCredentialsSecurityTokenManager` implementation and returns a different `System.IdentityModel.Selectors.X509SecurityTokenProvider` depending on whether the token requirement has the security binding element property.
```c#
internal class ClientCredentialsSecurityTokenManager : System.ServiceModel.ClientCredentialsSecurityTokenManager
{
private readonly ClientCertificateCredentials custCreds;
public ClientCredentialsSecurityTokenManager(ClientCertificateCredentials CustCreds)
: base(CustCreds)
{
custCreds = CustCreds;
}
public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
if (tokenRequirement.TokenType != SecurityTokenTypes.X509Certificate)
return base.CreateSecurityTokenProvider(tokenRequirement);
TransportSecurityBindingElement secBE = null;
if (tokenRequirement.Properties.TryGetValue(
ServiceModelSecurityTokenRequirement.SecurityBindingElementProperty, out var temp))
{
new X509SecurityTokenProvider(custCreds.ClientSigningCert);
}
return new X509SecurityTokenProvider(custCreds.ClientAuthCert);
}
}
```
However, the `X509SecurityTokenProvider` class [doesn't appear to be publicly exposed after .NET Framework 4.x](https://learn.microsoft.com/en-us/dotnet/api/system.identitymodel.selectors.x509securitytokenprovider?view=netframework-4.8.1&viewFallbackFrom=netstandard-2.0).
The method we are using is described in the following posts:
- https://learn.microsoft.com/en-us/dotnet/framework/wcf/extending/how-to-use-separate-x-509-certificates-for-signing-and-encryption#to-use-separate-certificates-for-signing-and-encryption
- https://blogesh.wordpress.com/2009/10/08/separate-certificates-for-transport-and-message-security-in-wcf/
I haven't been able to find any other way to achieve what we need. We also have no control over the service, so we can't change the requirement for two separate certificates.
**To Reproduce**
Steps to reproduce the behavior:
1. Create a class inheriting from `System.ServiceModel.ClientCredentialsSecurityTokenManager`.
2. Override `SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)` method.
3. Try to return a new `System.IdentityModel.Selectors.X509SecurityTokenProvider`.
4. The `X509SecurityTokenProvider` type won't resolve, and there seems to be no other way to return separate certificates for message and transport security.
**Expected behavior**
I can return different certificate token providers for transport and message security.
**Additional context**
Here's the code for the custom `System.ServiceModel.Description.ClientCredentials` we are using:
```c#
internal class ClientCertificateCredentials : ClientCredentials
{
public X509Certificate2 ClientAuthCert { get; set; }
public X509Certificate2 ClientSigningCert { get; set; }
public ClientCertificateCredentials(ClientCertificateCredentials other)
: base(other)
{
ClientSigningCert = other.ClientSigningCert;
ClientAuthCert = other.ClientAuthCert;
}
public ClientCertificateCredentials(X509Certificate2 ClientAuthCert, X509Certificate2 ClientSigningCert)
{
this.ClientAuthCert = ClientAuthCert;
this.ClientSigningCert = ClientSigningCert;
}
protected override ClientCredentials CloneCore()
{
return new ClientCertificateCredentials(this);
}
public override SecurityTokenManager CreateSecurityTokenManager()
{
return new ClientCredentialsSecurityTokenManager(this);
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.