How to generate BinarySecurityToken (X509PKIPathv1) from .p12 file - c#

I am trying to consume a Java web service from a C# client. The service requires BinarySecurityToken element with value type X509PKIPathv1.
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1">
MIIH......
</wsse:BinarySecurityToken>
Since WCF does not support X509PKIPathv1 value type, I am generating the SOAP message by hand, signing it using the SignedXml class, encrypting it using the EncryptedXml and sending it using the WebClient class. As for the value of BinarySecurityToken element, I used the value generated in SoapUI for the same certificate, and it works.
But, I would like to be able to generate this value programmatically from .p12 file, and not having to paste it from SoapUI again every time when the certificate expires.
The WS-Security documentation is a bit vague, so I am not sure how to go about it. This is all the information it gives about this token type:
#X509PKIPathv1: An ordered list of X.509 certificates packaged in a PKIPath
How to generate this value from .p12 file in C#? SoapUI does it somehow.

So this may not be a fully solution to your problem but it may help you out somewhat.
This:
#X509PKIPathv1: An ordered list of X.509 certificates packaged in a PKIPath
means is a asn1 sequence or chain of certificates that you have used to sign your message. You can even see it here.
To give some context asn1 is way of representing data in way independent of the machine you are using. This data is binary and not human readable so you transform it to bade 64 and that is what you see in that field.
I am not entirely sure what the exact content of your .p12 file is but at the very least I assume it has the certificate of the private key you used to sign your message and maybe the chain until the publicly trusted certificate or CA.
I am mostly a C++ developer and I know openssl provides a C like api to read a certificate manipulate the underlying asn1 structure and the output it as a string.
Sorry for not providing with a greater level of detail or a code example

Related

How to make WCF Client to suit specific WS-Security

I try to implement WCF Client (C#) to consume a specific web service from NEXI. Service required a WS-Security (signature & encryption) and client authentication.
In documentation specific standards.
WS-Security Spec.
In accordance with the WS-Interoperability Basic Profile 2.0 the Secure WebServices Interface uses SOAP 1.1 with an HTTP Binding and specifies additional requirements.
1.Hashing algorithm must be SHA256
2.Signature Algorithm must be RSAWithSHA1
3.Encryption Algorithm must be AES256
4.Certificates used MUST have a key length of 2048 bits
5.Certificates used MUST have been generated using only SHA-256 as a hashing algorithm
6.Certificates used for signature and encryption MUST be issued by known Certificate Authority
7.Certificates needs to be exchanged between parties
8.Parties have to manage multiple certificate for the same purpose (signature and/or encryption) to overcome any gap when certificate renewal occurs. Parties have to exchange renewed certificate at least 30 days before current certificate expires.
9.All SOAP messages MUST be serialized using UTF-8 character encoding of the Unicode character set
10.Use SOAP Request-Response Message Exchange Pattern as specified in SOAP 1.1 (see http://www.w3.org/TR/2000/NOTE-SOAP-20000508/)
11.A correctly processed client request MUST be answered with a server response, consisting of a HTTP response with a 200 Status Code containing a soap:Envelope element
12.The soap:Envelope element MUST contain a soap:Header child element
13.The soap:Body element MUST contain exactly one, namespace-qualified child element
14.The soap:Body element MUST have a wsu:ID attribute with a unique value that enables it to be included in the signature and encrypted
15.Encription Key must be encrypted and included in soap:Header “xenc:EncryptedKey”
16.The wsse:Security element in request messages MUST contain exactly one wsu:Timestamp
17.SignedParts and EncryptedParts:
a.SignedParts: wsu:Timestamp (the request timestamp)
b.EncryptedParts: Body.
I am looking for a solution or help to setup all this requirements to single request.
I tried the implementation in SOAPUI but I am not able to meet all the requirements. I also tried to create a WCF client in .NET. but I am not able to set individual namespaces and I don't know how to create a request that meets all the requirements.
Expectations:
The request according the documentation should look like:
Request:
Request
Response:
Response

Create SAML SLO request

As a service provider (SP), i'm trying to create request for SLO using the URL redirect flow. After going through a lot of articles, this is what i came up with:
Create a logout request xml and digitally sign it
Convert the request xml to base64 url encoded string
Append the base64 encoded request xml to the SLO url as a querystring
Redirect page to the above constructed url (IDP)
IDP will then perform necessary SLO steps for all SPs at its end and
redirect back to our current application (which initiated the SLO
request)
Parse above response and show message in UI accordingly
However, when i got into the actual implementation, i'm faced with the following challenges, some of them not specific to SAML SLO.
To digitally sign the logout request xml, is it mandatory to
load/import the x509 certificate from .pfx file or can i use any
certificate from the certificate store which has private key?
For demo purpose, I've successfully signed the request using a certificate in my local system which has private key. This process appends the signature and pulic key information in the logout request xml.
I've encoded (Base64Url) the request xml but the resulting string length is too long (more than 4k chars), which would exceed the maximum length allowed in URL/GET request. Have i got this step wrong?
None of the articles/SAML spec mentions how the querystring should look like. Is the querystring parameter name defined by the SAML spec (which i could have missed) or is it dependent on the IDP?
All in all, i feel that SAML spec lacks articles with proper implementation which is making it extremely difficult to get the hang of it.
Note: I didn't include any of the codes i've written so far since my questions can be answered without them. However, if required, i can include them.
Few of the many referenced articles:
SSO, SAML and SLO
SAML Logout Request (SP -> IdP)
Sign XmlDocument with X509Certificate2 and Verify in C#
I would strongly suggest using an existing SAML library instead of rolling your own.
Some of these are free and you can examine the source code to see how to do it.
Or alternatively just use the stack itself!

Incorrect Key for decrypting web service response

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

X509Certificate and .NET Compact Framework 3.5

I am trying to implement HTTP communication authenticated by client certificate. When sending an HTTP request on "normal" (i.e. not Compact) .NET Framework, it's quite simple:
HttpWebRequest request = ...;
string certificatePath = ...;
string certificatePassword = ...;
request.ClientCertificates.Add(
new X509Certificate(certificatePath, certificatePassword));
However, on Compact Framework 3.5, X509Certificate has only one constructor which accepts byte array and nothing else. I suppose that I should read a certificate file and pass its contents into that byte array, but what about the password? How should I specify it on Compact Framework?
I did not find any way to use X509Certificate and password.
In the end, I've decided to use X509Store and grab certificates from there. This will make deployment a bit more difficult then originally anticipated, but at least it's doable :)
I'm two years late, but I stumbled across this question in my own research.
If you look closely at the documentation's example code, you see that you have to first open the PFX file and then export it before creating another instance of the X509Certificate class.
The way I understood this is as follows: the full .NET Framework API (i.e., on the desktop) takes a password parameter for the class' constructor as an overload. So, using the full framework, you export the certificate's raw data (i.e., without the securing password) using the Export method and then store the resulting byte array into a file. Afterward, you transfer that file to the mobile device, read the file into a byte array and pass that to the X509Certificate constructor on the Compact Framework.
Of course, this is the "raw" way of going about the problem. One has to then take care to secure the data being transferred in some way.
On further reading, exporting the PFX file in this way does not include the private key, though.

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