Sign Your First Document in 5 Minutes
A complete walkthrough from a fresh VCL project to a signed XAdES envelope. Works with Delphi 7 through RAD Studio 13 and C++Builder.
A complete walkthrough from a fresh VCL project to a signed XAdES envelope. Works with Delphi 7 through RAD Studio 13 and C++Builder.
Two things only — sgcSign installed in the IDE, and a PFX certificate to sign with.
# No PFX yet? Generate a self-signed test cert with OpenSSL:
openssl req -x509 -newkey rsa:2048 \
-keyout key.pem -out cert.pem \
-days 365 -nodes \
-subj "/CN=sgcSign Test"
openssl pkcs12 -export \
-inkey key.pem -in cert.pem \
-out test.pfx \
-password pass:secret
# Now you have test.pfx with password "secret".
Spin up a VCL Forms application in your IDE. Drop two memos and a button on the form — that is the entire UI.
TMemo, paste your unsigned XML in here.
TMemo, signed XML appears here after the button click.
TButton, hooked to the OnClick handler in step 2.
object Form1: TForm1
Caption = 'sgcSign Quick Start'
ClientWidth = 800
ClientHeight = 600
object memoXML: TMemo
Left = 8
Top = 8
Width = 784
Height = 240
end
object memoSigned: TMemo
Left = 8
Top = 288
Width = 784
Height = 300
end
object btnSign: TButton
Left = 8
Top = 256
Caption = 'Sign XML'
end
end
Load a PFX provider, point a document signer at it with the VeriFactu profile, and call SignXML.
TsgcPFXKeyProvider imports the .pfx via Windows CNG — modern SHA-256 signing works regardless of the original CSP.
TsgcDocumentSigner picks the right XAdES level based on the profile.
spVeriFactu selects Spanish AEAT VeriFactu — XAdES-EPES, B-B, RSA-SHA256, exclusive C14N.
procedure TForm1.btnSignClick(Sender: TObject);
var
vKeyProvider: TsgcPFXKeyProvider;
vSigner: TsgcDocumentSigner;
begin
vKeyProvider := TsgcPFXKeyProvider.Create(nil);
try
vKeyProvider.FileName := 'certificate.pfx';
vKeyProvider.Password := 'secret';
vKeyProvider.LoadFromFile;
vSigner := TsgcDocumentSigner.Create(nil);
try
vSigner.KeyProvider := vKeyProvider;
vSigner.Profile := spVeriFactu;
memoSigned.Text := vSigner.SignXML(memoXML.Text);
finally
vSigner.Free;
end;
finally
vKeyProvider.Free;
end;
end;
__finally block ensures the providers are released even if signing throws.
UnicodeString is used end-to-end — no ANSI/UTF-8 conversion to worry about.
void __fastcall TForm1::btnSignClick(TObject *Sender)
{
TsgcPFXKeyProvider *vKeyProvider = new TsgcPFXKeyProvider(NULL);
try {
vKeyProvider->FileName = "certificate.pfx";
vKeyProvider->Password = "secret";
vKeyProvider->LoadFromFile();
TsgcDocumentSigner *vSigner = new TsgcDocumentSigner(NULL);
try {
vSigner->KeyProvider = vKeyProvider;
vSigner->Profile = spVeriFactu;
memoSigned->Text = vSigner->SignXML(memoXML->Text);
} __finally {
delete vSigner;
}
} __finally {
delete vKeyProvider;
}
}
Two units in your uses clause — the PFX provider and the document signer.
uses clauseEach key provider lives in its own unit so you only pay for what you reference. sgcSign_DocumentSigner brings in the routing layer that picks XAdES, PAdES, or CAdES based on the input.
uses
Classes, SysUtils, Forms, StdCtrls, Controls,
// sgc
sgcSign_KeyProvider_PFX,
sgcSign_DocumentSigner;
Same units, exposed as .hpp headers. The C++ Builder linker resolves the underlying static libraries automatically.
#include "sgcSign_KeyProvider_PFX.hpp"
#include "sgcSign_DocumentSigner.hpp"
Press F9, paste an invoice into the top memo, click Sign XML. The signed envelope appears in the bottom memo.
Press F9 in the IDE. The form opens with two memos and a button. No exceptions, no missing units.
Drop any invoice XML (or any well-formed XML at all) into memoXML. The signer normalises it to UTF-8 internally.
memoSigned now contains your XML with an enveloped <ds:Signature> element appended. Save it, run it through any XAdES verifier — or use TsgcSignatureVerifier directly.
On Delphi 7, string is AnsiString. Use the WideString overloads to round-trip Polish, Cyrillic, or Greek characters losslessly.
On Delphi 7 the string overload routes through the system ACP. Diacritics in 'Jarosław' only round-trip when the system ACP is CP1250. If the ACP is CP1252, characters get corrupted in the signed XML.
The WideString overloads bypass ACP entirely — UTF-16 to UTF-8 via WideCharToMultiByte with CP_UTF8. On Delphi 2009+ both overloads are equivalent; UnicodeString is already UTF-16.
var
Doc: IXMLDocument; // MSXML6
XML, Signed: WideString; // = MSXML6 DOMString
Sign: TsgcXAdESSigner;
begin
Doc.SaveToXML(XML); // WideString out, no ACP step
Signed := Sign.SignXML(XML); // resolves to WideString overload
// Polish, Cyrillic, Greek round-trip losslessly
end;
All X.509 / CRL / OCSP / TSA timestamps are stored as UTC TDateTime values, matching the underlying ASN.1 specs.
For end-user displays, use the *Local properties on each component (e.g. vCert.NotAfterLocal) or convert manually with sgcUTCToLocal from unit sgcSign_Time.
This matches RFC 5280 (X.509), RFC 3161 (TSA), and RFC 6960 (OCSP) which all specify UTC. The sgcUTCNow helper returns the current UTC TDateTime for code that needs to compare timestamps.
uses sgcSign_Time;
// Display certificate validity in local time
Memo1.Lines.Add('Cert expires: ' +
DateTimeToStr(vCert.NotAfterLocal));
Memo1.Lines.Add('Now (UTC): ' +
DateTimeToStr(sgcUTCNow));
// Or convert manually
vLocal := sgcUTCToLocal(vCert.NotAfter);
XAdES is just the start. PAdES, CAdES, profiles, key providers, and the centralised server are all one click away.
Tour the full XAdES, PAdES, CAdES API surface and the supporting timestamp + OCSP infrastructure.
Read more →VeriFactu, FatturaPA, KSeF, FACTUR-X, plus 9 EU employment-contract profiles. One-line jurisdiction switching.
Read more →PFX, PEM, Windows store, PKCS#11, Azure Trusted Signing, AWS KMS, Google KMS, Vault, Certum, CSC v2.
Read more →Centralise signing across the build farm. REST API, web admin, GitHub Actions, Azure DevOps, Jenkins, Docker.
Read more →