当前位置: 首页 > 知识库问答 >
问题:

使用新的比利时身份证签署PDF(eid中间件和itext)

耿俊
2023-03-14

我试着用比利时身份证在一些pdf上签名。为了实现这一点,我使用比利时eid中间件对数据进行签名,并使用itext7在pdf上盖章。

我使用了一个PdfSigner(itext),并实现了一个IExternalSignature来调用eid中间件对消息进行签名。

所有这些都适用于带有加密RSA和哈希SHA256的比利时身份证1.7。

但是当我尝试使用加密ECDSA和哈希SHA384的新比利时身份证1.8签名时,adobe阅读器(或其他阅读器)无法验证签名。“文档已被更改或损坏”。

这似乎是散列或。。。

我搜索了几天,但我不知道如何修复。。。

有人知道出了什么问题吗?

提前感谢你的帮助。

这里有一些额外的信息。

外部签名类:

    internal sealed class BeIDSignature : IExternalSignature
    {
        public string GetEncryptionAlgorithm()
        {
            return eidWrapper.Instance.GetEncryptionAlgorithm().ToString();
        }

        public string GetHashAlgorithm()
        {
            switch (EidWrapper.Instance.GetEncryptionAlgorithm())
            {
                case EidWrapper.EncryptionAmgorithm.RSA:
                    return DigestAlgorithms.SHA256;
                case EidWrapper.EncryptionAmgorithm.ECDSA:
                    return DigestAlgorithms.SHA384;
                default:
                    return null;
            }
        }
    
        public byte[] Sign(byte[] message)
        {
            return EidWrapper.Instance.SignData(message);
        }
    }

GetEncryption算法将根据芯片返回RSA或ECDSA。符号方法将使用eid-mw包来生成签名。

EidWrapper的sign方法的一小段代码:

    if (key.KeyType.KeyType == CKK.EC)
    {
        session.SignInit(new Mechanism(CKM.ECDSA_SHA384), key);
        return session.Sign(data);
    }
    else if (key.KeyType.KeyType == CKK.RSA)
    {
        session.SignInit(new Mechanism(CKM.SHA256_RSA_PKCS), key);
        return session.Sign(data);
    }

您可以在这里找到一个包含3个pdf文件的zip:

  • 原始文件

https://easyupload.io/yzscsu

再次感谢您抽出时间。

共有2个答案

蒯嘉赐
2023-03-14

一些想法:

  • 您确定芯片上有ECDSA密钥可用吗?我短暂地看了看留档(不确定它是最新的-参见eid-mw github),其中只提到了RSA。此外,如果您可以使用RSA/SHA256进行签名,那么也支持ECDSA将意味着卡上还有第二个密钥对-我对此有些怀疑;
  • 尝试使用您的eID在Adobe Reader中使用ECDSA/SHA384签名-检查您是否可以验证签名;
  • 在线验证签名,使用SD-DSS工具:诊断数据可能会帮助您定位错误的地方(例如生成了sha384摘要,但签名结构提到sha256作为摘要算法)。
闾丘冠玉
2023-03-14

这个答案总结了对这个问题的评论。

首先,我们必须认识到,目前(即对于iText 7.2.2),iText签名API的所有部分都不支持ECDSA。

这种限制主要是由于iTextPdfPKCS7类用于创建和验证嵌入在PDF中的CMS签名容器。当它用于创建签名容器时,它存储在signatureAlgorithm字段中的标识符不考虑使用的哈希算法。例如,它对RSA(带有PKCS1 v1.5填充)签名使用相同的值,不管它实际上是SHA1 WithRSA还是SHA256 WithRSA,或者两者的组合。

对于RSA来说,这是可以的,因为确实有一个标识符可以用于所有这些情况。对于DSA,这是可以的,因为在许多情况下,DSA仅限于与SHA1一起使用。

对于ECDSA来说,这是不好的,只有考虑哈希算法的标识符。iText在所有这些情况下都使用EC公钥标识符,这是完全错误的。几乎没有人注意到这个错误的原因是Adobe Acrobat validation显然忽略了signatureAlgorithm字段的内容:您甚至可以将RSA标识符写入ECDSA签名的这个字段,并且验证成功,没有任何问题的迹象。

