用手动签名入口创建Xades

发布于 2025-01-30 07:17:25 字数 3195 浏览 3 评论 0原文

我正在尝试使用我的身份证签名创建一个数字签名的XML文档。

我有两个程序的两个部分。第一个是从ID中获取文件的证书和签名。 为此,我正在使用类似的东西使用Python PKCS11库:

with open("input.xml", "rb") as f:
    data = f.read()

lib = lib('path/to/pkcs11/lib.dylib')
token = lib.get_token('name of token')

with token.open(PIN) as session:
    certificate = None

    for obj in session.get_objects({Attribute.CLASS: ObjectClass.CERTIFICATE}):
        certificate = obj
        der_bytes = certificate[Attribute.VALUE]

    with open('certificate.der', "wb") as f:
        f.write(der_bytes)

    # calculate SHA256 of data
    digest = session.digest(data, mechanism=Mechanism.SHA256)

    for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
        private_key = obj

    signature = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)

    with open('signature', "wb") as f:
        f.write(signature)

生成certift.dersignature文件,并且正在正常工作(至少我认为)

XML生成第一部分我正在使用Java中的欧洲DSS库:

DSSDocument toSignDocument = new FileDocument("input.xml");

// Preparing parameters for the XAdES signature
XAdESSignatureParameters parameters = new XAdESSignatureParameters();

// We choose the level of the signature (-B, -T, -LT, -LTA).     
parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B);

// We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED).
parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED);

// We set the digest algorithm to use with the signature algorithm. You must use the
// same parameter when you invoke the method sign on the token. The default value is SHA256 parameters.setDigestAlgorithm(DigestAlgorithm.SHA256);

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new FileInputStream("certificate.der");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);

// We set the signing certificate
parameters.setSigningCertificate(new CertificateToken(cert));

// Create common certificate verifier
CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();

// Create XAdES service for signature
XAdESService service = new XAdESService(commonCertificateVerifier);

// Get the SignedInfo XML segment that need to be signed.
ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));

// We invoke the service to sign the document with the signature value obtained in
// the previous step.
DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

File signedFile = new File("output.xml");
signedFile.createNewFile();
signedDocument.writeTo(new FileOutputStream(signedFile, false));

创建Xades文件,但是当我尝试验证签名时(例如,使用 this )它失败了,说签名不是完整的。

我在做什么错?

I am trying to create a digitally signed XML document using the signature from my ID card.

I have two parts of the program. The first one is getting the certificates and signature of the file from the ID.
For that I am using python PKCS11 library with something like this:

with open("input.xml", "rb") as f:
    data = f.read()

lib = lib('path/to/pkcs11/lib.dylib')
token = lib.get_token('name of token')

with token.open(PIN) as session:
    certificate = None

    for obj in session.get_objects({Attribute.CLASS: ObjectClass.CERTIFICATE}):
        certificate = obj
        der_bytes = certificate[Attribute.VALUE]

    with open('certificate.der', "wb") as f:
        f.write(der_bytes)

    # calculate SHA256 of data
    digest = session.digest(data, mechanism=Mechanism.SHA256)

    for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
        private_key = obj

    signature = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)

    with open('signature', "wb") as f:
        f.write(signature)

That generates the certificate.der and signature files and is working properly (at least I think)

For the XML generation part I am using Europe's DSS library in Java like this:

DSSDocument toSignDocument = new FileDocument("input.xml");

// Preparing parameters for the XAdES signature
XAdESSignatureParameters parameters = new XAdESSignatureParameters();

// We choose the level of the signature (-B, -T, -LT, -LTA).     
parameters.setSignatureLevel(SignatureLevel.XAdES_BASELINE_B);

// We choose the type of the signature packaging (ENVELOPED, ENVELOPING, DETACHED).
parameters.setSignaturePackaging(SignaturePackaging.ENVELOPED);

// We set the digest algorithm to use with the signature algorithm. You must use the
// same parameter when you invoke the method sign on the token. The default value is SHA256 parameters.setDigestAlgorithm(DigestAlgorithm.SHA256);

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
InputStream in = new FileInputStream("certificate.der");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);

// We set the signing certificate
parameters.setSigningCertificate(new CertificateToken(cert));

// Create common certificate verifier
CommonCertificateVerifier commonCertificateVerifier = new CommonCertificateVerifier();

// Create XAdES service for signature
XAdESService service = new XAdESService(commonCertificateVerifier);

// Get the SignedInfo XML segment that need to be signed.
ToBeSigned dataToSign = service.getDataToSign(toSignDocument, parameters);

File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));

// We invoke the service to sign the document with the signature value obtained in
// the previous step.
DSSDocument signedDocument = service.signDocument(toSignDocument, parameters, signatureValue);

File signedFile = new File("output.xml");
signedFile.createNewFile();
signedDocument.writeTo(new FileOutputStream(signedFile, false));

That creates XAdES file, but when I try to validate the signature (e.g. using this) it fails saying the signature is not intact.

What am I doing wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

剩余の解释 2025-02-06 07:17:25

您不使用dataTosign完全用于签名值创建。

您应该做的是使用与创建证书相对应的专用密钥来实际签署消化的dataTosign。即,

File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));

您应该做这样的事情(使用上面的示例):

# calculate SHA256 of data
digest = session.digest(dataToSign, mechanism=Mechanism.SHA256)

for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
    private_key = obj

signatureValue = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)

请注意,您应签署原始文档,而是dataToSign,因为它包含对原始的引用文档(其摘要),但也签署了参数,以确保符合ADES格式。

我希望这对您有帮助。

此致,
Aleksandr。

You do not use dataToSign variable at all for signature value creation.

What you should do is by using the private key corresponding to the created certificate to actually sign the digested dataToSign. I.e., instead of:

File file = new File("signature");
SignatureValue signatureValue = new SignatureValue(SignatureAlgorithm.RSA_SHA256, Files.readAllBytes(file.toPath()));

you should do something like this (using your example above):

# calculate SHA256 of data
digest = session.digest(dataToSign, mechanism=Mechanism.SHA256)

for obj in session.get_objects({Attribute.CLASS: ObjectClass.PRIVATE_KEY}):
    private_key = obj

signatureValue = private_key.sign(digest, mechanism=Mechanism.RSA_PKCS)

Please pay attention, that you shall sign not the original document, but the dataToSign, as it contains the reference to the original document (its digest), but also signed parameters, required to ensure compliance to AdES format.

I hope this will help you.

Best regards,
Aleksandr.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文