【问题标题】:XAdES creation with manual signature entry使用手动签名输入创建 XAdES
【发布时间】:2022-07-16 04:11:31
【问题描述】:

我正在尝试使用我的身份证上的签名创建一个数字签名的 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)

这会生成certificate.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)时,它会说签名不完整。

我做错了什么?

【问题讨论】:

    标签: digital-signature signature pkcs#11 xades


    【解决方案1】:

    您根本不使用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 格式。

    希望对你有帮助。

    最好的问候, 亚历山大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-08-23
      • 2022-07-16
      • 2022-06-24
      • 1970-01-01
      • 2015-11-05
      • 2020-02-18
      • 1970-01-01
      相关资源
      最近更新 更多