因此,要创建正确的ECDSA签名,当前不应使用PdfPKCS7类。由于所有PdfSigner.signDetated方法在内部都使用PdfPKCS7类,这反过来意味着必须不使用它们,而是使用PdfSigner.signExternalContainer。因此,必须不使用IExternalSignature实现来检索自己的签名值,而是使用IExternalSignatureContainer实现,其中以不同的方式构建CMS签名容器,例如使用BouncyCastle类。

因此,在本案中,必须相应地更换IExternalSignature签名实现。

有关更多详细信息,请阅读iText知识库文章“使用iText 7进行数字签名”中的哪个界面。

ECDSA签名值可以存储为两种主要格式,一种是两个整数的TLV(DER)编码序列,另一种是两个整数的固定长度表示的串联(普通编码)。

根据使用的格式,ECDSA和PLAIN-ECDSA必须分别使用特定的算法标识符。如果需要特定标识符,可以将签名值从一种格式转换为另一种格式。

在本例中,比利时身份证以普通格式返回ECDSA签名值。要使用更常见的非PLAIN ECDSA标识符,必须将该值转换为DER格式。这可以使用以下方法完成:

byte[] PlainToDer(byte[] plain)
{
    int valueLength = plain.Length / 2;
    BigInteger r = new BigInteger(1, plain, 0, valueLength);
    BigInteger s = new BigInteger(1, plain, valueLength, valueLength);
    return new DerSequence(new DerInteger(r), new DerInteger(s)).GetEncoded(Asn1Encodable.Der);
}

说明:来自iText 7数字签名的代码示例的X509Cerate2Signature助手方法

 类似资料:
  • 遵循http://itextpdf.com/book/digitalsignatures中的“使用智能卡和PKCS#11签名文档”主题并创建与所提供的代码示例类似的代码示例后,签名的文件签名在Adobe Reader中无效,签名外观具有不可否认证书的名称(即eID所有者的名称),但在Adobe Reader的签名面板中显示: 我使用的是金雅拓PinPad和葡萄牙语eID与eID中间件软件一起安装,

  • 我有一个客户端服务器场景。 我有厚客户端和瘦客户端(浏览器),它们与我的服务器进行通信。 我的胖客户端使用X-509系统证书进行客户端证书身份验证,并与服务器通信 此外,此证书用于生成签名URL(带过期时间),以便我的瘦客户机与服务器通信,用于完整性和授权目的。在这种情况下,我也有一个基于令牌的方法用于身份验证。 现在,我想使用客户端凭据或基于身份验证代码将身份验证机制移动到基于OAuth的流。

  • 我想构建一个API路由,经过身份验证的用户和未经身份验证的用户都可以调用该路由,并根据用户是否经过身份验证返回数据。 我卡在使用身份验证::检查()。 控制器的功能是这样的: 我最后有两个场景: 情景1 在这种情况下,在控制器中,当我检查Auth::check()在if条件内时,无论用户是否经过身份验证,我总是得到错误条件。 方案 2 在这种情况下,在控制器中,当我检查Auth::check()时

  • 我正在尝试验证Java中的数字签名PDF文档。 我得到以下警告: 警告:无效字典,在偏移量15756处找到:“[”,但应为:“/” 警告:尚未实现签名字段的外观生成-您需要手动生成/更新 当我尝试使用bouncy castle验证签名时,我得到一个消息异常:message-digest属性值不匹配计算值 我想这是因为签名的原始PDF和我使用从PDFBox中获得的PDF不一样。 这里是我的bounc

  • 我对laravel中内置的用户身份验证功能有一个疑问。我让身份验证部分开始工作,但它似乎没有在会话中存储用户 管理控制程序代码: 中间件身份验证。php代码: 我有: 正确详细信息和登录页面后的路线路线路线: 注销后重定向路由: 我的问题是如何在这段代码中使用中间件。因为注销后我可以轻松访问url。后退按钮也在工作,我希望通过中间件进行laravel用户身份验证。。

  • 我在PINPAD阅读器上验证PIN码的所有尝试都以失败告终,我的情况如下: 比利时EID卡; Vasco DIGIPASS 875,蓝牙连接; 使用Vasco SDK的Android应用程序。 我使用APDU命令来选择和读取文件,设置安全环境(MSE: SET),经过无数的研究和合并来自不同留档的不同解决方案,我可以让读者询问我的个人识别码。但是使用伪APDU命令,我收到一个69|C#响应。同样的