I have a client for an older service that I am trying to migrate to WCF.
The service is hand written in assembler on *nix.
The client is written in WSE3 in C++.
The WSDL, of course does not supply security specs, but I have an interface doc.
- The service supplies us with one certificate for the server with only a public key. The WSE3 client is using that one certificate to sign the security header and the message body as well as encrypting them both.
- WCF is balking hard at this and wants a private key.
The security header is based on
WS-Security 1.0
.
I need a
UsernameToken
.I have tried multiple different approaches. The
app.config
withBasicHTTPBinding
which is what Service import left me with andWSHttpBinding
.Because this is a COM DLL that we deploy to clients, I moved away from the config route and started directly coding the binding.
There are some good posts and even some answers here in SO from Yaron Naveh that I have been working with that use
AsymetricSecurityBinding
that feels like the right approach, but eventually I end up with a 'The private key is not present in the X.509 certificate.' message.
This is my current approach, modified for presentation:
CustomBinding b = new CustomBinding();
var profileEnum = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
var sec = (AsymmetricSecurityBindingElement)SecurityBindingElement.CreateMutualCertificateBindingElement( profileEnum );
sec.EndpointSupportingTokenParameters.Signed.Add( new UserNameSecurityTokenParameters() );
sec.MessageSecurityVersion = MessageSecurityVersion.WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
sec.IncludeTimestamp = false;
sec.MessageProtectionOrder = MessageProtectionOrder.EncryptBeforeSign;
b.Elements.Add( sec );
b.Elements.Add( new TextMessageEncodingBindingElement( MessageVersion.Soap11, Encoding.UTF8 ) );
b.Elements.Add( new HttpsTransportBindingElement() );
EndpointAddress addr = new EndpointAddress(
new Uri(URL),
new DnsEndpointIdentity( "yada.yada.com" ),
new AddressHeaderCollection()
);
client = new AWebService.SomeServiceClient( b, addr );
String credName = "my.hot.site.com";
client.ClientCredentials.ClientCertificate.SetCertificate(
StoreLocation.LocalMachine,
StoreName.Root,
X509FindType.FindBySubjectName,
credName
);
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(
StoreLocation.LocalMachine,
StoreName.Root,
X509FindType.FindBySubjectName,
credName
);
client.Endpoint.Contract.ProtectionLevel = ProtectionLevel.Sign;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
client.ClientCredentials.UserName.UserName = "samuser";
client.ClientCredentials.UserName.Password = "iampass";
client.Endpoint.EndpointBehaviors.Add( new ClientMessageInspectorBehavior() );
response = client.call(requestData);
What I need is
- A setup that will get me a WSSE Security header with a
UserNameToken
and - A way to sign and encrypt the outgoing request as well as check the response signature.