我试图创建一个数字签名的XML文件使用签名从我的ID卡。
我有两部分程序。第一个是从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)
生成证书. der
和签名
文件并且工作正常(至少我认为)
对于XML代部分,我使用欧洲的DSS库,Java如下:
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文件,但当我尝试验证签名(例如使用它)时,它失败了,说签名不完整。
我做错了什么?
您根本不使用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