Incorrect Key for decrypting web service response - c#

I am working on a WCF client to consume a third party web service over which I have no control. It works with a custom binding and WS Security. No app.config, all through code. I can successfully send requests and receive responses. However, it seems .Net cannot decrypt the service responses, so I have to do it manually. I have implemented a custom encoder and overriden the ReadMessage method. I have access to the raw SOAP response. I have seen code in MSDN as well as a blog where they explain how to decrypt the response. I read the oasis specifications for the response xml schema. The response contains a reference to the x509 certificate that has the private key necessary to decrypt the session key, so then the body can be decrypted. According to the documentation of the service I am trying to consume, and pretty much everywhere I've read, I should use the private key of the certificate I used to sign my request, but I get an Exception saying the key is incorrect. I then tried every possible certificate with a private key in all my certificate stores to see if one of them would successfully decrypt the message but all of them failed. If I understand it right, this means the service expects me to decrypt the message with a private key I don't have. I'm rather new to WCF and web services themselves, so I might be missing something.
Do you know what could be happening? Or maybe I am understanding something wrong. Any help will be greatly appreciated.
Thanks

Related

WCF Client to WSE 3.0 service Exception: CWWSS7310E: XML encryption information[.....]

I have never worked with soap services before, so I might have done something wrong. I have generated a service client reference for the service through it's wsdl with "Svcutil".
I have followed this guide https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-wcf-client-to-interoperate-with-wse3-0-services and set up the custom binding.
After that I a client from the reference and supply a new binding that is using WseSecurityAssertion.MutualCertificate10 and the service endpoint address.
I then add a certificate and add theese credentails to the service client:
clientProxy.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(string.Concat(xxx, yyy), GetCertificatePassword(xxx), PersistKeySet);
clientProxy.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(xxx, "", PersistKeySet);
clientProxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = ChainTrust;
clientProxy.ClientCredentials.ServiceCertificate.Authentication.RevocationMode = NoCheck;
This is code that have worked before (but before using wcf and "Svcutil") and I have mostly copied it, but refactored it a bit.
When I call the Web Service I get this error:
System.ServiceModel.FaultException: 'CWWSS5511E: An exception occurred during the decryption of a message. The exception is CWWSS7310E: XML encryption information exists in the security header, however an inbound XML encryption configuration is not present.'
I understand that I encrypt something that I shouldn't and when I compare the request I sent with the old code to the request I send now I can see that this is added in the securityheader:
<e:EncryptedKey Id="_0" xmlns:e="http://www.w3.org/2001/04/xmlenc#"><e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" xmlns="http://www.w3.org/2000/09/xmldsig#"/></e:EncryptionMethod><KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
And some info about the key.
I'm wondering what it is I do wrong that the code didn't do before. I can't find any config files so I don't think it's some configuration I have missed. Where might this encryption be set? Is it inside the binding or is it where I set clientCredentials?
So after alot of reading and comparing I finaly figured out that I did not set
ProtectionLevel to System.Net.Security.ProtectionLevel.Sign in the new generation of the service reference file. this was probably hardcoded there in the old ones instead of using a config file to set the ProtectionLevel.
This is what caused the service on the service side to not understand how to decrypt it correctly.

WCF Protectionlevel, why is there no 'encryptOnly'?

I'm attempting to make a client that uses WCF to communicate with a SOAP endpoint made in Java. The service requires me to send my PKCS10 request inside a encrypted SOAP request, using a X509 certificate that I have received from the service using another function, but I can't figure out how to configure WCF properly to allow me to only encrypt but not sign, seeing as I have yet to receive my final certificate from the service.
I've tried to set the X509 certificate I've received from the server as both DefaultCertificate for the service and the ClientCertificate, but no matter what kind of options I set for the binding and endpoint, I always end up with the error "The private key is not present in the X.509 certificate" and that's because (I assume) there are only the following ProtectionLevels in WCF:
None
Sign
EncryptAndSign
I understand the error here because obviously I haven't received the service's private key and setting the service's certificate as the ClientCertificate I would expect this error, but is it me who has misunderstood something here?
Shouldn't it be possible for me to just encrypt the SOAP envelope using the service's public key that I've already received, without having to sign it as well with my own private key (which I haven't actually received yet)?

Encrypting SOAP messages when using HttpWebRequest and soap message as string

