距首次发布仅一个月,sgcSign 2026.5 带来了对该库的一次重大扩展。本次发布新增了面向 Windows 二进制文件的 Microsoft Authenticode 签名、三款新的代码分发签名器(ClickOnce、NuGet、VSIX)、完整的欧盟 eIDAS 合规套件(ASiC 容器、LOTL / EUTL 信任列表、云签名联盟远程签名)、九个预调优的国家雇佣配置文件、一个保加利亚 Peppol BIS Billing 3.0 配置文件、一个原生 QR Code 生成器、ECDSA P-256/384/521 加上 RSA-PSS 支持、完整的 CI/CD 集成,以及一系列广泛的 XAdES / PFX 合规修复。
本文介绍主要亮点,并为每个新组件提供即取即用的 Delphi 代码片段。
Microsoft Authenticode
TsgcAuthenticodeSigner 按照 Authenticode 规范对 Windows 可移植可执行文件(.exe、.dll、.sys)进行签名。签名器解析 PE,使用 Authenticode 算法(跳过校验和与已有的证书表)对其进行哈希,构建带有 SPC 间接数据内容的完整 PKCS#7 SignedData 数据块,并将其追加到二进制文件的证书表中。
支持从 SHA-1 到 SHA-512 的哈希算法,RFC 3161 时间戳作为未签名属性嵌入,而 AppendSignature := True 会生成嵌套签名(例如 SHA-1 + SHA-256 双重签名以保证旧版 Windows 的兼容性)。
uses
sgcSign_Authenticode, sgcSign_KeyProvider_PFX, sgcSign_TSAClient;
var
oSigner: TsgcAuthenticodeSigner;
oPFX: TsgcPFXKeyProvider;
oTSA: TsgcTSAClient;
begin
oPFX := TsgcPFXKeyProvider.Create(nil);
oPFX.FileName := 'codesign.pfx';
oPFX.Password := 'secret';
oTSA := TsgcTSAClient.Create(nil);
oTSA.URL := 'http://timestamp.digicert.com';
oSigner := TsgcAuthenticodeSigner.Create(nil);
try
oSigner.KeyProvider := oPFX;
oSigner.TSAClient := oTSA;
oSigner.Hash := ahSHA256; // ahSHA1 / ahSHA256 / ahSHA384 / ahSHA512
oSigner.Level := alT; // alBES or alT (with timestamp)
oSigner.Description := 'My Application';
oSigner.URL := 'https://www.example.com';
oSigner.SignFile('MyApp.exe', 'MyApp-signed.exe');
finally
oSigner.Free; oTSA.Free; oPFX.Free;
end;
end;
验证过程是对称的。TsgcAuthenticodeVerifier.Verify 返回一个记录,其中包含验证结果、计算出的与嵌入的哈希值、签名者主题/颁发者,以及是否存在时间戳:
var
oVer: TsgcAuthenticodeVerifier;
oRes: TsgcAuthenticodeVerifyResult;
begin
oVer := TsgcAuthenticodeVerifier.Create(nil);
try
oRes := oVer.Verify('MyApp-signed.exe');
if oRes.Valid then
ShowMessage('Signed by ' + oRes.SubjectName)
else
ShowMessage('Invalid: ' + oRes.ErrorMessage);
finally
oVer.Free;
end;
end;
仅哈希 Authenticode 签名
大型 CI 工件(安装程序、运行时、驱动程序)使得将完整的 PE 上传到远程签名器变得很痛苦。新的仅哈希签名流程允许客户端在本地计算 Authenticode 哈希值,并仅将 32 字节的摘要发送到 sgcSign Server。服务器返回未附加的 PKCS#7 数据块,客户端再将其嵌回到二进制文件中 — 在带宽受限的代理上将数兆字节的上传量缩减到几 KB。
// Local: compute the hash with sgcSign_PE_Hasher, POST it to the server,
// receive the SignedData blob, then append it to the PE's certificate table.
var
oSigner: TsgcAuthenticodeSigner;
vHash, vPKCS7: TBytes;
begin
// vHash := ComputePEHash('MyApp.exe', haSHA256);
vPKCS7 := oSigner.SignHash(vHash, ahSHA256);
// EmbedPKCS7IntoPE('MyApp.exe', vPKCS7, 'MyApp-signed.exe');
end;
同样的操作可以通过服务器的 POST /api/v1/sign/authenticode/hash 端点、sgcsign sign --prehash CLI 标志以及 .NET SDK 上的 TsgcSignClient.SignAuthenticodeHashAsync 方法来调用。
ClickOnce、NuGet 与 VSIX 签名器
三款新签名器覆盖了 Microsoft 开发者分发生态系统。
TsgcClickOnceSigner 使用封套式 W3C XML-DSig 对 .application 部署清单和 .exe.manifest 应用清单进行签名,输出与 Microsoft mage.exe 一致。签名器使用证书的 issuerKeyHash 重写 publisherIdentity 节点。
uses sgcSign_ClickOnce;
var oCO: TsgcClickOnceSigner;
begin
oCO := TsgcClickOnceSigner.Create(nil);
try
oCO.KeyProvider := oPFX;
oCO.Hash := haSHA256;
oCO.PublisherName := 'My Company';
oCO.SignManifestFile('MyApp.application', 'MyApp-signed.application');
finally
oCO.Free;
end;
end;
TsgcNuGetSigner 对 .nupkg 作者包进行签名,生成一个 CMS/PKCS#7 SignedData 数据块(带签名证书 v2,承诺类型为 "proof of origin"),可选 RFC 3161 反签名。
uses sgcSign_NuGet;
var oNu: TsgcNuGetSigner;
begin
oNu := TsgcNuGetSigner.Create(nil);
try
oNu.KeyProvider := oPFX;
oNu.TSAClient := oTSA;
oNu.Hash := haSHA256;
oNu.SignPackageFile('MyLib.1.0.0.nupkg', 'MyLib.1.0.0.signed.nupkg');
finally
oNu.Free;
end;
end;
TsgcVSIXSigner 为 Visual Studio 扩展实现了 OPC(开放打包约定)数字签名,计算每个 part 的 XML-DSig 引用并重写 [Content_Types].xml 与包的 _rels/.rels。
uses sgcSign_VSIX;
var oVX: TsgcVSIXSigner;
begin
oVX := TsgcVSIXSigner.Create(nil);
try
oVX.KeyProvider := oPFX;
oVX.Hash := haSHA256;
oVX.SignPackageFile('MyExt.vsix', 'MyExt-signed.vsix');
finally
oVX.Free;
end;
end;
这三者都复用了与现有 XAdES / PAdES / CAdES 签名器相同的 IsgcKeyProvider 接口,因此为发票签名配置的 AWS KMS、Azure Trusted Signing 或 PKCS#11 令牌可以直接复用于二进制签名,无需额外的管道工作。
欧盟 eIDAS / 合规套件
本次发布引入了 eIDAS 套件 — 三个新单元,让 Delphi 应用能够根据官方欧盟信任框架验证签名,并生成长期归档容器。
ASiC 容器(ETSI EN 319 162-1)
sgcSign_ASiC 以 XAdES 和 CAdES 两种风格构建和解析 ASiC-S(单文档)与 ASiC-E(多文档)容器。输出是一个确定性的 ZIP,其中 mimetype 条目位于最前,签名放置在 META-INF/ 下。
uses sgcSign_ASiC;
var
oDocs: TsgcASiCDocumentArray;
vBytes: TBytes;
begin
SetLength(oDocs, 1);
oDocs[0].Name := 'invoice.xml';
oDocs[0].Data := TFile.ReadAllBytes('invoice.xml');
// aSignatureXML comes from TsgcXAdESSigner (detached signature over the doc)
vBytes := TsgcASiCContainer.BuildXAdES(apASiCE, oDocs, vXAdESSignature);
TFile.WriteAllBytes('invoice.asice', vBytes);
end;
LOTL / EUTL 信任列表
sgcSign_TrustList 下载欧盟可信列表清单(List of Trusted Lists),跟随每个成员国的信任列表指针,并解析每个 TSPService 条目。其结果是一个内存中的目录,包含 31 个成员国大约 3,600 项服务。IsQualifiedAtTime 查找方法可在给定的签名时间将任何证书归类为"由合格 TSP 颁发" — 这是根据 eIDAS 第 25 条将签名从高级(AdES)升级到合格(QES)所需的操作。
云签名联盟(CSC v2)
TsgcCSCKeyProvider 是一个针对云签名联盟 API v2 的 IsgcKeyProvider 实现 — 这是 Buypass、Certinomis、Globalsign EU、InfoCert、Namirial、Trust Pro 等 QTSP 所使用的欧洲远程合格签名标准。该提供者处理 Basic / OAuth2 / OTP 认证,列出用户的凭证,获取证书链,并使用 SAD 授权执行仅哈希的远程签名。
uses sgcSign_KeyProvider_CSC, sgcSign_XAdES;
var oCSC: TsgcCSCKeyProvider; oX: TsgcXAdESSigner;
begin
oCSC := TsgcCSCKeyProvider.Create(nil);
oCSC.BaseURL := 'https://csc.example-qtsp.eu/csc/v2';
oCSC.AuthMethod := cscOAuth2;
oCSC.OAuthClientID := 'my-client-id';
oCSC.OAuthClientSecret := 'my-client-secret';
oCSC.CredentialID := oCSC.ListCredentials[0];
oCSC.PIN := '1234';
oCSC.OTP := '987654'; // pushed via SMS / app
oCSC.LoadCredentialInfo;
oX := TsgcXAdESSigner.Create(nil);
oX.KeyProvider := oCSC;
oX.Profile := spEIDAS;
oX.SignXML(vXML);
end;
九个雇佣配置文件
九个预调优的配置文件针对欧洲劳动法文档(雇佣合同、工资单、转岗协议):
| 配置文件 | 国家 | 等级 | C14N | TSA | OCSP |
|---|---|---|---|---|---|
spEmploymentDE | 德国 | B-LT | Exclusive | 是 | 是 |
spEmploymentIT | 意大利 | B-LT | C14N 1.0 | 是 | 是 |
spEmploymentES | 西班牙 | B-T | Exclusive | 是 | 否 |
spEmploymentFR | 法国 | B-T | Exclusive | 是 | 否 |
spEmploymentPL | 波兰 | B-T | Exclusive | 是 | 否 |
spEmploymentAT | 奥地利 | B-LT | Exclusive | 是 | 是 |
spEmploymentBE | 比利时 | B-LT | Exclusive | 是 | 是 |
spEmploymentPT | 葡萄牙 | B-LT | Exclusive | 是 | 是 |
spEmploymentNL | 荷兰 | B-T | Exclusive | 是 | 否 |
新的 EU_Employment 演示提供了完整的流水线(签名 → ASiC-E 打包 → LOTL 验证 → QTSP 分类)。
保加利亚 Peppol BIS Billing 3.0
新的 TsgcProfilePeppolBG 配置文件在 XAdES B-T 等级下以独占 C14N 对保加利亚 UBL 2.1 发票(BGN 货币、20% 增值税、BG VAT / EIK、BG IBAN、scheme ID 9926 端点)进行签名。Delphi 和 C++Builder 演示提供了一个填充完整的发票模板。
uses sgcSign_XAdES, sgcSign_Types;
var oSigner: TsgcXAdESSigner;
begin
oSigner := TsgcXAdESSigner.Create(nil);
try
oSigner.KeyProvider := oPFX;
oSigner.TSAClient := oTSA;
oSigner.Profile := spPeppolBG;
oSigner.SignXMLFile('invoice_bg.xml', 'invoice_bg_signed.xml');
finally
oSigner.Free;
end;
end;
CI/CD 集成
sgcSign Server 现在为每种常见的流水线提供一流的工件:
- GitHub Actions — 带仅哈希 Authenticode 签名的复合 Action。
- Azure DevOps — 集成安全文件的原生任务。
- Jenkins — 声明式流水线 DSL 加共享库。
- Docker — Windows Server Core 镜像加
docker-compose文件。 - Helm — 用于高可用 sgcSign Server 的 Kubernetes chart。
QR Code 生成器
对于 TicketBAI、VeriFactu 等需要在可打印发票上加入二维码的配置文件,新的 sgcSign_QRCode 单元提供了一个纯 Pascal 生成器,以字节模式实现 ISO/IEC 18004 — 涵盖全部四个 ECC 级别、版本 1 至 40、GF(256) Reed-Solomon、完整的掩码罚分评估 — 并配有 TBitmap 渲染器。无外部 DLL,无授权陷阱。
uses sgcSign_QRCode, Graphics;
var
oMatrix: TQRMatrix;
oBmp: TBitmap;
begin
oMatrix := GenerateQRCode(
'https://tbai.eus/QURL/123456789-A?cr=42',
qrECM);
oBmp := TBitmap.Create;
try
RenderQRMatrix(oMatrix, oBmp, 5, 4); // 5 px / module, 4-module border
oBmp.SaveToFile('invoice_qr.bmp');
finally
oBmp.Free;
end;
end;
ECDSA P-256 / P-384 / P-521 与 RSA-PSS
TsgcPEMKeyProvider 现在可以通过 Windows BCrypt CNG(ECCPRIVATEBLOB)导入 EC 私钥,并以适用于 XML-DSig 的原始 r||s 形式输出签名。新的 SignDataPSS 方法使用 BCRYPT_PAD_PSS 生成 RSA-PSS 签名(SHA-256,盐值 = 32 字节) — 越来越多的国家电子发票配置文件需要这种签名。
在验证端,TsgcSignatureVerifier 可从 BCRYPT_ECCPUBLIC_BLOB 导入 EC 公钥,并在 XAdES SignatureValue 和原始的 VerifyData 两条代码路径上验证这三条曲线的 ECDSA 签名。
为了实现这一点,TsgcX509Certificate 现在会解析 KeyUsage 扩展,并通过 KeyUsage 属性以及 HasKeyUsageDigitalSignature / HasKeyUsageNonRepudiation 辅助方法将其公开;新的 PublicKeyParameters 属性公开原始的 AlgorithmIdentifier 参数 TLV(EC 证书的命名曲线 OID)。
面向 Delphi 7 的 WideString 重载
对于传入非 ACP 文本的调用方(波兰 KSeF、希腊 myDATA、保加利亚 Peppol 等),公开的签名和验证 API 现在在 TsgcXAdESSigner.SignXML、SignXMLDetached、SignXMLEnveloping(以及 TsgcDocumentSigner 和 TsgcSignatureVerifier 上的相应方法)上提供了 WideString 重载。这保证了在 Delphi 7 上 Unicode 输入/输出的无损 — 无 ACP 往返 — 等同于 Delphi 2009+ 上的 string 重载。
合规性与可靠性修复
2026.5 的错误修复批次关闭了一长串针对实际税务机关端点发现的 XAdES / PFX / 验证器问题。
TsgcDocumentSigner现在能正确地为 AdES 配置文件生成 XAdES。在内部,它将sfXAdES路径委托给TsgcXAdESSigner,并对sfPAdES/sfCAdES抛出明确的错误(请使用专用签名器)。新的已发布的Format: TsgcSignatureFormat属性(默认sfXAdES)使选择显式化。先前版本无论配置文件如何都发出纯 XML-DSig,国家电子发票服务因此拒绝。TsgcPFXKeyProvider新增了已发布的HashAlgorithm属性(默认haSHA256),TsgcXAdESSigner现在会将活动配置文件的哈希推入 PFX 提供者。基于 PFX 的 FacturaeB2B 签名发票现在正确使用 RSA-SHA1,修复了 FACe INVALID_INVOICE-122 «los datos de la firma no son correctos» 拒绝错误。TsgcPFXKeyProvider现在支持现代 P12 文件:PKCS12_PREFER_CNG_KSP、多证书迭代探测、两阶段获取(先ONLY_NCRYPT再PREFER_NCRYPT)以及通过NCryptSignHash的 CNG 签名。- XAdES KSeF / ETSI 合规性 — V1
SigningCertificate包装、条件性SignaturePolicyIdentifier发出、十进制X509SerialNumber、单次构建SignedProperties(时钟竞争修复)、SignedProperties引用上的显式 exc-c14n 变换,以及新的SignatureParentElement属性。TsgcSignatureVerifier现在通过元素 Id 查找来解析URI=#<Id>。 - X.509 扩展解析 — v3
[3] EXPLICIT Extensions标签内容此前被双重包装,从而默默跳过了每张证书上的KeyUsage、ExtendedKeyUsage、AIA、CDP、SubjectAltName 与 BasicConstraints。已修复。 - 自闭合 XML 标签 —
ExtractFullElement现在能正确处理<ds:DigestMethod Algorithm="…/sha1"/>。先前版本默认为 SHA-256,破坏了 FacturaeB2B 验证并出现 "Digest length mismatch for Reference 0"。 - 包含式 C14N 回退 —
TsgcSignatureVerifier按照 XML-DSig §4.3.3.2 对省略显式变换的片段 / 空 URI 引用应用隐式包含式 C14N。修复了包含式 C14N 配置文件(FacturaeB2B)中 KeyInfo 和正文引用上的 "Digest value mismatch"。 - PEM 加固 — Unicode
ReadFileContent修复、两步 PKCS#8 解码、AT_KEYEXCHANGEkeyspec、GUID 后缀的 CSP 容器、通过 BCrypt 的原生加密 PKCS#8(PBES2 / PBKDF2 / AES-CBC)、LoadCertificateOnly以及 EC 标记识别。 - 设计期清理 — 所有九个签名器 / 验证器组件现在通过
Notification(opRemove)自动清除关联引用,消除了当密钥提供者或 TSA 客户端从窗体中删除时的悬空指针。 - 构建卫生 —
sgcSign_ASiC中的 W1000(UTF8Decode)通过{$IFDEF UNICODE} UTF8ToString回退已修复;sgcSign_XAdES和sgcSign_TrustList中的 H2077 / H2219 死代码警告已清理。
升级
对于现有的 2026.4 项目,2026.5 是即插即用的升级。需要注意的唯一行为变化是 TsgcDocumentSigner:依赖它为 AdES 配置文件发出纯 XML-DSig 的代码现在将正确生成 XAdES — 这正是税务机关所要求的,但如果您的集成测试固定到了旧的输出,则需要刷新黄金文件。
拥有有效订阅的客户可以从客户区域下载新版本。试用用户可以在 esegece.com/products/sgcsign/sgcsign-download 获取更新的安装程序。
有问题、反馈或迁移帮助?联系我们 — 您会收到编写代码的人的回复。
