使用.pfx证书封装,签名和创建PKCS#7 DER消息

时间:2014-05-29 13:52:05

标签: c# ssl-certificate digital-signature certificate pkcs#7

我的任务是创建以PKCS#7 version 1.5 (RFC 2315) DER (ITU-T Recommendation X.690)格式进行数字签名的数据 - 基本为ANSI.1 X.509 signature

该消息必须满足以下条件:

  • 必须是signedData
  • 类型
  • 必须包含签名数据
  • 必须包含签名者证书
  • 必须包含一个数字签名

我的代码正在关注

static void Main(string[] args)
{

    string pfx = @"C:\Users\marek\Downloads\mfcr\marek-pfx.pfx";
    string xml = @"C:\Users\marek\Downloads\mfcr\souhr20141.xml";
    X509Certificate2 cert = new X509Certificate2(pfx, "thepass");

    byte[] publicBytes = cert.RawData;

    //var f = new FileStream(xml, System.IO.FileMode.Open);
    var fileContent = System.IO.File.ReadAllBytes(xml);

    char[] cArray = System.Text.Encoding.ASCII.GetString(fileContent).ToCharArray();
    RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;

    byte[] signedData = rsa.SignData(new System.Text.UTF8Encoding().GetBytes(cArray), new SHA1CryptoServiceProvider());

    RSACryptoServiceProvider rsa2 = (RSACryptoServiceProvider)new X509Certificate2(publicBytes).PublicKey.Key;

    var dataGenerator = new CmsEnvelopedDataStreamGenerator();
    bool verified = rsa2.VerifyData(new System.Text.UTF8Encoding().GetBytes(cArray), new SHA1CryptoServiceProvider(), signedData);

    File.WriteAllBytes(@"C:\Users\marek\Downloads\mfcr\Foo.p7b", signedData);
 }

我发送WebService的{​​{1}}响应:文件不是PKCS7(DER)的预期格式。

此代码用于发送Foo.p7b

HttpWebRequest

我在这个问题上挣扎了近5天 - 我肯定不是数字签名或证书的专家。

从我到目前为止所学到的 - 创建我应该做的信息:

  1. 使用我的static void Main(string[] args) { try { string fileName = (@"C:\Users\marek\Downloads\mfcr\Foo.p7b"); WebResponse rsp = null; HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://adisepo.mfcr.cz/adistc/epo_podani"); request.ClientCertificates.Add(new X509Certificate(pfx,"thepass")); request.Method = "POST"; request.ContentType = "application/pkcs7-signature"; request.Credentials = CredentialCache.DefaultNetworkCredentials; var encoder = new UTF8Encoding(); var reqStream = request.GetRequestStream(); StreamWriter writer = new StreamWriter(request.GetRequestStream()); // Write the XML text into the stream writer.WriteLine(GetTextFromXMLFile(fileName)); writer.Close(); reqStream.Close(); rsp = request.GetResponse(); StreamReader sr = new StreamReader(rsp.GetResponseStream()); string result = sr.ReadToEnd(); sr.Close(); Console.Write("\n příkaz odeslán \n"); Console.Write(result); Console.ReadLine(); Console.Read(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); Console.ReadLine(); } } private static string GetTextFromXMLFile(string file) { StreamReader reader = new StreamReader(file); string ret = reader.ReadToEnd(); reader.Close(); return ret; } }
  2. xml进行签名
  3. 使用我的private key
  4. 封印的信封

    但收件人如何检查我是否是真正的发件人?我应该在我的证书中添加public key参数吗?或者第2步 - 包含信息就足以让他检查一下?

    感谢大家的时间和回复。

2 个答案:

答案 0 :(得分:9)

您的代码尝试以数字方式对XML的字节表示进行签名,但在签名之前签署XML需要更多处理。例如,XML需要规范化(或者签名消息可以注入无符号数据),并且封装签名有一种特殊格式。我不知道Danovy Portal使用的实际方法是什么,但如果它使用标准方式,您可以按照下面的链接并签署您的数据。

MSDN: How to: Sign XML Documents with Digital Signatures

How enveloped signatures look

仅供参考(不要以为你真的需要读这个) W3C Xml Signature specification

编辑:发送pkcs#7消息更改代码。生成时

        ContentInfo contentInfo = new ContentInfo(new System.Text.UTF8Encoding().GetBytes(cArray));
        SignedCms cms = new SignedCms (contentInfo);
        CmsSigner signer = new CmsSigner (cert);
        cms.ComputeSignature (signer);
        byte[] pkcs7=cms.Encode ();
        File.WriteAllBytes(@"../../Foo.p7b", pkcs7);

发送时:

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("https://adisepo.mfcr.cz/adistc/epo_podani");
            //we don't need to add certificate to POST
    //      request.ClientCertificates.Add(new X509Certificate(pfx,"test"));
            request.Method = "POST";
            request.ContentType = "application/pkcs7-signature";
            request.Credentials = CredentialCache.DefaultNetworkCredentials;
            var encoder = new UTF8Encoding();
            using (var reqStream = request.GetRequestStream())
            {
                // Write pkcs#7 into the stream
                byte[] pkcs = File.ReadAllBytes(@"../../Foo.p7b");
                reqStream.Write(pkcs, 0, pkcs.Length);
            }
            rsp = request.GetResponse();

答案 1 :(得分:0)

看看BouncyCastle - 它拥有你所需要的一切:

http://www.bouncycastle.org/csharp/