[英]Signing PDF document by certificate
我正在嘗試使用 Syncfusion 對 PDF 文檔進行數字簽名。 (生成pdf文檔的庫)
整個文檔,而不僅僅是字段。 我對簽名或證書一無所知。
我知道證書是 HSM 的類型,所以我使用了: Syncfusion - Externally sign a pdf 文檔
它適用於我的開發 PC,但不適用於生產。 找到證書,但在簽署文件時會導致:
CryptographicException: Unknown error „-1073741823“ at System.Security.Cryptography.Pkcs.SignedCms.Sign(CmsSigner signer, Boolean silent)
我的代碼:
using Syncfusion.Licensing;
using Syncfusion.Pdf;
using Syncfusion.Pdf.Graphics;
using Syncfusion.Pdf.Parsing;
using Syncfusion.Pdf.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace SyncfusionTest3
{
class Program
{
public static X509Certificate2 infoCertifikat = null;
static void Main(string[] args)
{
var store = new System.Security.Cryptography.X509Certificates.X509Store(StoreLocation.LocalMachine);
string thumbprint = "9F.."; //Production
store.Open(OpenFlags.ReadOnly);
foreach (var mCert in store.Certificates)
{
if (mCert.Thumbprint.ToUpper().Equals(thumbprint.ToUpper()))
infoCertifikat = mCert;
}
if (infoCertifikat == null)
{
Console.WriteLine("404 Certificate not found");
Console.ReadKey();
return;
}
string licenceKey = "LicenceKey";
SyncfusionLicenseProvider.RegisterLicense(licenceKey);
using (var pdfDoc = new PdfLoadedDocument("document.pdf"))
{
pdfDoc.DocumentInformation.Creator = "Me";
pdfDoc.DocumentInformation.Author = "Naxi";
PdfCertificate pdfCertificate = new PdfCertificate(infoCertifikat);
//Normal signing
//Syncfusion.Pdf.Security.PdfSignature signature1 = new Syncfusion.Pdf.Security.PdfSignature(pdfDoc, pdfDoc.Pages[0], pdfCertificate, "DigitalSign");
//External signing becouse of HSM type of certificate
Syncfusion.Pdf.Security.PdfSignature signature1 = new Syncfusion.Pdf.Security.PdfSignature(pdfDoc, pdfDoc.Pages[0], null, "DigitalSign");
signature1.ComputeHash += Signature_ComputeHash1;
signature1.Bounds = new System.Drawing.RectangleF((6 * 25.4f / 0.352777778f), (9.3f * 25.4f / 0.352777778f), 65, 25);
signature1.ContactInfo = "Contact";
signature1.LocationInfo = "World";
signature1.Reason = "I want it";
PdfStandardFont font = new PdfStandardFont(PdfFontFamily.Helvetica, 3.8f);
float row_height = 4.2f;
signature1.Appearance.Normal.Graphics.DrawString("Digitally Signed by " + signature1.ContactInfo, font, PdfBrushes.Black, 0, row_height * 1);
signature1.Appearance.Normal.Graphics.DrawString("Reason: " + signature1.Reason, font, PdfBrushes.Black, 0, row_height * 2);
signature1.Appearance.Normal.Graphics.DrawString("Location: " + signature1.LocationInfo, font, PdfBrushes.Black, 0, row_height * 3);
signature1.Appearance.Normal.Graphics.DrawString((DateTime.Now).ToString(), font, PdfBrushes.Black, 0, row_height * 4);
pdfDoc.Save("document_signed.pdf");
pdfDoc.Close(true);
}
}
private static void Signature_ComputeHash1(object sender, PdfSignatureEventArgs ars)
{
//Get the document bytes
byte[] documentBytes = ars.Data;
SignedCms signedCms = new SignedCms(new ContentInfo(documentBytes), detached: true);
var cmsSigner = new CmsSigner(infoCertifikat);
//Set the digest algorithm SHA256
//cmsSigner.DigestAlgorithm = new Oid("1.3.6.1.4.1.311.10.3.12"); //Document signing – just tried
//cmsSigner.DigestAlgorithm = new Oid("1.2.840.113549.1.1.11"); //SHA256RSA
//cmsSigner.DigestAlgorithm = new Oid("1.2.840.113549.1.1.5"); //SHA1RSA
//cmsSigner.DigestAlgorithm = new Oid("1.3.14.3.2.26"); //SHA1
cmsSigner.DigestAlgorithm = new Oid("2.16.840.1.101.3.4.2.1"); //SHA256
cmsSigner.IncludeOption = X509IncludeOption.EndCertOnly; //Without this it throws CryptographicException: A certificate chain could not be bulit to a trusted root authority. (only in production)
signedCms.ComputeSignature(cmsSigner);
//Embed the encoded digital signature to the PDF document
ars.SignedData = signedCms.Encode();
}
}
}
我嘗試使用不同的 DigestAlgorithm。 (在代碼中注釋)但我不知道我應該使用哪個。
我為 Platform target x64 構建它,因為沒有它會導致:
CryptographicException: The keyset is not defined. at System.Security.Cryptography.Pkcs.PkcsUtils.CreateSignerEncodeInfo(CmsSigner signer, Boolean silent, DafeCryptoProvHandle)
生產中使用了經過審查的證書:
我的開發證書有密鑰用法:簽名文檔,生產中缺少。 或者增強的密鑰用法缺少什么?
感謝您的任何建議。
更新:所以,我以不同的幾種方式做了我的小步驟,看起來很有希望,但不是mutch。
Syncfusion.Pdf.Security.PdfSignature signature1 = new Syncfusion.Pdf.Security.PdfSignature(pdfDoc, pdfDoc.Pages[0], pdfCertificate, "DigitalSign");
signature1.Settings.CryptographicStandard = CryptographicStandard.CADES;
它制作簽名文件並使程序崩潰。 喜歡無一例外。
所以,我嘗試以外部方式使用 oid:
cmsSigner.DigestAlgorithm = new Oid("1, 3, 36, 3, 3, 1, 1"); //RSA + SHA1
這會導致: CryptographicsException:object 標識符格式不正確。 在 SignedCms.Sign(...)
我不知道我在做什么。
更新 2:
所以,正確的方法可能是使用外部的 SHA1。 簽名文件有效,但是當程序結束時,程序不會像往常一樣關閉,而是停止工作。 微軟應用程序 certutil 也是如此。 列出證書后,它停止工作。
這是關於該證書的新信息。 它在 Luna 提供的 HSM 中。
================ Certificate 0 ================
Serial Number: ...
Issuer: ...
NotBefore: ...
NotAfter: ...
Subject: ...
Non-root Certificate
Cert Hash(sha1): 9f
Key Container = ...
Provider = Luna enhanced RSA and AES provider for Microsoft Windows
Private key is NOT exportable
ERROR: Could not verify certificate public key against private key
Revocation check skipped -- server offline
Certificate is valid
確保證書安裝在正確的商店中(您的代碼顯示StoreLocation.LocalMachine
)。 所以我們先檢查一下store中的證書是否正常,key是否關聯且可訪問。
運行以下命令以列出並驗證存儲中的所有證書:
certutil -verifystore MY
output 應該顯示如下:
================ Certificate X ================
Serial Number: ...
Issuer: ...
NotBefore: ...
NotAfter: ...
Subject: ...
Non-root Certificate
Cert Hash(sha1): ...
Key Container = ...
Unique container name: ...
Provider = ...
Private key is NOT exportable
Signature test passed
...
這將向您顯示私鑰關聯及其提供者,並將創建簽名以檢查密鑰是否可訪問。
因此,請確保為運行命令的用戶以及您的應用程序授予訪問密鑰的權限。 您可能需要通過閱讀 HSM 用戶手冊或聯系負責人(內部或制造商支持)來澄清這一點
您的SignedCms
代碼看起來不錯 - 對於測試,請使其盡可能簡單(無摘要算法)並小步前進。
編輯
此外,當然,您需要讓您的證書受信任。 這意味着證書信任鏈已安裝到證書存儲區。
證書可以在這里找到: http://crt.postsignum.cz/certifikaty_autorit.html
certlm.msc
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.