Ein Windows-Programm zu signieren bedeutete bisher immer eine Windows-Maschine. signtool läuft nur unter Windows, sodass eine Build-Pipeline, die unter Linux kompiliert, trotzdem irgendwo einen Windows-Host braucht, nur um am Ende eine Signatur auf die Datei zu setzen.
Ab sgcSign 2026.10 ist dieser Host optional. Das Authenticode-Format in sgcSign, das die PE-Datei hasht und die Signatur aufbaut, ist jetzt Delphi-Code statt eines Aufrufs der Windows-Signier-APIs. Unter Windows läuft die eigentliche Schlüsseloperation weiterhin über CNG, und überall sonst läuft sie in der eigenen Kryptografie von sgcSign, sodass die Komponenten, die eine EXE unter Windows signieren, auch unter Linux 64-Bit kompilieren und laufen, und Windows akzeptiert die von ihnen erzeugte Datei wie jede andere signierte Datei. Dieser Beitrag zeigt ein kurzes Konsolenprogramm, das genau das tut, wie man es für Linux baut und wie man das Ergebnis prüft.
Das Delphi-Programm signiert eine EXE unter Ubuntu, dann wird dieselbe Datei unter Windows geprüft. Auch auf YouTube.
Warum überhaupt unter Linux signieren
- Build-Agenten. Gehostete CI-Runner und Build-Container sind in erster Linie Linux. Wer auf demselben Agenten signiert, der die Datei gebaut hat, spart den Sprung zu einer Windows-Maschine und die Zugangsdaten, die dieser Sprung braucht.
- Wo der Schlüssel liegt. Ein Code-Signing-Schlüssel gehört in ein HSM oder einen Cloud-Schlüsseltresor, und beide erreicht man von Linux aus genauso einfach. Die PKCS#11- und Cloud-Schlüsselanbieter in sgcSign funktionieren auf jeder Plattform.
- Ein Werkzeug überall. Dasselbe Delphi-Programm signiert auf der Windows-Maschine eines Entwicklers und auf dem Release-Server, mit denselben Optionen und derselben Ausgabe.
Das Programm
Ein Konsolenprogramm, das die zu signierende Datei, die Ausgabedatei, eine PFX mit ihrem Passwort und optional eine Zeitstempelstelle entgegennimmt. Es ist derselbe Code unter Windows und unter Linux.
program SignExe;
{$APPTYPE CONSOLE}
uses
SysUtils, sgcSign_Authenticode, sgcSign_KeyProvider_PFX, sgcSign_TSA;
var
PFX: TsgcPFXKeyProvider;
TSA: TsgcTSAClient;
Signer: TsgcAuthenticodeSigner;
begin
if ParamCount < 4 then
begin
Writeln('usage: SignExe <input.exe> <output.exe> <file.pfx> <password> [tsa-url]');
Halt(1);
end;
PFX := TsgcPFXKeyProvider.Create(nil);
TSA := TsgcTSAClient.Create(nil);
Signer := TsgcAuthenticodeSigner.Create(nil);
try
try
PFX.LoadFromFile(ParamStr(3), ParamStr(4));
Signer.KeyProvider := PFX;
Signer.Hash := ahSHA256;
Signer.Level := alBES;
Signer.Description := 'sgcSign demo';
if ParamCount >= 5 then
begin
TSA.URL := ParamStr(5);
Signer.TSAClient := TSA;
Signer.Level := alT;
end;
Signer.SignFile(ParamStr(1), ParamStr(2));
Writeln('Signer: ', PFX.Certificate.Subject);
Writeln('Signed: ', ParamStr(2));
except
on E: Exception do
begin
Writeln('Error: ', E.Message);
ExitCode := 1;
end;
end;
finally
Signer.Free;
TSA.Free;
PFX.Free;
end;
end.
TsgcPFXKeyProvider hält das Zertifikat und den privaten Schlüssel. TsgcAuthenticodeSigner hasht die PE-Datei so, wie es Windows tut, baut die PKCS#7-Signatur auf und schreibt sie in die Zertifikatstabelle der Datei. Ist ein TsgcTSAClient angehängt, holt er zusätzlich einen RFC-3161-Zeitstempel, damit die Signatur auch nach Ablauf des Zertifikats gültig bleibt.
Für Linux 64-Bit bauen
Im Fenster Projects fügen Sie Linux 64-bit als Zielplattform hinzu, mit einem im SDK Manager eingerichteten Linux-SDK, und bauen Sie dann. Die sgcSign-Runtime-Pakete werden ab Delphi 10.3 für Linux64 gebaut. Unter Linux wird die PFX in reinem Pascal geparst, da es keinen Windows-Zertifikatspeicher zum Importieren gibt, und die RSA- oder ECDSA-Operation läuft in der eigenen Kryptografie von sgcSign. Das Signaturformat drum herum wird vom selben Code aufgebaut, der auch unter Windows läuft.
Ausführen und Ergebnis prüfen
$ file Hello.exe
PE32+ executable (console) x86-64, for MS Windows
$ ./SignExe Hello.exe Hello-signed-linux.exe ../certs/demo.pfx demo http://timestamp.digicert.com
Signer: O=eSeGeCe Demo, CN=sgcSign Demo Code Signing
Signed: Hello-signed-linux.exe
Um es ohne Windows zu prüfen, berechnet osslsigncode verify den Digest der Datei neu und prüft die Signatur darüber: Signature verification: ok.
Anschließend kopieren Sie die Datei nach Windows. PowerShell und signtool verify /pa /v lesen dieselbe Signatur: Der von Windows berechnete Datei-Hash stimmt mit dem signierten überein, der Signierer ist das Demo-Zertifikat, und der DigiCert-Zeitstempel wird verifiziert. Die Datei läuft weiterhin.
PS> Get-AuthenticodeSignature .\Hello-signed-linux.exe | Format-List SignatureType,
@{n='Signer';e={$_.SignerCertificate.Subject}},
@{n='TimeStamper';e={$_.TimeStamperCertificate.Subject}}
SignatureType : Authenticode
Signer : CN=sgcSign Demo Code Signing, O=eSeGeCe Demo
TimeStamper : CN=DigiCert SHA256 RSA4096 Timestamp Responder 2026 1, O="DigiCert, Inc.", C=US
Die einzige Beanstandung von Windows betrifft das Demo-Zertifikat, nicht die Signatur. Die Demo-Kette endet in einer selbstsignierten Test-Root, die auf der Maschine nicht installiert ist, sodass Windows sie keiner vertrauenswürdigen Root zuordnen kann. Digest, Signatur und Zeitstempel werden alle verifiziert.
Dieselben Bytes unter Linux und unter Windows
Signieren Sie dieselbe Hello.exe mit derselben PFX und ohne Zeitstempel, einmal mit dem Linux-Build und einmal mit dem Windows-Build des obigen Programms, und vergleichen Sie die beiden Dateien:
Linux 82344 bytes SHA-256 6FD63BB01A8E911AB099431BC76F3BFA4EF557082BFB8BC18CCBFA97A9E8079D
Windows 82344 bytes SHA-256 6FD63BB01A8E911AB099431BC76F3BFA4EF557082BFB8BC18CCBFA97A9E8079D
Sie sind identisch, Byte für Byte. Eine RSA-Signatur dieser Art ist deterministisch, und der Signierer lässt die Signierzeit weg, sofern man sie nicht anfordert, sodass die Datei nur vom Schlüssel und der Eingabe abhängt, nicht von der Maschine, die signiert hat. Der Zeitstempel ist der einzige Teil, der sich von Lauf zu Lauf unterscheidet, weil die Zeitstempelstelle den Moment stempelt, in dem sie angefragt wird.
Woher der Schlüssel kommt
Unter Linux kann der Schlüssel aus einer PFX- oder PEM-Datei, von einem PKCS#11-Token oder HSM oder von einem Cloud-Signierdienst stammen: Azure Trusted Signing, AWS KMS, Google Cloud KMS, HashiCorp Vault oder ein CSC-Remote-Signierdienst. Der Windows-Zertifikatspeicher-Anbieter ist derjenige, der aus naheliegendem Grund Windows-exklusiv bleibt.
Nicht nur EXE
Dasselbe gilt für jede Code-Signing-Komponente in sgcSign: TsgcAuthenticodeSigner für EXE und DLL, TsgcCatalogSigner für .cat-Kataloge, TsgcMSISigner für .msi- und .msp-Dateien von Windows Installer, TsgcAppxSigner für .msix- und .appx-Pakete, TsgcPowerShellSigner für PowerShell-Skripte, und TsgcAuthenticodeVerifier, um jede davon zu prüfen. Alle bauen und laufen unter Linux, macOS, iOS und Android.
Auf dem Server und in der Kommandozeile
Das Gleiche gilt über die Bibliothek hinaus. Ein für Linux gebauter sgcSign Server signiert und prüft Authenticode-, PowerShell-, Katalog-, MSI- und MSIX-Anfragen genau wie unter Windows, und das Kommandozeilenwerkzeug sgcsign sendet sie von jeder Plattform aus. Ein Weg bleibt im Delphi-Kommandozeilenwerkzeug weiterhin Windows vorbehalten: eine EXE oder eine DLL lokal zu hashen und nur den Hash zu senden. Das .NET-Kommandozeilenwerkzeug nutzt diesen Weg auf jeder Plattform.
Verfügbarkeit
Code-Signing unter Linux, macOS, iOS und Android erscheint in sgcSign 2026.10 für Delphi. Für ein Windows-Programm ändert sich nichts: dieselben Komponenten, dieselben Eigenschaften und dieselbe Ausgabe. Jede Eigenschaft ist in der sgcSign-Online-Hilfe dokumentiert.
Fragen, oder eine Pipeline, die Sie von Windows weg verlagern wollen? Nehmen Sie Kontakt auf, und Sie erhalten eine Antwort von den Leuten, die den Code geschrieben haben.
