我正在尝试读取多次签名的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,这是导致错误的代码)。