Onderteken je eerste document in 5 minuten

Een volledige walkthrough van een vers VCL-project naar een ondertekende XAdES-envelope. Werkt met Delphi 7 tot en met RAD Studio 13 en C++Builder.

Delphi 7 – RAD Studio 13
C++ Builder
VeriFactu-profiel

Voordat je begint

Slechts twee dingen — sgcSign geïnstalleerd in de IDE en een PFX-certificaat om mee te ondertekenen.

Wat je nodig hebt

  • sgcSign geïnstalleerd in je IDE — zie de downloadpagina.
  • Een PFX-certificaatbestand met het bijbehorende wachtwoord (elk X.509 PKCS#12-bestand werkt).
  • Delphi 7 tot en met RAD Studio 13 of elke versie van C++ Builder. Zowel 32-bits als 64-bits Windows worden ondersteund.
  • Geen externe afhankelijkheden — sgcSign gebruikt Windows CNG/BCrypt voor cryptografie en WinHTTP voor netwerkaanroepen.
make-test-cert.sh
# Nog geen PFX? Genereer een self-signed test-cert met 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

# Nu heb je test.pfx met wachtwoord "secret".

Maak een nieuw project

Start een VCL Forms-applicatie in je IDE. Plaats twee memos en een knop op het form — dat is de volledige UI.

Form-layout

  • memoXMLTMemo, plak hier je niet-ondertekende XML.
  • memoSignedTMemo, hier verschijnt de ondertekende XML na de klik op de knop.
  • btnSignTButton, gekoppeld aan de OnClick-handler in stap 2.
  • Geen design-time-componenten nodig — alles wordt in code aangemaakt.
Unit1.dfm
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

Voeg de ondertekencode toe

Laad een PFX-provider, koppel er een document-signer aan met het VeriFactu-profiel en roep SignXML aan.

Delphi

  • TsgcPFXKeyProvider importeert de .pfx via Windows CNG — moderne SHA-256-ondertekening werkt ongeacht de oorspronkelijke CSP.
  • TsgcDocumentSigner kiest het juiste XAdES-niveau op basis van het profiel.
  • spVeriFactu selecteert het Spaanse AEAT VeriFactu — XAdES-EPES, B-B, RSA-SHA256, exclusieve C14N.
  • Vervang de constante door een van de 21 landprofielen — zie Landprofielen.
Unit1.pas
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;

C++ Builder

  • Zelfde vorm, zelfde klassen, zelfde property-namen — de C++-wrapper is een 1-op-1-port van de Delphi-API.
  • Het __finally-blok zorgt ervoor dat de providers worden vrijgegeven, zelfs als de ondertekening een fout geeft.
  • UnicodeString wordt end-to-end gebruikt — geen zorgen over ANSI/UTF-8-conversie.
Unit1.cpp
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;
  }
}

Voeg de vereiste units toe

Twee units in je uses-clausule — de PFX-provider en de document-signer.

Delphi uses-clausule

Elke sleutelprovider staat in zijn eigen unit, zodat je alleen betaalt voor wat je gebruikt. sgcSign_DocumentSigner brengt de routerings-laag mee die XAdES, PAdES of CAdES kiest op basis van de invoer.

Unit1.pas
uses
  Classes, SysUtils, Forms, StdCtrls, Controls,
  // sgc
  sgcSign_KeyProvider_PFX,
  sgcSign_DocumentSigner;

C++ Builder-includes

Dezelfde units, beschikbaar als .hpp-headers. De C++ Builder-linker lost de onderliggende statische bibliotheken automatisch op.

Unit1.cpp
#include "sgcSign_KeyProvider_PFX.hpp"
#include "sgcSign_DocumentSigner.hpp"

Uitvoeren en testen

Druk op F9, plak een factuur in de bovenste memo en klik op Sign XML. De ondertekende envelope verschijnt in de onderste memo.

Compileren en uitvoeren