I have implemented a SOAP client based on the code in this thread Client to send SOAP request and received response however I would now like to extend this to allow us to encrypt the soap message using X509 certs and tripleDes and wondered if there was a starting point. the output payload i am looking for will need to include an xml segment based on schema http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd and probably also include headers, anybody have any links to behind the scenes with soap encryption.
I have found this Creating Signed SOAP Message as a String with C# aqrticle which seems to be having a similiar issue, where is the theory behind creating the hash values for soap signing.
Bit late to my own funeral but it appears the solution is here:
Creating Signed SOAP Message as a String with C#

WCF Using X509 Private key for outgoing messages

So, here is my million dollar question. I want to consume a service hosted by a third party, and therefore for the set up we exchanged X509 certificates. I sent them ours and we got theirs. I added their self signed certificate in the certificate store. Now, I have tried to connect to the services with soapUI, where i need to create a JKS file with my private key to connect, and use the WSSE headers for username, password, nonce and TTL and it works just fine.
But, I want to write a WCF c# client to communicate with the service, and adding my certificate to the client credentials in the config or through code does not work. Can someone please let me know how to use the private key for out going messages using WCF?
I have tried both these things, but not sure where am i going wrong...
proxy.ClientCredentials.ClientCertificate.Certificate = new X509Certificate2(#"C:\soapUI\soapUI\Agency1\certificates\myprivatekey.pfx", "Pwd");
proxy.ClientCredentials.ServiceCertificate.DefaultCertificate = new X509Certificate2(#"C:\soapUI\soapUI\Agency1\certificates\myprivatekey.pfx", "Pwd");
i have also added the correct wsu and wsse headers to the soap envelope. When i take the soap envelope from the WCF client to SOAPUI, it works, but not from WCF itself. So i am pretty sure its the difference in how the private keys are being used. So any line of thought will be helpful.
In this article, we will start with transport and message security understanding. We will then see simple code samples of how to implement transport and message security using WsHTTP bindings. We will also see the differences between ‘BasicHttpBinding’ and ‘WsHttpBinding’ with the help of a simple code. WCF security is a huge topic by itself, but I am sure with this article you will get a quick start of how to go about WCF security.
http://www.codeproject.com/Articles/36732/WCF-FAQ-Part-3-10-security-related-FAQ

PayPal API Certificate

Ok, I've never seen this ever when coding againts and sending 3rd party SOAP API calls but looks like PayPal requires their bigger clients to use the X509 certificate in order to send API calls rather than just sending over a standard API signature like most APIs require you to do.
Am I the only one who thinks this is kinda strange or not stadnard?
http://en.wikipedia.org/wiki/X.509
I don't get how this relates to an API call. I see an example code that they gave me in C# implementing the ICertificatePolicy interface in .NET...but it's just foreign to me and how this relates to the fact that they still give you an API signature too in the PayPal sandbox regardless. So why would I need to read a physical file Certificate AND use an API Signature? I guess I don't see the link between the Certificate and the PayPal SOAP API.
This is a common thing among larger names when dealing with connections that demand a more secure "handshake" and thats all it is used for.
This file is made from a Root Certificate and usually a .pem, .p12, .pfx here is an example using python and cURL, it is very simple to do and if you have any trouble with the X.509 file, I would get in contact with whoever you buy your root certificate from or just search google on how to export the file you need ( I personally always end up with a .p12 file ).
Here is the python code
c = pycurl.Curl()
c.setopt(pycurl.URL, FirstDataAPI_URL)
c.setopt(pycurl.HTTPHEADER, ["Accept:"])
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.POSTFIELDS, urllib.urlencode(FirstDataAPI_PostData))
b = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, b.write)
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(pycurl.MAXREDIRS, 5)
#c.setopt(pycurl.SSLCERT, '/home/***/***/***/ssl/digitalID.p12')
c.setopt(pycurl.SSLCERT, '/home/***/***/***/ssl/productionDigitalId.p12')
c.setopt(pycurl.SSLCERTTYPE, 'p12')
c.setopt(pycurl.SSLCERTPASSWD, '******')
c.perform()
For use with SOAP I would look for a setting that allows you to set a Certificate file and you will be set.
Just as a side note, this just goes to show that Paypal has not updated their API in quite a few years ... most API's I work on that require a X509 cert are extremely outdated and I haven't seen this used in an API that was writing in the last 2 years.
You're dealing with people's money, and while I'm unaware of the specifics on how the certificate's work, basically it's ensuring that payments sent from your application are more secure.
A simple API key would be easier to spoof, and allow fraud more easily I assume.

Categories