使用 ItextSharp 验证数字签名

2023-12-06

我正在尝试使用 iTextSharp 验证 C# 中的数字签名。

我按照 iText 网络中的示例进行操作(http://gitlab.itextsupport.com/itextsharp/tutorial/blob/master/signatures/chapter5/C5_03_CertificateValidation/C5_03_CertificateValidation.cs)但结果不是我所期望的。具体来说,当尝试通过 OCSP 或 CRL 验证签名时,结果通常是无法验证签名。我认为这种情况不应该发生,因为 Adob​​e Reader 可以正常验证签名。

我用来测试验证的 pdf 可以在此链接中找到:https://blogs.adobe.com/security/SampleSignedPDFDocument.pdf

这是我正在使用的代码(上面链接中示例的简短版本):

static void Main(String[] args)
{
    LoggerFactory.GetInstance().SetLogger(new SysoLogger());
    C5_03_CertificateValidation app = new C5_03_CertificateValidation();
    app.VerifySignatures(EXAMPLE); //Pdf file I'm using to test the verification
}

public void VerifySignatures(String path)
{
    Console.WriteLine(path);
    PdfReader reader = new PdfReader(path);
    AcroFields fields = reader.AcroFields;
    List<String> names = fields.GetSignatureNames();
    foreach (string name in names)
    {
        Console.WriteLine("===== " + name + " =====");
        VerifySignature(fields, name);
    }
    Console.WriteLine();
}

public PdfPKCS7 VerifySignature(AcroFields fields, String name)
{
    PdfPKCS7 pkcs7 = fields.VerifySignature(name);
    X509Certificate[] certs = pkcs7.SignCertificateChain;
    DateTime cal = pkcs7.SignDate;

    X509Certificate signCert = certs[0];
    X509Certificate issuerCert = (certs.Length > 1 ? certs[1] : null);
    Console.WriteLine("=== Checking validity of the document at the time of signing ===");
    CheckRevocation(pkcs7, signCert, issuerCert, cal);
    Console.WriteLine("=== Checking validity of the document today ===");
    CheckRevocation(pkcs7, signCert, issuerCert, DateTime.Now);
    return pkcs7;
}

public static void CheckRevocation(PdfPKCS7 pkcs7, X509Certificate signCert, X509Certificate issuerCert, DateTime date)
{
    List<BasicOcspResp> ocsps = new List<BasicOcspResp>();
    if (pkcs7.Ocsp != null)
        ocsps.Add(pkcs7.Ocsp);
    OcspVerifier ocspVerifier = new OcspVerifier(null, ocsps);
    List<VerificationOK> verification =
        ocspVerifier.Verify(signCert, issuerCert, date);
    if (verification.Count == 0)
    {
        List<X509Crl> crls = new List<X509Crl>();
        if (pkcs7.CRLs != null)
            foreach (X509Crl crl in pkcs7.CRLs)
                crls.Add(crl);
        CrlVerifier crlVerifier = new CrlVerifier(null, crls);
        verification.AddRange(crlVerifier.Verify(signCert, issuerCert, date));
    }
    if (verification.Count == 0)
        Console.WriteLine("The signing certificate couldn't be verified with the example");
    else
        foreach (VerificationOK v in verification)
            Console.WriteLine(v);


    //Code not in the example, added by me
    //This way, I can find out if the certificate is revoked or not (through CRL). Not sure if it's the right way though
    if (verification.Count == 0 && pkcs7.CRLs != null && pkcs7.CRLs.Count != 0)
    {
        bool revoked = false;
        foreach (X509Crl crl in pkcs7.CRLs)
        {
            revoked = crl.IsRevoked(pkcs7.SigningCertificate);
            if (revoked)
                break;
        }

        Console.WriteLine("Is certificate revoked?: " + revoked.ToString());
    }
}

这是我得到的输出:

===== Signature2 =====

=== Checking validity of the document at the time of signing ===
i.t.p.s.OcspClientBouncyCastle INFO  Getting OCSP from http://adobe-ocsp.geotrust.com/responder
iTextSharp.text.pdf.security.OcspClientBouncyCastle ERROR Error en el servidor remoto: (502) Puerta de enlace no válida.
i.t.p.s.OcspVerifier INFO  Valid OCSPs found: 0
i.t.p.s.CrlVerifier INFO  Getting CRL from http://crl.geotrust.com/crls/adobeca1.crl
i.t.p.s.CrlVerifier INFO  Valid CRLs found: 0
The signing certificate couldnt be verified with the example
Is certificate revoked?: False

=== Checking validity of the document today ===
i.t.p.s.OcspClientBouncyCastle INFO  Getting OCSP from http://adobe-ocsp.geotrust.com/responder
iTextSharp.text.pdf.security.OcspClientBouncyCastle ERROR Error en el servidor remoto: (502) Puerta de enlace no válida.
i.t.p.s.OcspVerifier INFO  Valid OCSPs found: 0
i.t.p.s.CrlVerifier INFO  Getting CRL from http://crl.geotrust.com/crls/adobeca1.crl
i.t.p.s.CrlVerifier INFO  Valid CRLs found: 0
The signing certificate couldnt be verified with the example
Is certificate revoked?: False

我不明白为什么签名无法验证,因为 Adob​​e 可以做到这一点。任何想法表示赞赏。


这个问题有两个方面:

  • 为什么 iTextSharp 似乎无法验证 Adob​​e 提供的给定示例签名?
  • 应在哪一天使用哪种 CRL 进行吊销检查?

使用 iTextSharp 验证给定的签名

使用来自的示例代码C5_03_CertificateValidation.csOP 无法验证相关证书(特别是签名者证书)是否未被撤销,也无法验证“签署时” nor "today"。另一方面,我可以立即验证“签署时”.

OP 的测试和我的测试之间的主要区别在于,前者使用 OP 的时区 UTC-3 进行,而我的测试使用 UTC+2。

因此,我使用不同的系统时区运行代码,实际上:验证仅在 UTC-01 及以上时区成功,即 UTC-01、UTC、UTC+01,...

返回的时间为DateTime cal = pkcs7.SignDate在测试中结果是使用当前本地时区给出的。

因此,显然 CRL 验证代码确实not根据本地时区使用时间,而不是使用某个固定时区,大概是 UTC 本身。

因此,可以通过以下方式使示例代码普遍工作

changing

crlVerifier.Verify(signCert, issuerCert, date)

to

crlVerifier.Verify(signCert, issuerCert, date.ToUniversalTime())

正如OP在测试后可以确认的那样。

选择正确的日期和 CRL 进行吊销检查

OP 提到他更愿意使用当前时间和相关 PKI 的 CRL 的当前版本来执行撤销检查。

虽然这种方法似乎利用了最新的可用信息,但其用处是有限的:

  • 如果受审查的证书现在已超过其原始有效期(即其有效期已过),但在签署时尚未到期,则有关其在签署时可能被撤销的信息可能不会出现在证书上。不再 CRL 了。事实上,根据 RFC 5280

    不得删除条目 从 CRL 开始直至出现在定期发布的一份 CRL 上 超过被撤销证书的有效期。

    因此,言下之意是,may在任何发布的版本中从 CRL 中删除after有效期。

    因此,使用比证书有效期结束时间更新的 CRL 是没有意义的。

  • 即使受审查的证书尚未超出其原始有效期,PKI 提供商也可能已经倒闭。在这种情况下,吊销信息的所有访问点现在可能仅提供在 PKI 仍处于活动状态或根本没有活动时创建的 CRL 的最终版本。

    在这种情况下,只要 CRL 足够新,就可以使用最终的 CRL 或仍然可用的最新 CRL(例如在某些 CRL 缓存中)。

因此,验证策略通常允许甚至要求使用较旧的 CRL,只要它足够新,至少是 CRLnextUpdate值必须在签名时间之后,并且同时足够旧,至少是 CRL 的thisUpdate值必须是在证书有效期结束之前。

不过,需要考虑的一项是在检查是否可以使用较旧的 CRL 时要比较的签名时间。

The pkcs7.SignDate上面的 iText 示例代码中使用的可能只是 PDF 或 CMS 容器中可能被伪造的字段内容:有人可能已经掌握了私钥;在关联的证书被撤销后,该人仍然可能滥用密钥,将签名时间信息设置为撤销之前的日期。

因此,您可能会以不同的方式确定签名日期。例如。

  • 如果签名容器包含签名时间戳或者PDF文档包含较晚的文档时间戳,并且如果该时间戳可以信任,则可以使用该时间戳的时间;

  • 如果签名的文档已经在本地存储了一段时间(例如在某些归档系统中)并且存储时间已知并且可以信任,则可以使用该时间;

  • ...

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 ItextSharp 验证数字签名 的相关文章

  • 用 C++ 进行服装建模 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在编写一些软件 最终会绘制一个人体框架 可以配置各种参数 并且计划是在假人身上放置某种衣服 我研究
  • 在 C# 中创建具有单独列的分隔文本

    我一直在尝试在 C 中创建一个制表符限制的文本文件 以便数据正确显示在单独的列中 Firstname Lastname Age John Smith 17 James Sawyer 31 我尝试过 t 字符 但我得到的只是 Firstnam
  • 如何读取扩展文件属性/文件元数据

    因此 我按照教程使用 ASP net core 将文件 上传 到本地路径 这是代码 public IActionResult About IList
  • Unix网络编程澄清

    我正在翻阅这本经典书籍Unix网络编程 https rads stackoverflow com amzn click com 0139498761 当我偶然发现这个程序时 第 6 8 节 第 179 180 页 include unp h
  • 向 Nhibernate 发出 SQL 查询

    如何将此 SQL 查询发送给 Nhibernate SELECT Customer name FROM Company INNER JOIN Customer ON Company CompanyId Customer CompanyId
  • 如何将 #ifdef DEBUG 添加到 Xcode?

    我的项目中有一些代码永远不应该在发布版本中使用 但在测试时很有用 我想做这样的事情 ifdef DEBUG Run my debugging only code endif 在 Xcode 4 中哪里添加 DEBUG 设置 我尝试将其放入
  • 如何修复此错误“GDI+ 中发生一般错误”?

    从默认名称打开图像并以默认名称保存 覆盖它 我需要从 Image Default jpg 制作图形 将其放在 picturebox1 image 上并在 picurebox1 上绘制一些图形 它有效 这不是我的问题 但我无法保存 pictu
  • 在新的浏览器进程中打开 URL

    我需要在新的浏览器进程中打开 URL 当浏览器进程退出时我需要收到通知 我当前使用的代码如下 Process browser new Process browser EnableRaisingEvents true browser Star
  • 互斥体实现可以互换(独立于线程实现)

    所有互斥体实现最终都会调用相同的基本系统 硬件调用吗 这意味着它们可以互换吗 具体来说 如果我使用 gnu parallel算法 使用openmp 并且我想让他们称之为线程安全的类我可以使用boost mutex用于锁定 或者我必须编写自己
  • 将 System.Windows.Input.KeyEventArgs 键转换为 char

    我需要将事件参数作为char 但是当我尝试转换 Key 枚举时 我得到的字母和符号与传入的字母和符号完全不同 如何正确地将密钥转换为字符 这是我尝试过的 ObserveKeyStroke this new ObervableKeyStrok
  • 生成(非常)大的非重复整数序列而不进行预洗牌

    背景 我编写了一个简单的媒体客户端 服务器 我想生成一个不明显的时间值 随从客户端到服务器的每个命令一起发送 时间戳中将包含相当多的数据 纳秒分辨率 即使它不是真正准确 因为现代操作系统中计时器采样的限制 等 我想做的 在 Linux 上
  • 用于检查项目文件中的项目变量和引用路径的 api

    我正在研究一个 net application VS2010 与 x 没有 解和变量号这些解决方案中的项目数量 我需要检查项目属性 特定于一定数量的项目 是否同质 并且检查 验证构建期间的参考路径 有没有一个API是这样的吗 如果没有 我该
  • 如何编写一个同时需要请求和响应Dtos的ServiceStack插件

    我需要提供本地化数据服务 所有本地化的响应 Dto 都共享相同的属性 IE 我定义了一个接口 ILocalizedDto 来标记那些 Dto 在请求端 有一个ILocalizedRequest对于需要本地化的请求 Using IPlugin
  • std::async 与重载函数

    可能的重复 std bind 重载解析 https stackoverflow com questions 4159487 stdbind overload resolution 考虑以下 C 示例 class A public int f
  • .NET中的LinkedList是循环链表吗?

    我需要一个循环链表 所以我想知道是否LinkedList是循环链表吗 每当您想要移动列表中的 下一个 块时 以循环方式使用它的快速解决方案 current current Next current List First 电流在哪里Linke
  • C++ 密码屏蔽

    我正在编写一个代码来接收密码输入 下面是我的代码 程序运行良好 但问题是除了数字和字母字符之外的其他键也被读取 例如删除 插入等 我知道如何避免它吗 特q string pw char c while c 13 Loop until Ent
  • 英特尔 Pin 与 C++14

    问题 我有一些关于在 C 14 或其他 C 版本中使用英特尔 Pin 的问题 使用较新版本从较旧的 C 编译代码很少会出现任何问题 但由于 Intel Pin 是操作指令级别的 如果我使用 C 11 或 C 14 编译它 是否会出现任何不良
  • 使用 GROUP 和 SUM 的 LINQ 查询

    请帮助我了解如何使用带有 GROUP 和 SUM 的 LINQ 进行查询 Query the database IEnumerable
  • 检查Windows控制台中是否按下了键[重复]

    这个问题在这里已经有答案了 可能的重复 C 控制台键盘事件 https stackoverflow com questions 2067893 c console keyboard events 我希望 Windows 控制台程序在按下某个
  • 防止在工厂方法之外实例化对象

    假设我有一个带有工厂方法的类 class A public static A newA Some code logging return new A 是否可以使用 a 来阻止此类对象的实例化new 那么工厂方法是创建对象实例的唯一方法吗 当

随机推荐

  • 使用app sdk登录Rally

    如何使用 app sdk 以编程方式登录 Rally 我在拉力赛之外使用它 它首先重定向到登录页面 我想在没有用户输入凭据的情况下登录 Rally 有一个称为 LoginKey 的工具 可用于帮助对应用程序进行外部身份验证 如果您想在不登录
  • 如何在pygame中上下移动一个盒子[矩形作为正方形]?

    我正在尝试上下移动一个盒子pygame 我可以用钥匙向左移动盒子a并右键使用d 我怎样才能上下移动它 我的代码 import sys import pygame as pg def main screen pg display set mo
  • Vuejs 和数据表:使用 v-for 填充数据时表为空

    我正在尝试使用 vuejs v for 指令和 ajax 来填充数据表来获取数据 但该表始终显示 表中没有可用数据 即使显示了一些数据 并且底部还显示 显示 0 到0 个条目 共 0 个条目 我猜这是因为 vuejs 是反应性的 表格可能无
  • 将页脚置于底部

    我想将页脚放置在页面底部 例如 在内容不多的页面上 我仍然需要底部的页脚 但如果内容长于页面的高度 则必须将页脚向下推 可以仅使用 CSS 来完成还是需要添加一些 jQuery 魔法 您应该使用其中之一粘页脚技巧
  • JUnit 测试用例在 eclipse 中通过,但在 Maven 构建中失败

    我使用 spring 为 JPA 编写了一个 JUnit 测试用例 测试用例在 eclipse 中通过 但是如果我使用 maven mvn test 执行相同的测试用例 它就会失败 我的测试用例是 import javax annotati
  • _IDTExtensibility2,什么DLL导入到ATL项目中?

    所以我正在努力解决我的问题Office 插件再次任务 我已经创建了ATL项目 添加了简单的类 现在想要添加接口实现 如下http www devarticles com c a Cplusplus Writing an MS Word Ad
  • 释放数据库中库存的最佳实践

    我正在构建一个售票应用程序 用于跟踪门票库存 并在特定门票售完时停用它们 我想知道当订单中途放弃时将库存释放回商店的最佳做法是什么 目前的流量 用户添加items to an order as line items和order付款成功后标记
  • 如何动态添加edittext到android

    我想将 edittext 动态添加到 android 显示 我想做一些类似于 Android 联系人的东西 您可以在其中动态添加字段并在不需要时删除它们 感谢您的帮助 动态查看一切 TextView tv new TextView this
  • printf 中 double 的正确格式说明符

    正确的格式说明符是什么double在 printf 中 是吗 f或者是 lf 我相信这是 f 但我不确定 代码示例 include
  • 如何将nif流文件从1.12版本迁移到1.16.3

    我有一个在 NiFi 1 12 0 中运行的数据流 此安装的相关属性如下 nifi sensitive props key nifi sensitive props key protected nifi sensitive props al
  • .net实体框架与oracle 11g

    我正在将实体框架与 Oracle 提供程序 Oracle ManagedDataAccessDTC 一起使用 从 Visual Studio 运行一切正常 但是当我将其发布到 IIS 时 我收到连接错误异常 这是我的 webconfig 女
  • 使用 dplyr 从数据帧中采样子组行

    如果我想从不同组中随机选择一些样本 我使用 plyr 包和下面的代码 require plyr sampleGroup lt function df size df sample nrow df size size iris sample
  • 跟踪 Android 应用程序内的用户空闲时间

    据我所知 没有系统API可供我获取用户空闲时间 当我说用户空闲时间时 我的意思是用户在我的应用程序内的触摸屏上进行一些交互 因此 我想自己跟踪它 我想到的方法是扩展Activity并覆盖onuserinteraction方法来保存最后用户活
  • 图像上传后,React Native 中仅 iOS 的图像 uri 为空

    在我的 React Native 应用程序中 我添加了上传多个图像的功能 这些图像将存储为 image 包括 uri 这对于 Android 来说非常有效 但对于iOS来说 创建的image 也包含一些数据 但与android完全不同 对于
  • 从“.exe”中删除调试信息[重复]

    这个问题在这里已经有答案了 如果我将 C 程序 exe 放入文本编辑器中 我可以在其中找到调试信息 我怎样才能删除它 编辑 我不关心 pdb 文件 我只关心可执行文件中有 pdb 文件的路径 该路径包含我的名字 在本例中是巧合 我的问题是如
  • 如何在.NET Core 3.1中的Newtonsoft JsonConverter中注入依赖

    我无法让依赖注入在 NET Core 3 1 中为以下 Newtonsoft JsonConverter 工作 我只想在属性级别使用它 而不是在全局级别使用它 因此 只有当指定的属性来自某个类时才应执行 JsonConverter publ
  • 如何通过 SQL 将计算列添加到 Access

    如何在 SQL 中向 Access 表添加计算列 我知道我可以使用 SQL 添加一列 如下所示 ALTER TABLE Clients ADD COLUMN AccountDate TEXT 60 谢谢 维托尔 您无法使用 SQL 添加计算
  • Jackson 的 JsonIgnore

    JsonIgnore 注释似乎对我不起作用 有什么想法吗 public class JsonTest implements Serializable JsonIgnore private static JsonTest instance n
  • 在最新的 64 位 Intel CPU 上,如何在没有隐式锁的情况下与寄存器交换堆栈顶部?

    x64 调用约定使用寄存器最多前 4 个参数 rcx rdx r8 r9 并将其余参数传递到堆栈上 在这种情况下 处理补充参数的明显方法是asm程序如下 procedure example param1 rcx param2 rdx par
  • 使用 ItextSharp 验证数字签名

    我正在尝试使用 iTextSharp 验证 C 中的数字签名 我按照 iText 网络中的示例进行操作 http gitlab itextsupport com itextsharp tutorial blob master signatu