验证分离的签名(* .p7s文件)和X509Certificate2

时间:2012-09-02 22:42:57

标签: c# cryptography digital-signature

我在方法中收到一个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中的证书。

  3. 问题

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

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

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

    4. 输入参数

      • Dictionary <string, byte[]> dictP7SFiles(键 - 文件名* .p7s,值 - 字节数组,表示* .p7s文件)

      • Dictionary <string, byte[]> dictNotP7SFiles(key - 使用* .p7s文件中的分离签名签名的文件名,值 - 字节数组,表示文件)

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

      代码

      以下是测试验证步骤的实施(参见上面的2个步骤):

      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;    
      }
      

1 个答案:

答案 0 :(得分:0)

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

  
      
  1. 如何正确验证.p7s文件的分离签名?
  2.   

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

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

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

  
      
  1. 代码行foreach(X509Certificate2 x509 in signCms.Certificates){} ---&gt;证书集合始终为空。为什么?
  2.   

在构建新的CMS结构时,你根本没有把它放进去。

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