【问题标题】:Verify detached signature (*.p7s files) and X509Certificate2验证分离的签名(*.p7s 文件)和 X509Certificate2
【发布时间】:2012-08-27 17:56:58
【问题描述】:

我在我的方法中收到一个 XML 文档作为字符串参数。 XML 文档是:

<Document>
    <ZipContainer> Zip_File_In_Base64 </ZipContainer>
    <X509Certificate> Certificate_In_Base64 </X509Certificate>
</Document>

我从这个字符串中提取 base64 格式的 ZIP 文件和 base64 格式的 X509Certificate2 证书。 ZIP 文件包含:

  • 将 ZIP 文件内容描述为 XML 的文件(文件 packageDescription.xml);

  • 包含传输文档内容的文件(例如,*.doc 文件);

  • 具有分离数字签名内容的文件(*.p7s 文件 - 分离数字签名);

应该从存档中提取签名文件的签名(分离的数字签名可能不止一个)。分离的数字签名存储在扩展名为.p7s 的文件中。必须完成每个签名以检查其与用户登录门户的数字签名是否一致。

必须包括两个步骤:

  1. 参见方法certificateValidator()(参见下面的这个方法):这是一个分离的签名,包含在.p7s 文件中,并带有相应的签名文件,这些 *. P7s 文件。
    例如:一对相关文件:ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s
    ZayavUL_3594c921f545406d9b8734bbe28bf894.doc

  2. 参见方法 certificateValidator():这会使用从 XML 文档输入字符串中提取的证书验证文件 .p7s 中的证书。

问题

  1. 方法signatureValidator(参见下面的方法)当前未使用文件.p7s的分离签名。我确实尝试过,但没有成功。如何正确验证.p7s文件对应文件的分离签名?

  2. 在方法certificateValidator(参见下面的方法)中,如何验证从.p7s文件中提取的证书与从Base64格式的输入字符串中提取的证书的一致性?

  3. 代码行foreach (X509Certificate2 x509 in signCms.Certificates) { } ---> 证书集合始终为空。为什么?

输入参数

  • Dictionary &lt;string, byte[]&gt; dictP7SFiles(key - 文件名*.p7s,value - 字节数组,代表*.p7s文件)

  • Dictionary &lt;string, byte[]&gt; dictNotP7SFiles(key - 使用 *.p7s 文件的分离签名签名的文件的名称,value - 字节数组,代表文件)

  • X509Certificate2 userCertX509 - 证书对象,从输入 xml 文档中提取(格式为 Base64)

代码

下面是验证步骤的测试实现(见上面这两个步骤):

private bool certificateValidator(Dictionary<string, byte[]> dictP7SFiles, 
    Dictionary<string, byte[]> dictNotP7SFiles, X509Certificate2 userCertX509)
{
  bool isValid = false;           
  try
  {               
    foreach (KeyValuePair<string, byte[]> pair in dictP7SFiles)
    {
      ContentInfo contentInfo = new ContentInfo(pair.Value);
      SignedCms signCms = new SignedCms(contentInfo, true);                   

      if (signCms.Certificates.Count != 0)
      {
        //Certificates Collection always is empty. Why?
        foreach (X509Certificate2 x509 in signCms.Certificates)
        {
          if ((x509.SerialNumber != userCertX509.SerialNumber) 
              || (x509.Thumbprint != userCertX509.Thumbprint))
          {
            isValid = false;
            return isValid;
          }
        }

        isValid = true;
        return isValid;
      }
    }
  }
  catch (Exception ex)  
  {
    //here process exception code
  }           

  return isValid;
}



private bool signatureValidator(Dictionary<string, byte[]> dictP7SFiles, 
    Dictionary<string, byte[]> dictNotP7SFiles, X509Certificate2 userCertX509)
{
  bool isValid = false;
  try
  {              
    byte[] data = dictP7SFiles["ZayavUL_3594c921f545406d9b8734bbe28bf894.doc"];
    byte[] publicKey;
    byte[] signature;
    object hasher = SHA1.Create(); // Our chosen hashing algorithm.
    // Generate a new key pair, then sign the data with it:
    using (var publicPrivate = new RSACryptoServiceProvider())
    {
      signature = publicPrivate.SignData(data, hasher);
      publicKey = publicPrivate.ExportCspBlob(false); // get public key
    }
    // Create a fresh RSA using just the public key, then test the signature.
    using (var publicOnly = new RSACryptoServiceProvider())
    {
      publicOnly.ImportCspBlob(publicKey);

      isValid = publicOnly.VerifyData(data, hasher, signature); // Return True

      //isValid = ByteArrayCompare(dictP7SStreams["ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s"], signature);

      byte[] p7sDetachedSignature = File.ReadAllBytes(@"D:\ZayavUL_3594c921f545406d9b8734bbe28bf894.doc_1.p7s");
      isValid = ByteArrayCompare(p7sDetachedSignature, signature);
    }                
  }
  catch (Exception)
  {
    //here process exception code
  }

  return isValid;    
}

【问题讨论】:

  • 我认为这类文件不存储证书。您可以使用 OpenSSL.exe 对其进行测试。 openssl.exe asn1parse -in file.p7s -inform DER。另外,谢谢你的代码,它帮助了我。

标签: c# cryptography digital-signature


【解决方案1】:

您做错的主要事情是重新生成 CMS 和签名。您应该解析 CMS 消息,然后在验证时指明外部内容。

  1. 如何正确验证 .p7s 文件与其对应文件的分离签名?

查看following Java code on SO 了解如何验证签名; C# 应该使用相同的架构,因此应该类似地工作。

  1. 在方法certificateValidator(参见下面的方法)中,如何验证从.p7s 文件中提取的证书与从Base64 格式的输入字符串中提取的证书的一致性?

解码base 64证书,对证书进行链式验证和验证。您要执行多少验证(例如检查生效日期)取决于您。

  1. foreach 的代码行(signCms.Certificates 中的 X509Certificate2 x509){ } ---> 证书集合始终为空。为什么?

您只是在构建新的 CMS 结构时没有放入。


您当然也不应该重新生成签名。通常在验证期间您不会拥有私钥,并且该算法可能与 CMS 文档中使用的算法不匹配。此外,即使可以,签名生成也并不总是确定性的(您可能会得到不同的签名值)。

【讨论】:

  • 抱歉回复晚了,重温了旧的加密信息。希望你能同时解决它:)
猜你喜欢
  • 1970-01-01
  • 2014-11-12
  • 1970-01-01
  • 1970-01-01
  • 2017-03-23
  • 1970-01-01
  • 2020-02-05
  • 2023-02-20
  • 1970-01-01
相关资源
最近更新 更多