使用BouncyCastle读取多次签名(.xml.p7m.p7m)的XML文件的签名内容(包括错误的解决方案原型)

时间:2019-01-30 18:18:47

标签: c# stream bouncycastle

我正在尝试读取多次签名的XML文件的签名内容。
我编写了这段代码来读取已签名的内容,并且如果文件已被一次签名,则可以正常工作:

public static MyType LoadFromSignedFile(string fileName)
{  
    using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        CmsSignedData signedFile = new CmsSignedData(fileStream);

        XmlSerializer serializer = new XmlSerializer(typeof(MyType));
        using (MemoryStream memStream = new MemoryStream())
        {
            signedFile.SignedContent.Write(memStream);
            memStream.Position = 0;
            using (StreamReader sr = new StreamReader(memStream))
                return serializer.Deserialize(sr) as MyType;
        }
    }
}  

如果文件被签名两次或更多次(反XML文档(1,1)中的错误),则反序列化将引发错误,这是可以的,因为SignedContent包含另一个SignedContent签名。

我正在尝试遍历签名者(使用GetSigners())以在每个循环中读取签名内容,但是即使文件被签名两次,GetSigners()也会返回1。
如果像这样“手动”完成反序列化,则效果很好:

Stream st = parser.GetSignedContent().ContentStream;
CmsSignedDataParser p = new CmsSignedDataParser(st);
Stream st2 = p.GetSignedContent().ContentStream;

using (StreamReader sr = new StreamReader(st2))
    return serializer.Deserialize(sr) as MyType;  

这是使用DataParser对象的糟糕的解决方案原型:

public static MyType LoadInvoiceFromSignedFile(string fileName)
{
    using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
    {
        CmsSignedDataParser parser = new CmsSignedDataParser(fileStream);
        XmlSerializer serializer = new XmlSerializer(typeof(MyType));

        CmsSignedData data = new CmsSignedData(new FileStream(fileName, FileMode.Open, FileAccess.Read));
        Stream internalStream = null;

        // --> try to deserialize the XML hoping there is only 1 signature
        bool isError = false;
        try
        {
            using (MemoryStream memStream = new MemoryStream())
            {
                CmsSignedData signedFile = new CmsSignedData(new FileStream(fileName, FileMode.Open, FileAccess.Read));
                signedFile.SignedContent.Write(memStream);
                memStream.Position = 0;
                using (StreamReader sr = new StreamReader(memStream))
                    return serializer.Deserialize(sr) as MyType;
            }
        }catch(Exception ex)
        {
            isError = true;
        }
        // <--

        // --> signed multiple times, trying with a loop
        if (isError)
        {
            for (int i = 0; i < data.GetSignerInfos().GetSigners().Count; i++)
            {
                internalStream = parser.GetSignedContent().ContentStream;
                try
                {
                    parser = new CmsSignedDataParser(internalStream);
                }
                catch (Exception ex)
                {
                    using (MemoryStream memStream = new MemoryStream())
                    {
                        CmsSignedData signedFile = new CmsSignedData(new FileStream(fileName, FileMode.Open, FileAccess.Read));
                        signedFile.SignedContent.Write(memStream);
                        memStream.Position = 0;
                        using (StreamReader sr = new StreamReader(memStream))
                            return serializer.Deserialize(sr) as MyType;
                    }
                }
            }

            using (StreamReader sr = new StreamReader(parser.GetSignedContent().ContentStream))
                return serializer.Deserialize(sr) as MyType;
        }

        // <--

        return null;
    }
}

CmsTypeStream既不支持seek也不支持position,因此我无法识别流的结尾(也不太了解Stream,这是导致错误的代码)。

0 个答案:

没有答案