Druk in de IDE op F9. Het form opent met twee memos en een knop. Geen excepties, geen ontbrekende units.

Plak de invoer

Plak een willekeurige factuur-XML (of welke well-formed XML dan ook) in memoXML. De signer normaliseert die intern naar UTF-8.

Controleer het resultaat

memoSigned bevat nu je XML met een toegevoegd enveloped <ds:Signature>-element. Sla het op, haal het door een willekeurige XAdES-verifier — of gebruik direct TsgcSignatureVerifier.

Unicode en de WideString-overload

Op Delphi 7 is string gelijk aan AnsiString. Gebruik de WideString-overloads om Poolse, cyrillische of Griekse tekens verliesvrij heen en weer te krijgen.

De valkuil

Op Delphi 7 routeert de string-overload via de system-ACP. Diakrieten in 'Jarosław' overleven alleen heen en weer als de system-ACP CP1250 is. Als de ACP CP1252 is, raken tekens beschadigd in de ondertekende XML.

De WideString-overloads omzeilen de ACP volledig — UTF-16 naar UTF-8 via WideCharToMultiByte met CP_UTF8. Op Delphi 2009+ zijn beide overloads gelijkwaardig; UnicodeString is al UTF-16.

d7-unicode.pas
var
  Doc: IXMLDocument;       // MSXML6
  XML, Signed: WideString; // = MSXML6 DOMString
  Sign: TsgcXAdESSigner;
begin
  Doc.SaveToXML(XML);            // WideString uitvoer, geen ACP-stap
  Signed := Sign.SignXML(XML);   // kiest de WideString-overload
  // Pools, cyrillisch, Grieks verliesvrij heen en weer
end;

Standaard UTC

Alle X.509-/CRL-/OCSP-/TSA-tijdstempels worden opgeslagen als UTC-TDateTime-waarden, in lijn met de onderliggende ASN.1-specificaties.

Weergeven in lokale tijd

Gebruik voor weergave aan eindgebruikers de *Local-properties op elk component (bijvoorbeeld vCert.NotAfterLocal) of converteer handmatig met sgcUTCToLocal uit unit sgcSign_Time.

Dit komt overeen met RFC 5280 (X.509), RFC 3161 (TSA) en RFC 6960 (OCSP), die allemaal UTC specificeren. De sgcUTCNow-helper geeft de huidige UTC-TDateTime terug voor code die tijdstempels moet vergelijken.

time-zones.pas
uses sgcSign_Time;

// Certificaatgeldigheid weergeven in lokale tijd
Memo1.Lines.Add('Cert verloopt: ' +
                DateTimeToStr(vCert.NotAfterLocal));
Memo1.Lines.Add('Nu (UTC):     ' +
                DateTimeToStr(sgcUTCNow));

// Of handmatig converteren
vLocal := sgcUTCToLocal(vCert.NotAfter);

Hoe je verder gaat

XAdES is pas het begin. PAdES, CAdES, profielen, sleutelproviders en de centrale server staan allemaal op één klik afstand.

Functieoverzicht

Bekijk het volledige XAdES-, PAdES- en CAdES-API-oppervlak en de bijbehorende tijdstempel- en OCSP-infrastructuur.

Lees meer →

21 landprofielen

VeriFactu, FatturaPA, KSeF, FACTUR-X plus 9 EU-arbeidscontractprofielen. Wissel van jurisdictie met één regel code.

Lees meer →

10 sleutelproviders

PFX, PEM, Windows-store, PKCS#11, Azure Trusted Signing, AWS KMS, Google KMS, Vault, Certum, CSC v2.

Lees meer →

sgcSign Server

Centraliseer ondertekening over je build-farm. REST-API, webadmin, GitHub Actions, Azure DevOps, Jenkins, Docker.

Lees meer →

Klaar voor productie?

Download de proefversie, lever vandaag nog een ondertekende binary en licentieer sgcSign zodra je tevreden bent.