带签名文件的 iTextsharp
iTextsharp with signed file
我对 PDF 签名有疑问。我收到了一个 PDF 文件,该文件是使用 Life Cycle (Acrobat) 创建的,其中已经包含对某些 acroFields 的两个数字签名。我必须将一些数据放在其他 acrofields 上,我在 C# 中使用以下代码:
PdfReader pdfReader = null;
PdfStamper stamper = null;
string filePDF = @"C:\Visual Studio Solutions\Visual Windows\cpce Certificaciones\prueba_xfa.pdf";
string outPDF = @"C:\Visual Studio Solutions\Visual Windows\cpce Certificaciones\prueba_xfa_out.pdf";
try
{
using (var inStream = new FileStream(filePDF, FileMode.Open))
{
pdfReader = new PdfReader(inStream);
}
using (var outStream = new FileStream(outPDF, FileMode.Create))
{
stamper = new PdfStamper(pdfReader, outStream, '[=10=]', true);
var form = stamper.AcroFields;
form.SetField("FORMULARIO[0].SUBFORMULARIO[0].ConsejoSubForm[0].OBLEA[0]", "probando");
stamper.Close();
pdfReader.Close();
}
}
catch (Exception ex)
{
throw new Exception("error: " + ex.Message);
}
问题是新文件破坏了之前的两个签名。
我不知道出了什么问题。
提前致谢
考虑到对问题的评论,您观察到您的 iTextSharp/C# 代码破坏了两个先前的签名,而您的 iText/Java 代码仅破坏了第一个签名。所以这里有两个感兴趣的话题:
- 为什么 C# 和 Java 代码的结果不同?
- 为什么签名会被破坏?
我试着重现了这个问题。不幸的是,我得到了不同的结果,这里 C# 和 Java 版本都只破坏了第一个签名。因此,我在这里尝试解释第一个签名被破坏的原因。
为什么第一个签名坏了?
Adobe Acrobat 签名属性显示 PDF 的原始修订版未被篡改。因此,您的代码添加的增量更新中所做的一些更改被认为是无效的。 Acrobat 列出了 ConsejoSubForm.OBLEA
、ContribuyenteSubForm.FECHA_CIERRE
、ContribuyenteSubForm.FECHA_REALIZACION
、ContribuyenteSubForm.LeyendaAdjuntarArchivo
和 Encabezado.FECHA_ACTUAL
字段中的修改(我删除了所有 [0]
和 FORMULARIO[0].SUBFORMULARIO[0]
前缀)。
检查 XFA 发现签名字段 FIRMA_CONTRIBUYENTE
(包含第一个签名的字段)不允许更改收集为 camposFirmaContribuyente
的字段;除 ConsejoSubForm.OBLEA
之外的所有修改字段都在此集合中。
因此,第一个签名显示为已损坏,因为四个 FECHA_*
和 Leyenda*
字段发生了变化。
的确,正如您自己所说,日期字段已被清除。而如果你仔细观察Leyanda值,你会发现不同。
为什么所有这些字段都有变化?
该代码旨在仅更改 ConsejoSubForm.OBLEA
字段(不受第一个签名保护)而不更改其他四个字段。那为什么他们也改变了?
首先,比较签名前后的XFA表单XMLs,唯一的变化(超过等效XML序列化)确实是[=11的值=].特别是,声称更改的其他四个字段 在 XFA XML!
中未更改
因此,iText 既没有明确更改它不打算更改的字段,也无法在 XFA 中找到其他更改 XML。
为什么 Adobe 认为它们已更改?
在 XFA XML 中搜索四个 FECHA_*
和 Leyenda*
字段值,发现这些值 不 包含在{http://www.xfa.org/schema/xfa-data/1.0/}:datasets
部分(根据 XFA 规范 包含与表单 一起使用的所有数据集)但在单独的 {http://www.xfa.org/schema/xfa-form/2.8/}:form
部分中。
XFA规范3.3中没有规定这一段
关于此部分的一件事引人注目的是 {http://www.xfa.org/schema/xfa-form/2.8/}:form
元素包含一个 checksum
属性:
<form xmlns="http://www.xfa.org/schema/xfa-form/2.8/"
checksum="Y3ReuUF4b/rARe9AfHzXknOOs5Q=">
这个属性实际上是 Bruno Lowagie this question 的重点。
我对此的解读:
- Adobe 使用 XFA 的这个专有部分 XML 来存储 XFA 数据集中不包含的额外表单数据。
- 此外,它在整个表单状态的某些表示上存储校验和,以确定该专有部分仍然基于其他表单数据的当前状态。
- iText 没有更新这个未记录的校验和。
- 因此,Adobe Acrobat 在打开表单时会检测到基础表单数据的更改未与专有
{http://www.xfa.org/schema/xfa-form/2.8/}:form
部分同步,因此 重新初始化此部分中的数据 根据各自的字段定义更改四个 FECHA_*
和 Leyenda*
字段值。
- 验证第一个签名时,Adobe Reader 确定由于 重新初始化 导致的更改不被签名字段定义所允许,并将签名显示为坏了。
TL;DR
在手头的 XFA 表单中,XFA 规范的专有 Adobe 扩展用于某些表单数据和表单数据校验和。由于此扩展未公开记录,iText 无法对其进行适当更新。这使得 Adobe Acrobat 认为在 iText 更新 OBLEA 字段后签名已损坏。
此类专有添加可能是 PDF 2.0 XFA 表单被宣布弃用的原因。
因此,如果要使用 iText 编辑 XFA 表单,请确保表单完全符合 XFA 规范的规定,并且不包含专有扩展。
我对 PDF 签名有疑问。我收到了一个 PDF 文件,该文件是使用 Life Cycle (Acrobat) 创建的,其中已经包含对某些 acroFields 的两个数字签名。我必须将一些数据放在其他 acrofields 上,我在 C# 中使用以下代码:
PdfReader pdfReader = null;
PdfStamper stamper = null;
string filePDF = @"C:\Visual Studio Solutions\Visual Windows\cpce Certificaciones\prueba_xfa.pdf";
string outPDF = @"C:\Visual Studio Solutions\Visual Windows\cpce Certificaciones\prueba_xfa_out.pdf";
try
{
using (var inStream = new FileStream(filePDF, FileMode.Open))
{
pdfReader = new PdfReader(inStream);
}
using (var outStream = new FileStream(outPDF, FileMode.Create))
{
stamper = new PdfStamper(pdfReader, outStream, '[=10=]', true);
var form = stamper.AcroFields;
form.SetField("FORMULARIO[0].SUBFORMULARIO[0].ConsejoSubForm[0].OBLEA[0]", "probando");
stamper.Close();
pdfReader.Close();
}
}
catch (Exception ex)
{
throw new Exception("error: " + ex.Message);
}
问题是新文件破坏了之前的两个签名。 我不知道出了什么问题。 提前致谢
考虑到对问题的评论,您观察到您的 iTextSharp/C# 代码破坏了两个先前的签名,而您的 iText/Java 代码仅破坏了第一个签名。所以这里有两个感兴趣的话题:
- 为什么 C# 和 Java 代码的结果不同?
- 为什么签名会被破坏?
我试着重现了这个问题。不幸的是,我得到了不同的结果,这里 C# 和 Java 版本都只破坏了第一个签名。因此,我在这里尝试解释第一个签名被破坏的原因。
为什么第一个签名坏了?
Adobe Acrobat 签名属性显示 PDF 的原始修订版未被篡改。因此,您的代码添加的增量更新中所做的一些更改被认为是无效的。 Acrobat 列出了 ConsejoSubForm.OBLEA
、ContribuyenteSubForm.FECHA_CIERRE
、ContribuyenteSubForm.FECHA_REALIZACION
、ContribuyenteSubForm.LeyendaAdjuntarArchivo
和 Encabezado.FECHA_ACTUAL
字段中的修改(我删除了所有 [0]
和 FORMULARIO[0].SUBFORMULARIO[0]
前缀)。
检查 XFA 发现签名字段 FIRMA_CONTRIBUYENTE
(包含第一个签名的字段)不允许更改收集为 camposFirmaContribuyente
的字段;除 ConsejoSubForm.OBLEA
之外的所有修改字段都在此集合中。
因此,第一个签名显示为已损坏,因为四个 FECHA_*
和 Leyenda*
字段发生了变化。
的确,正如您自己所说,日期字段已被清除。而如果你仔细观察Leyanda值,你会发现不同。
为什么所有这些字段都有变化?
该代码旨在仅更改 ConsejoSubForm.OBLEA
字段(不受第一个签名保护)而不更改其他四个字段。那为什么他们也改变了?
首先,比较签名前后的XFA表单XMLs,唯一的变化(超过等效XML序列化)确实是[=11的值=].特别是,声称更改的其他四个字段 在 XFA XML!
中未更改因此,iText 既没有明确更改它不打算更改的字段,也无法在 XFA 中找到其他更改 XML。
为什么 Adobe 认为它们已更改?
在 XFA XML 中搜索四个 FECHA_*
和 Leyenda*
字段值,发现这些值 不 包含在{http://www.xfa.org/schema/xfa-data/1.0/}:datasets
部分(根据 XFA 规范 包含与表单 一起使用的所有数据集)但在单独的 {http://www.xfa.org/schema/xfa-form/2.8/}:form
部分中。
XFA规范3.3中没有规定这一段
关于此部分的一件事引人注目的是 {http://www.xfa.org/schema/xfa-form/2.8/}:form
元素包含一个 checksum
属性:
<form xmlns="http://www.xfa.org/schema/xfa-form/2.8/"
checksum="Y3ReuUF4b/rARe9AfHzXknOOs5Q=">
这个属性实际上是 Bruno Lowagie this question 的重点。
我对此的解读:
- Adobe 使用 XFA 的这个专有部分 XML 来存储 XFA 数据集中不包含的额外表单数据。
- 此外,它在整个表单状态的某些表示上存储校验和,以确定该专有部分仍然基于其他表单数据的当前状态。
- iText 没有更新这个未记录的校验和。
- 因此,Adobe Acrobat 在打开表单时会检测到基础表单数据的更改未与专有
{http://www.xfa.org/schema/xfa-form/2.8/}:form
部分同步,因此 重新初始化此部分中的数据 根据各自的字段定义更改四个FECHA_*
和Leyenda*
字段值。 - 验证第一个签名时,Adobe Reader 确定由于 重新初始化 导致的更改不被签名字段定义所允许,并将签名显示为坏了。
TL;DR
在手头的 XFA 表单中,XFA 规范的专有 Adobe 扩展用于某些表单数据和表单数据校验和。由于此扩展未公开记录,iText 无法对其进行适当更新。这使得 Adobe Acrobat 认为在 iText 更新 OBLEA 字段后签名已损坏。
此类专有添加可能是 PDF 2.0 XFA 表单被宣布弃用的原因。
因此,如果要使用 iText 编辑 XFA 表单,请确保表单完全符合 XFA 规范的规定,并且不包含专有扩展。