Pergunta

I am currently trying to call an API that requires me to put XML data in a PKCS#7 format.
This data is posted to the API end point.
The response also comes in a form of a PKCS#7 cryptographic messages (MIME-type is application/pkcs7-mime).
Some Notes they provide: A cryptographic message doesn't contain any certification chains. Data compression is not used. Data encryption is not used. A cryptographic message is in the OpenSSL PEM format.

I have been supplied two certificates. One I created the request for and have the private key, the other supplied to me by the service provider.
I have managed to successfully install these certificates, and can communicate with the service.

I am seemingly sending data to this API service successfully.
Now I'm trying to make sense of the response I'm receiving from this API.
This response looks like this

-----BEGIN PKCS7-----
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
WISGCSqGSIb3DQEHSqCSWISCSQExCzSJBgUrDgWCGgUSWISGCSqGSIb3DQEHSSCS
AfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsdfdAfsdFAD3433423ASfdsd
-----END PKCS7-----

(I jumbled up the contents on the off chance there's anything sensitive in there)

With this response i need to

  1. Verify the digital signature to ensure that response was sent by the provider
  2. Get an Xml formatted message from this response

I have been primarily using the Bouncy Castle library and the MS SignedCms Class
In summary, I am getting absolutely nowhere.

Please can someone guide me on what to do here as I've been at this for about 5 days and am going nowhere fast.

Here is some of what I'm doing so far:

Make the request

Using the HttpWebRequest and HttpWebResponse i am posting data to the service using my supplied certificate

var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2 cert = store.Certificates.Find(X509FindType.FindByThumbprint, "ACLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLK", false)[0];

HttpWebRequest request = null;
var uri = new Uri(endPointUri);
request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/pkcs7-mime";
request.ContentLength = requestString.Length;
request.ClientCertificates.Add(cert);

using (Stream writeStream = request.GetRequestStream())
{
    var encoding = new UTF8Encoding();
    byte[] bytes = encoding.GetBytes(requestString);
    writeStream.Write(bytes, 0, bytes.Length);
}
string result = null;
using (var response = (HttpWebResponse) request.GetResponse())
{
    using (Stream responseStream = response.GetResponseStream())
    {
        if (responseStream != null)
        {
            using (var readStream = new StreamReader(responseStream, Encoding.UTF8))
            {
                result = readStream.ReadToEnd();
            }
        }
    }
}

return result;

Here I get back the "BEGIN PKCS7" message from above.
Now I'm trying to figure out what to do with this

MS Signed CMS Class Approach

SignedCms signedCms = new SignedCms();
signedCms.Decode(Encoding.Default.GetBytes(resultString));
try
{
    signedCms.CheckSignature(new X509Certificate2Collection(cert1), true);
}
catch (System.Security.Cryptography.CryptographicException e)
{
    _Log.Error(e.Message)
}

This throws the exception on "signedCms.Decode" of "ASN1 bad tag value met."

BouncyCastle ISigner

Here the documentation is non-existent.
So first I save my response to a file and use the TextReader object to try test with BouncyCastle

using (TextReader reader = File.OpenText(@"c:\temp\resultString.txt"))
{
    PemReader pemRd = new PemReader(reader);
    ContentInfo d = (ContentInfo)pemRd.ReadObject();
    Console.WriteLine(d.ContentType.ToString());
}

This returns the result: "1.2.840.113549.1.7.2"
From what i can tell, this means its "Pkcs7 Signed Data"
Woohoo, something looks like its working.
But from here, how do I verify, and how do I extract any information from this

My Verify attempt

using (TextReader reader = File.OpenText(@"c:\temp\resultString.txt"))
{
    PemReader pemRd = new PemReader(reader);
    var signature = new CmsSignedData(pemRd.ReadObject());
}

Fail - signature is null

var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2 cert = store.Certificates.Find(X509FindType.FindByThumbprint, "ACLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLKJCLK", false)[0]; //tried with both certs
ISigner signer = SignerUtilities.GetSigner("RSA");
var bouncyx509 = DotNetUtilities.FromX509Certificate(cert1);
signer.Init(true, DotNetUtilities.FromX509Certificate(cert1).GetPublicKey());

Fail - need private key to create signer

In Closing

I hope I have provided enough information to get some help here.
Maybe I'm heading in completely the wrong direction.

My Questions are:

  1. How do I Verify the digital signature?
  2. How do I get an Xml formatted message from this response?

THE SOLUTION

Thanks to gtrig, i finally have a solution.
Using the MS SignedCms object I had to first remove the Header and Footer form the message, then Convert.FromBase64String

Working Solution

SignedCms signedCms = new SignedCms();
resultString = resultString.Replace("\n", "").Replace("-----BEGIN PKCS7-----", "").Replace("-----END PKCS7-----", "");
signedCms.Decode(Convert.FromBase64String(resultString));

Now signedCms.ContentInfo.Content contains the reponse Xml message I expect

Foi útil?

Solução

This is an incomplete answer, but it may get you a little further along.

If you have access to openssl, try this command to see if it can read the data:

openssl pkcs7 -in resultString.txt -text

After that try this in your code (The only difference from what you had is "Content" instead of "ContentType":

Console.WriteLine(d.Content.ToString());

signedCms.Decode() takes a byte array, and that is probably the DER formatted message instead of the PEM formatted message that you received in the response. To get that in a byte array, you'll have to strip the header and footer (Begin/End) lines and pass the rest to this method:

Convert.FromBase64String()

Alternatively, you could use openssl to convert the file to DER format and then read in the bytes directly from the file.

openssl pkcs7 -in resultString.txt -outform DER -out result.der

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top