sgcSign release notes

Every public release of sgcSign, newest first. Each version lists what was added, what was fixed and anything that changes behaviour, exactly as it is written in the history file that ships with the product.

sgcSign product page · Download

sgcSign 2026.10.0 Latest

  • 2026.10.0: 2026 October
  • NewCzech EET 2.0 support (Elektronicka evidence trzeb, the electronic registration of sales). A new TsgcEETClient component sends a registered sale to the Czech tax authority and reads the answer back: it signs the message with the taxpayer's certificate, checks the signature on the acknowledgement that comes back, and reports the acknowledgement code (pok) together with any warnings the tax authority raised. Verification mode lets a taxpayer confirm the connection works without reporting a sale, the message is checked in full and nothing is filed. The message can also be built and signed without being sent, so an offline queue can store it while the line is down and send it later, and a sale that was never acknowledged can be replayed as a repeat submission. Reporting starts on 1 January 2027 and the tax administration playground is open now, which is where the component points by default, so a first test can never file a real sale.
  • NewWindows Installer packages can now be signed. A new TsgcMSISigner component signs .msi and .msp files with SHA-1, SHA-256, SHA-384 or SHA-512, adds an RFC 3161 timestamp, and can add a second signature to a package that is already signed, exactly the way the Authenticode signer does for an exe or a dll. Requested by a customer, thank you.
  • NewMSIX and APPX packages can now be signed. A new TsgcAppxSigner component signs .msix, .appx and their bundles and writes the signature into the package as AppxSignature.p7x. Windows only accepts SHA-256 for a package, so that is the only digest offered, and signing a package that is already signed replaces the old signature. If the package does not yet declare the signature part, it is added for you. Requested by a customer, thank you.
  • NewThe Authenticode verifier now recognises what it was given and checks a Windows Installer package and an MSIX or APPX package as well as an exe or a dll. The call and the result are the same as before, so nothing changes for code that already verifies PE files.
  • NewSignature server: two new formats, msi and appx, reachable at /api/v1/sign/msi and /api/v1/sign/appx. Both take the whole file, the same way the catalog format does. The command line tool accepts them as --format msi and --format appx.
  • NewSignature server: an API key can now have a total call quota beside its per minute limit, daily quota and expiry. Only a call that passed every check is counted, so a call refused with 429 never uses up the quota, and concurrent calls can never go past it. A key that has used its quota is answered with 403 and the error quota_exhausted, without Retry-After, and it stays active. The admin console sets the quota when a key is created and edits it in the key list, shows the calls made against it, and a new Reset count action sets the count back to 0, so raising the quota or resetting the count lets the key work again at once.
  • NewWS-Security signatures, for any SOAP 1.1 service that asks for a signed message. The signature can now carry its certificate the way the standard expects, as a binary security token held in the message with the signature pointing at it, instead of repeating the certificate inside the signature itself. The verifier follows that pointer and picks the certificate out of the message, so a signature that arrives in that shape can now be checked as well as produced. A SOAP 1.1 envelope builder is included, so the body, the token and the signature end up where the standard puts them.
  • NewThe shared HTTP transport now hands back the response headers as well as the status code and the body, and a new helper reads a single header by name, matching the name case insensitively. It matters the moment a service puts something you need in a header and nowhere else: the Czech EET service returns a tracing identifier that its support desk asks for first, and until now there was no way to read one.
  • NewSignature server: a new EET route at /api/v1/sign/eet builds and signs a Czech registered sale with a key the server holds, and optionally posts it to the tax authority and returns what came back. A chain of point of sale terminals can therefore share one taxpayer certificate kept on the server, instead of every till holding a copy of it.
  • NewThe command line tool gained the matching eet verb, which reads the sale from a JSON file, has the server sign it, and with --submit sends it. The exit code says what happened, because a till script has to tell a refusal from a broken line: 6 means the tax authority rejected the sale, so it is not reported and has to be stored and sent again, 5 means the server could not sign it or could not reach the tax authority at all, and 4 means the sgcSign server itself could not be reached.
  • NewThe command line tool now has an exit code of its own for a request the server read and refused, 8, and for a request it rate limited, 9. Until now both ended up on the generic 1, which left a till script unable to tell a sale the tax authority called invalid, which must never be sent again, from one that failed because the line was busy, which must be. Code 8 covers HTTP 400, 404, 409, 413 and 415 and is never worth retrying, code 9 covers HTTP 429 and is worth retrying after a delay, which the tool now prints when the server says how long to wait. Read this as a change to the contract: a script that compares the exit code to exactly 1 stops matching an invalid request, and has to test for 8 and 9 as well. Codes 0 and 2 through 7 are untouched, and the health verb still reports anything other than a refused credential as unreachable.
  • NewEvery key provider now has a read only IsLoaded property, which is True once the call that loads its certificate and key has been made, so a program can check first instead of waiting for an exception. The Windows certificate store provider already had it, and its value there is unchanged.
  • NewSignature server: an installer or a package can now be signed without uploading it. Two new routes, /api/v1/sign/msi/hash and /api/v1/sign/appx/hash, take only the digest of the file and hand back the signature, so a large installer never crosses the network and the server never spends time reading it. On your side the package is prepared, hashed, and the signature that comes back is written into it, with sgcMSIPrepareForSigning, sgcMSIComputeHash and sgcMSIEmbedSignature for an installer, and sgcAppxPrepareForSigning, sgcAppxComputeDigestBlob and sgcAppxEmbedSignature for a package. Prepare first and hash what prepare gave you, because that is what the signature covers. The command line tool now works this way by default for --format msi and --format appx, the same as it already did for --format authenticode, and --upload sends the whole file instead. Requested by a customer, thank you.
  • NewSignature server: the hash routes now also return signer_subject, the subject of the certificate that signed. It lets a caller see which identity signed without holding the certificate, which matters for an MSIX or APPX package, where the publisher written in the package has to be exactly that subject and nothing else in this flow can check it.
  • NewThe QR code generator no longer needs the VCL, so it can be used on Linux, macOS, iOS and Android and in FireMonkey applications. RenderQRMatrix, which draws on a VCL TBitmap, is still there for Windows VCL projects and is left out of FireMonkey projects (Delphi 11 and later) and of any build that defines SGC_SIGN_NO_VCL.
  • NewsgcSign now builds and runs on Linux, macOS, iOS and Android as well as Windows. Signing a document, producing and checking a signature, reading and writing a PKCS#12 file, hashing and signing a PE file or a Windows Installer package, and talking to a timestamp authority, an OCSP responder or a cloud signing service are the same code on every platform, and the file that comes out is the same file. The runtime packages are built for Linux64 and macOS on Intel from Delphi 10.3, for Android and iOS from Delphi 10.4, and for macOS on Apple Silicon and the ARM iOS simulator from Delphi 11; the installer offers those platforms and adds the library path for each one. Delphi 10.2 has no Linux64 build because its Linux compiler has no AnsiString, which the library uses. Nothing changes on Windows: the same components, the same properties, the same bytes out, and Delphi 7 onwards builds exactly as it did.
  • NewCode signing no longer needs Windows. TsgcAuthenticodeSigner, TsgcCatalogSigner, TsgcMSISigner, TsgcAppxSigner and TsgcAuthenticodeVerifier build and run on Linux, macOS, iOS and Android as well, so an exe, a dll, a .cat catalog, an .msi, an .msp, an .msix and an .appx can be signed and checked on a build agent that is not a Windows machine. The file produced is the same file: everything these components do is the signature format itself, so the same key over the same input writes the same bytes on every platform, and Windows accepts a package signed on Linux exactly as it accepts one signed on Windows. Nothing changes for a Windows program, the API, the properties and the output are untouched. The key still has to come from somewhere the platform can reach, so the Windows certificate store provider stays Windows only while the PFX, PEM, PKCS#11 and cloud providers work everywhere. The signature server and the command line tool sign and verify these formats on every platform too.
  • NewTwo new key providers, for the keystore the platform already has. TsgcAppleKeychainProvider finds an identity in the macOS or iOS keychain by SHA-1 thumbprint, subject or label, lists what is there the way the Windows store and PKCS#11 providers do, resolves the issuing certificate from the keychain, imports a PKCS#12, and signs through the keychain so the private key never leaves it, with RSA and with ECDSA on P-256, P-384 and P-521. TsgcAndroidKeyStoreProvider does the same against AndroidKeyStore, selecting by alias, thumbprint or subject, taking the certificate chain from the store, and it can open the system credential chooser to let the user pick a key or the platform import screen to install a PKCS#12. Both are driven by the signers like any other provider, and both are inert on a platform that is not theirs. Be aware that the keychain and KeyStore calls themselves have not yet been run on a real Mac, iPhone or Android device, because there is none here to run them on; everything around them is covered by the test suite. Tell us what does not work and it will be fixed.
  • NewPKCS#12 files are read and written without Windows. A .pfx or .p12 is now parsed and produced by sgcSign itself: the MAC is verified before anything is decrypted, PBES2 with PBKDF2 and AES-128, AES-192, AES-256 or 3DES is supported together with the older pkcs-12 schemes, and RC4 and public key protected files are refused by name instead of failing obscurely. Files written by OpenSSL 1.1, OpenSSL 3 and Windows all load, and a file sgcSign writes opens in all three. TsgcPFXKeyProvider therefore loads a file, reports the key algorithm, signs data and digests with RSA and EC keys, resolves issuers inside the file and saves back to PFX on every platform. On Windows the certificate store and its key handles are still used, so nothing there changes.
  • NewThe crypto the library needs is now inside the library. On Windows it still runs through CNG and CryptoAPI exactly as before; everywhere else it runs on sgcSign's own pure Pascal implementation of SHA-1 and SHA-2, HMAC, PBKDF2, AES, 3DES, RC2, RSA with PKCS#1 v1.5, PSS and OAEP, and ECDSA on P-256, P-384 and P-521. Nothing is linked, nothing is downloaded and there is no OpenSSL to deploy with your application. The private key operations are written to take the same time whatever the secret is and to check their own result before returning it, so a signature is never emitted from a faulty computation.
  • NewHTTP requests work on every platform. On Windows the transport is still WinHTTP and behaves as it always did; elsewhere it is the RTL HTTP client, and the timestamp, OCSP, CRL, KSeF, EET and cloud provider calls all go through it with no change to your code. A client certificate can now be given as a PFX or PEM file with a password, which is how a platform with no Windows certificate store presents one, and an option the platform cannot honour is refused with a message that names it.
  • NewThe signing server runs on Linux. The Linux build is a foreground daemon that handles SIGTERM and SIGINT, flushes every line so journald sees it, and is installed as a systemd unit with the script that ships with it. It finds its data directory from XDG_DATA_HOME, then HOME/.local/share, then /var/lib/sgcsign, then the folder the executable is in, and it uses file locking for the single instance check. The Windows service is untouched. Authenticode, PowerShell, catalog, MSI and MSIX or APPX are signed and verified on a Linux server exactly as they are on Windows. A provider configured to use the Windows certificate store is refused when the server starts, with a message saying why.
  • NewThe Linux signing server now ships prebuilt. The release carries the Linux64 daemon and its systemd unit beside the Windows binaries, installed as apps\Linux64\sgcSignServer and apps\Linux64\sgcsignserver.service, so a Linux deployment no longer has to be compiled first.
  • NewEvery component now declares the platforms it runs on, so from Delphi 10.3 the Tool Palette offers a component only where sgcSign has a compiled unit for it. TsgcWindowsCertStoreProvider is offered on Windows only and TsgcPKCS11Provider everywhere except iOS, which has nowhere to load a PKCS#11 module from. Everything else is offered on every platform the runtime package is built for.
  • NewThe signing server and the command line tool sign and check PowerShell scripts. The server route /api/v1/sign/powershell signs a script and the verify route checks one, and both take the file name, which decides the comment style, and the code page for a file with no byte order mark. The answer says which style and which code page were used. The command line tool has the same through --format powershell and --codepage. Before this the route always failed, because it was handing the script to the signer for programs.
  • NewSignature server: API keys can now be created in bulk. The create form in the admin console takes a number of keys, up to 10000 at a time, all with the same project, expiry, rate limit and quotas, and they are created all together or not at all. The new keys come back once, as a CSV file download. The server keeps only a hash of each key, so the file can never be downloaded again. The API keys page now shows 100 keys per page and can be filtered by name or id. Requested by a customer, thank you.
  • NewSignature server: delegated administrators and child API keys. A new delegated_admin role can be put in charge of a top-level key and splits it into child keys for its own users, one at a time or in bulk. A child key always belongs to the project of its parent, cannot expire after it, and the total quotas of the children together can never exceed the total quota of the parent, which the calls made with the parent itself also draw on. A delegated administrator sees only its own keys and their children, cannot change the parent key, cannot reset a count and has no access to the rest of the console. Disabling the parent key stops every child key at once, and a key that still has children cannot be deleted. Requested by a customer, thank you.
  • NewPowerShell scripts can now be signed and checked, on every platform. A new TsgcPowerShellSigner signs a .ps1, .psm1, .psd1, .ps1xml, .psc1, .cdxml or .mof file the way Windows does it, writing the signature as the comment block at the end of the file, and TsgcAuthenticodeVerifier checks one. Windows accepts what the component produces, including a script signed on Linux, and reports a script that was altered afterwards as changed. Signing again replaces the old block instead of adding a second one. A script that has no byte order mark is read in the code page you choose, 1252 by default off Windows, so a plain text script gives the same signature on every machine. A script whose own text contains a signature marker line is refused with a message saying so, because Windows refuses it too.
  • NewSignature server: every admin console user can now change their own password, whatever their role. Until now only an admin could change a password, from the Users page. A new My account page, in the menu just above Logout, asks for the current password, the new password and its confirmation. The new password needs at least 8 characters and must differ from the current one, the change is written to the audit log, and every session of the account ends so the user signs in again with the new password. Available in every edition. Requested by a customer, thank you.
  • NewPAdES visible signature placement. VisibleSignature.Page is now honored, and a negative value counts from the end, so -1 always means the last page, whatever the page count. The new Pages property puts the same signature on several pages at once, either 'all' or a list such as '1,3,5-7,-1', which is how documents that need the signer's initials on every page are signed. It stays one signature, shown on each listed page. Requested by a customer, thank you.
  • NewPAdES visible signature anchoring. The new Anchor property places the stamp in a corner, at the center of an edge or in the middle of the page, with MarginX and MarginY as the distance from the edges (36 points by default). The position is worked out for each page, so the stamp lands in the same place on A4, A3 and landscape pages, and it stays upright on pages that are rotated. The default keeps the fixed Left, Bottom, Right and Top coordinates, as before.
  • NewPAdES: a PDF template that already has an empty signature field can now be signed into it. Set SignatureFieldName to the name of that field and the signature uses the field's own page and rectangle. When a field with that name is already signed, the new signature takes the next free name (Signature1 becomes Signature2) instead of creating a second field with the same name.
  • NewPAdES visible signature appearance. The new Text property is a template for the stamp, one line per entry, with {SIGNER}, {REASON}, {LOCATION}, {CONTACTINFO}, {DATE} and {ISSUER}, so the labels can be written in any language, accented characters included. A line whose values are all empty is left out. DateFormat sets how the date is written, and TimeZone can add the UTC offset (-03:00) or show the time in UTC. The date shown is exactly the signing time stored in the signature. Transparent draws the stamp with no background, so the page content under it stays visible, and WordWrap (on by default) wraps long lines inside the rectangle. Requested by a customer, thank you.
  • NewPAdES visible signature image and QR code. The stamp can show a JPEG or PNG image, such as a company logo or a handwritten signature (PNG transparency is kept), on the left, right, top or as a background. It can also show a QR code, for example pointing to the service where the signature is validated, drawn as vector graphics so it scans cleanly at any size. Leaving these properties empty keeps the stamp exactly as before.
  • NewSignature server: the API keys page now shows who created each key, with an Administrator or Delegated admin badge, and a Created by filter separates the keys created by administrators from those created by delegated administrators. Keys created before this version are shown as created by an administrator when they are top-level keys. Requested by a customer, thank you.
  • NewSignature server: two-factor sign-in for the admin console. A user turns it on from My account by adding the account to any authenticator app (TOTP), and from then on the console asks for a code from the app after the password. Ten recovery codes, shown only once, sign in when the phone is not at hand, and a new set can be issued at any time. An administrator can reset the second factor of a user who lost the device with Reset 2FA on the Users page. Setting admin.require_2fa to true (false by default) makes it compulsory: an account without it reaches only My account and Logout until it enrolls. Turning it on, turning it off, an administrator reset and every wrong code are written to the audit log and can be sent as webhooks.
  • NewSignature server: the admin console can now be signed in to with OpenID Connect, so users sign in with the identity provider the company already has, for example Microsoft Entra ID, Google, Okta or Keycloak, instead of a separate password. Any standard OpenID Connect provider works, several can be configured, and the sign in uses the authorization code flow with PKCE. A provider identity is linked to an existing console user, and with auto_link_by_email (false by default) it is linked by its verified email address at the first sign in. With allow_account_requests (false by default) a person who has no console account can ask for one, and an administrator approves or denies the request in the console. When the identity provider already asks for a second factor, skip_local_2fa (false by default) stops the console asking for its own code as well.
  • NewSignature server: the secrets in the configuration file are now encrypted at rest. Provider passwords and PINs, cloud credentials, webhook secrets, the TLS certificate password, the SMTP password, the backup passphrase and the OpenID Connect client secrets are stored as enc:v1: values, encrypted with a master key the server creates at the first start and binds to the machine, with DPAPI on Windows and a file only the service account may read on Linux. A stolen copy of the configuration file therefore reveals none of them, and the two-factor secrets in the database are protected with the same key. Secrets saved from the admin console are stored encrypted, and the new --protect-secrets switch encrypts the plain values already in an existing file, keeping the original as a .bak copy (--dry-run only lists them). A value that cannot be decrypted is never used: the provider stays unavailable, the webhook does not deliver and a TLS password stops the start, each with a message naming the setting and the master key file.
  • NewSignature server: the admin console is harder to attack. Every page is sent with security headers and a strict Content Security Policy, and a failed sign in shows the same message whether the username or the password was wrong, so it no longer tells anyone which accounts exist. The new admin.password_policy sets the rules for every console password (at least 8 and at most 128 characters by default, and optionally an upper case letter, a lower case letter, a digit and a symbol). A password set by an administrator, for a new user or on a reset, is temporary and has to be changed at the next sign in before anything else can be done. When the role or the projects of a user change, every session of that user ends, so the new rights apply at once.
  • NewSignature server: more control over the life of an API key. Regenerate gives a key a new secret on the same row, so its id, limits, project and child keys stay, and the old secret can keep working for 1 hour, 24 hours or 7 days while the consumers switch (by default it stops at once). The expiry of an existing key can now be set, extended, shortened or cleared, and the key list shows who owns each key. With api_keys.self_service (false by default) operators get a My API keys page where they create and manage their own keys, within the caps of api_keys.self_service_limits (5 keys, 60 calls per minute and 1000 calls per day by default). A key can also be limited to some of the providers of its project: a request that names another provider is refused with 403 provider_not_allowed, and /api/v1/keys lists only the providers the key may use.
  • NewSignature server: approvals are now enforced by the server. With approval_required set on a provider or on a project (false by default), every signature with that provider needs an approved request first, on every signing route, raw signing and signtool through the dlib included, and a signature asked for without one is answered with 403 approval_required. GET /api/v1/approvals/{id} reports the state of a request. An approval is single use: executing one that has already signed answers 409 approval_already_used, a request that has not been approved answers 409 approval_not_approved, and a signing attempt that fails does not use the approval up. The command line tool has a new approval verb to request, check and execute an approval, and sign --approval --wait asks for the approval, waits for it and then signs. Exit code 10 means the approval is still pending, and 11 means it was denied, has expired or was already used.
  • NewSignature server: default timestamp servers with fallback. The new timestamp block lists the servers used when a request does not name one (timestamp.servers, http://timestamp.digicert.com and http://timestamp.sectigo.com by default, 30 seconds each), and a provider can replace that list with its own tsa_urls. The servers are asked in order, and a server that fails or returns a token that does not check out moves on to the next one. A request can still give its own tsa_url, or send no_timestamp to sign without one. On the Authenticode, MSI, APPX, catalog and PowerShell routes level is now optional, and without it the server decides. Every failed server is written to the log and counted in the new sgcsign_tsa_failures_total metric, and the dashboard shows the list in use.
  • NewThe command line tool has a new timestamp verb. sgcsign timestamp adds an RFC 3161 timestamp to a file that is already signed, the way signtool timestamp does, for a program or a dll, an installer, a catalog or a PowerShell script. It talks to the timestamp server directly, so no sgcSign server and no API key are needed, and --tsa can be repeated to give fallbacks. The library has the same as the new TimestampSignature and TimestampBytes methods of the Authenticode signer.
  • NewSignature server: encrypted backups. The new backup block (off by default) writes an archive every 24 hours by default and keeps the 14 newest. Each archive holds the configuration, a consistent snapshot of the database, the master key and every key and certificate file the configuration refers to, all protected by a passphrase. The admin console has a Backup page with a Backup now button, and a failed backup is reported in the audit log, by webhook and by email. The new --archive switch creates, verifies, extracts and restores an archive from the command line. A restore on another machine seals the master key for that machine, so moving the server keeps the encrypted secrets and the two-factor enrollments working.
  • NewSignature server: email notifications. The new smtp block configures the mail server, and on Windows the connection uses the Windows TLS stack (SChannel) by default, so no OpenSSL DLLs are needed. The notifications block says who receives the emails and which ones are sent: security events such as account lockouts, two-factor changes and password changes, failed backups and certificate expiry warnings (all on by default). Each console user can have an email address, the emails are sent in the background so a slow mail server never holds up the console, and the new Email page has a Send test email button.
  • NewSignature server: certificate expiry monitoring. The server checks the certificates it holds when it starts and then once a day, and warns when one is 30, 14, 7 and 1 days from expiry (notifications.expiry_days), once for each threshold and certificate. Each warning is a cert.expiring webhook, an audit entry, a log line and, when email is configured, an email. The dashboard has a Certificates card, the providers page shows when each certificate expires, and the new sgcsign_certificate_not_after_seconds gauge lets a monitoring system raise its own alert.
  • NewPKCS#11: a guard against locking a token with a wrong PIN. After MaxPinAttempts incorrect PINs in a row (2 by default) the provider refuses every further login without sending it to the token until ResetPinGuard is called, so a wrong PIN in a configuration or a script can no longer use up the retries of a smart card or a USB token. The token flags are checked before every login, and when the token says the next wrong PIN locks it, the login is refused unless AllowFinalPinTry is True (False by default). Signature server: the same is set per provider with max_pin_attempts and allow_final_pin_try, the count is kept when the provider is rebuilt, and Reset PIN guard on the providers page clears it.
  • NewThe command line tool can now remember its settings. sgcsign config set, get, unset and list save the server and the other options in a profile, sgcsign auth set-key stores the API key (read from standard input when no key is given, so it stays out of the shell history), and --config-profile picks a profile other than the default one. The stored key is protected for the current user, with DPAPI on Windows and a file only that user can read on Linux and macOS. An option given on the command line still wins over the saved value, and the .NET tool reads the same profiles.
  • NewSignature server: a Windows installer. sgcSignServer_Setup.exe installs the server as a Windows service, asks for the password of the first administrator and for the port (8443 by default), opens that port in Windows Firewall, and offers three choices for TLS: a self-signed certificate generated on the spot (the default), an existing PFX file, or plain HTTP for an isolated test machine. The database and the other data go to ProgramData\eSeGeCe\sgcSign Server, which only SYSTEM and Administrators can open. It also runs silently, and it upgrades and uninstalls an existing installation. For a server installed without it, the new --init-admin switch creates the first administrator from an elevated command prompt.
  • NewAuthenticode page hashes, the same as signtool sign /ph. Turn on PageHashes and the signature also carries one hash for every 4 KB page of the file, so Windows can check each page as it loads it instead of the whole file, which kernel drivers need when Memory integrity is on (off by default). The result is byte for byte what signtool writes, for SHA-1, SHA-256, SHA-384 and SHA-512. Requested by a customer, thank you.
  • NewSignature server: page hashes on both Authenticode routes. The hash route takes the page hash table in a new page_hashes field, so a driver still never has to be uploaded, and the whole file route takes page_hashes=true. The command line tool adds them with --page-hashes, which also works with --append, --tsa-direct and --add-cert.
  • FixedA key provider that was never loaded now says so straight away. Asking the PFX, PEM, CSC, Azure Trusted Signing, Certum SimplySign or HashiCorp Vault provider for its certificate before the call that loads it used to hand back an empty certificate, which only failed much later, far from the missing line, and the Windows certificate store provider refused with a general error that named no call. All of them now raise EsgcSignKeyProviderNotLoaded, with a message naming the call to make, for example LoadFromFile, Connect or SelectCertificateBySubject. Certum SimplySign also raises it when asked to sign with no certificate selected, where it used to raise a general error. A provider that is configured and never used, such as one dropped on a form, behaves exactly as before.
  • FixedA PFX provider whose reload fails no longer carries on with the certificate it held before. A reload from a file that does not exist, or from empty data, used to leave the previous certificate loaded and still signing. A reload with a wrong password already refused to sign, but the Certificate property still showed the previous certificate, so a program displaying or logging it saw the wrong one. In both cases the provider is now left not loaded, with the previous certificate cleared. Certum SimplySign had the same problem when SelectCertificate failed: it kept the new certificate id, so it went on signing with that certificate's key while still returning the previous certificate, and a document could carry one certificate over a signature made by another. A failed selection now leaves no certificate selected, and a selection answered with a subject but no certificate no longer returns the previous certificate either.
  • FixedLoading a certificate from a PKCS#12 file could leave a copy of its private keys in the Windows key store. When Windows refused to keep the keys in memory, the load fell back to an import that writes them into the user profile, and nothing ever removed them. The keys are now kept in memory the same way the PFX provider keeps them, and anything that fallback writes is deleted before the load returns.
  • FixedThe command line tool now checks, when --cacert is given, that the server certificate was issued for the host name or IP address in --server. Until now any certificate that CA had issued was accepted for any server. Without --cacert, the trust store the indy transport finds on its own already checked a host name and now checks an IP address too. Upgrade note: a server whose certificate does not carry the address it is reached by is now refused, with --cacert, and on the default trust store when the server is given by IP address. A certificate refused over the indy transport now exits 7, the TLS error code, instead of 4.
  • FixedThe command line tool now follows a redirect only when it stays on the same scheme, host and port as the server. Any other redirect is refused before a request is sent there and exits 1, on every verb, health included, so the API key is never sent to another host. Until now both transports followed a redirect to any host and sent the API key along with it.
  • FixedThe command line tool now gives the right exit code for a response that carries nothing it can use. On the Authenticode route Windows uses by default, a response without a signature exits 5, as the upload route already did, instead of 1. An empty or unreadable response exits 4 for health, which used to report the server as up and exit 0, 1 for keys, which used to print an empty list and exit 0, and 1 for verify, which used to exit 6 as though the signature were invalid.
  • FixedThe command line tool built for a platform other than Windows now refuses --prehash, --append, --tsa-direct and --add-cert with --format authenticode, with exit code 2 and before any request is sent. Those options need the local pre-hash route, which sgcsign.exe has on Windows only, and such a build used to upload the whole file and drop them without a word. The .NET tool takes that route on every platform.
  • FixedThe command line tool now applies SGCSIGN_TSA_DIRECT only to a run that asks for a timestamp through --tsa. The variable used to override --no-timestamp and fetch a timestamp anyway, and a run without --tsa had the server sign and then failed with exit code 5, so a variable set for a whole build agent broke every job on it that gave no --tsa. Those runs now behave exactly as they do without the variable, and --tsa-direct keeps its own checks.
  • FixedThe command line tool now treats a response that ends before the length the server announced as a server that cannot be reached, exit code 4, on both transports and for every verb, instead of using the part that arrived. The health verb also exits 4 for an answer that is a JSON array, which it used to report as a healthy server, and for a server URL with no host, which the WinHTTP transport used to stop on with a fatal error and exit code 1.
  • FixedThe command line tool now refuses an API key that contains a line break or any other control character before any request is sent, with exit code 2 when it comes from --apikey and 1 when it comes from SGCSIGN_APIKEY, and the message never repeats the key. Such a key used to be sent as it was, and a line break added a header line of its own to the request. A --server port above 65535, a port of 0 and a port that is not a number are refused too, with exit code 4 on every verb. Both transports used to wrap the number around 65536, so port 99999 connected to port 34463, and the Windows transport sent the API key there as well.
  • FixedThe command line tool now refuses a server URL whose scheme is not http or https, such as ftp://, before any request is sent, with exit code 4 on every verb and both transports, and a URL with a scheme and no host, such as http://, exits 4 the same way on both. The Windows transport used to read the scheme as a host name, so wherever a host of that name resolved the request went there with the API key, and the indy transport sent the request as plain http to the host and port the URL named. A server URL with no scheme at all, such as localhost:8443, is now refused the same way, where the Windows transport used to send the request, API key included, over plain http. Upgrade note: a script that gives the server without http:// or https:// must now add it. Spaces before and after the server URL are now trimmed, backslashes after the scheme are accepted as slashes, so http:\\host is read as http://host, and a server given as a bracketed IPv6 address, such as http://[::1]:8443, now works on the Windows transport, which could not connect to it.
  • FixedSignature server: the admin console now reports a duplicate username with a clear message instead of the raw database error, including a name that differs from an existing one only in case and two administrators creating the same name at once. A project slug created twice at once is reported the same way, and any other database failure behind a console action or page now shows a short message pointing to the server log, where the detail is written.
  • FixedSigning an MSIX or APPX package with a certificate that does not match the package no longer produces a package Windows refuses. Windows requires the Publisher written in the package manifest to be exactly the subject of the signing certificate, and rejects the whole package when the two differ, which shows up as a package with no signature at all and one that looks corrupted. sgcSign signed it anyway and reported success. It now stops and names both values, and the server answers 400 instead of handing back a package that will not work. A new ValidatePublisher property (True by default) turns the check off, and two new helpers, sgcAppxReadPublisher and sgcAppxDNMatches, let you compare the two yourself before signing. Reported by a customer, thank you.
  • FixedSignature server: the admin console error page for an unexpected failure now always shows a short message pointing to the server log and never the text of the error, which is written to the log instead, and writing to that log never holds up the console, even when nothing is reading the server output. The audit log page now also shows the message a console action sends back to it, so a failed audit chain check reports that the audit log could not be read, where the page used to show nothing.
  • FixedThe PEM key provider now loads an EC private key in the traditional OpenSSL form, the file that starts with BEGIN EC PRIVATE KEY, which is what openssl ecparam -genkey writes. Only the PKCS#8 form, BEGIN PRIVATE KEY, was accepted, and the traditional form failed with "Failed to decode private key". It now loads from a separate key file and from a combined certificate and key file, and signs exactly as a PKCS#8 EC key does. Such a key can now also be saved to a PFX/P12 file with SaveToP12 and SaveToP12Bytes.
  • FixedThe PEM key provider can now save an encrypted PKCS#8 key, the file that starts with BEGIN ENCRYPTED PRIVATE KEY and is loaded with PrivateKeyPassword, to a PFX/P12 file. SaveToP12 and SaveToP12Bytes passed the still encrypted key to the export and failed with NCryptImportKey failed: NTSTATUS=$8009310B. The decrypted key is now exported, for RSA and EC keys, and the key held in memory is overwritten when the provider is reloaded or freed. Calling LoadCertificateOnly after LoadFromFile also no longer keeps the previous private key, which let SaveToP12 pair the new certificate with the old key.
  • FixedThe PFX key provider can now sign with an EC key. A PFX or P12 file holding a P-256, P-384 or P-521 key was reported as RSA-SHA256 and every signature failed with NCryptSignHash error $80090027, so no XAdES, CAdES, PAdES or Authenticode signature could be made with it. The provider now reads the key type from the key itself, reports ECDSA with the configured digest, and signs with ECDSA through SignData and SignDigest, exactly as the PEM provider does. This includes a P12 written by the PEM provider with SaveToP12, and a certificate with an EC key issued by an RSA CA, which is reported by the algorithm of its own key.
  • FixedThe Windows certificate store key provider, TsgcWindowsCertStoreProvider, can now sign with a certificate whose private key is EC (P-256, P-384 or P-521). It reported RSA and every signature failed with 0x80090027. It now reads the key type from the key itself, reports ECDSA with the configured digest, and signs with ECDSA through CNG, exactly as the PEM and PFX providers do.
  • FixedSigning with an EC key set to SHA-1 now produces a valid signature. The PEM, PFX, PKCS#11 and Windows certificate store providers reported such a key as ECDSA with SHA-256, so XMLDSig and XAdES declared ecdsa-sha256, and CAdES, PAdES and timestamp requests declared ecdsa-with-SHA256, over a signature made with SHA-1, which did not verify. TsgcSignatureMethod has a new value, smECDSA_SHA1, added at the end so the existing values keep their ordinal numbers, and the signers now declare http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1 and ecdsa-with-SHA1 (1.2.840.10045.4.1) for it.
  • FixedNuGet packages and CMS signed timestamp requests could carry a signature that does not verify. TsgcNuGetSigner.Hash and TsgcTSAClient.SignOptions.HashAlgorithm were written into the signature, while the PEM, PFX, PKCS#11 or Windows certificate store provider kept signing with its own HashAlgorithm, so a SHA-384 package on a provider left at SHA-256 declared one digest over a signature made with the other, with RSA and EC keys alike. Both signers now hand their digest to the provider for the signature and restore the provider setting afterwards, as CAdES, PAdES and Authenticode do, and a provider that only signs with SHA-256, such as the cloud providers, now refuses any other digest with a clear error.
  • FixedAn RSA key set to SHA-1 was declared as rsa-sha256 by the ClickOnce signer and by TsgcXMLDSigEngine, so the manifest named one digest over a signature made with another and did not verify. Both now declare http://www.w3.org/2000/09/xmldsig#rsa-sha1. The ClickOnce signer also hands its Hash to the key provider before signing, as the XMLDSig signer does, so SHA-1, SHA-384 and SHA-512 manifests verify whatever the provider was set to, and a provider that only signs with SHA-256 refuses the other digests with a clear error.
  • FixedThe Google Cloud KMS provider reported every key as RSA with SHA-256 and always asked Cloud KMS for a SHA-256 signature, so an EC P-256 key was labelled RSA and an RSA-PSS key was labelled PKCS#1 v1.5, producing signatures that fail validation with no error raised. Connect now reads the algorithm of the key version from the public key answer, and each request carries the digest that key version requires. EC_SIGN_P256_SHA256 is reported as ECDSA with SHA-256 and its signature is returned as the raw r||s pair the other providers return. EC_SIGN_P384_SHA384 (ECDSA with SHA-384) and RSA_SIGN_PKCS1_4096_SHA512 (RSA with SHA-512) sign through SignDigest only, because the signers declare SHA-256 for a cloud provider. RSA-PSS, raw PKCS#1, secp256k1, Ed25519 and post-quantum key versions are refused at Connect, a digest the key version does not sign is refused with a message naming its algorithm, and changing the key after Connect now requires a new Connect.
  • FixedVSIX packages could carry a signature that does not verify. The VSIX signer declared rsa-sha256 for an RSA key set to SHA-1, and it never handed its Hash to the key provider, so a SHA-1, SHA-384 or SHA-512 package on a PEM, PFX, PKCS#11 or Windows certificate store provider left at another digest declared one digest over a signature made with another, and on the signature server it signed with whatever digest the previous request had left. The signer now declares http://www.w3.org/2000/09/xmldsig#rsa-sha1 for SHA-1, hands its Hash to the provider for the signature and restores the provider setting afterwards, and a provider that only signs with SHA-256, such as the cloud providers, now refuses any other digest with a clear error, which the server answers with 400.
  • FixedTsgcVSIXSigner accepted an EC key and wrote an ECDSA signature under an RSA SignatureMethod, so a VSIX signed with a P-256, P-384 or P-521 key from a PEM, PFX, PKCS#11 or Windows certificate store provider failed every verifier. VSIX signing is RSA only, so an EC key is now refused with a clear error before the key provider is used, and /api/v1/sign/vsix answers 422 sign_failed.
  • FixedSignature server: saving providers, webhooks or the firewall from the admin console could delete the configuration file. The file was deleted before the new copy was moved into place, so when that move failed the server was left with no configuration and could not be restarted. The new copy now replaces the file in a single step, a failed save leaves the file exactly as it was, and the console says so.
  • FixedSignature server: a firewall change saved from the admin console that could not be applied to the running server left the server with no firewall at all. The new rules are now built before they replace the running ones, so when applying them fails the previous rules stay in force and the console says so.
  • FixedSignature server: when a firewall change could not be written to the configuration file, the admin console showed the rejected values as if they had been saved. It now shows the stored rules.
  • FixedSignature server: the Hash algorithm setting of a PFX provider (hash) had no effect. It is now applied to the provider, an unknown value makes the provider unavailable with a configuration error, and a sign request that leaves out hash (or alg on the authenticode, msi and raw hash routes) is signed with it. Every other provider defaults to SHA-256, an explicit hash or alg still wins, MSIX and APPX keep SHA-256, and XAdES keeps the digest its profile fixes.
  • FixedSignature server: CAdES and PAdES signed every document with SHA-256 whatever the request asked for. They now sign with the requested digest, and a cloud provider that only signs SHA-256 answers 400 instead of signing with another digest than the one requested.
  • FixedSignature server: the AWS KMS provider ignored its certificate file (cert_file), and a Google Cloud KMS provider had no way to receive one, so both could only sign through /api/v1/sign/raw. Both now read the optional cert_file before connecting, and a missing or invalid file makes the provider unavailable with a clear error. The AWS KMS, Google Cloud KMS and HashiCorp Vault providers accept the certificate file as PEM or DER; a PEM file made the Vault provider fail with "Invalid certificate: expected SEQUENCE".
  • FixedSignature server: the admin console labelled the Vault provider certificate as a CA certificate file. It is the signing certificate paired with the Vault key, and the field is now labelled Certificate file path (optional).
  • FixedSignature server: the OpenAPI description of /api/v1/keys now says it lists every configured provider without a project filter, and the sign routes no longer declare sha256 as the default hash, since the provider default applies.
  • FixedPKCS#11: the PIN, the certificate label filter and the token and slot description fields were handled in the code page of the machine. PKCS#11 defines all of them as UTF-8, so a PIN or a label holding an accented character was sent as the wrong bytes and a token label came back unreadable. They are now encoded and decoded as UTF-8.
  • FixedThe Authenticode digest of a Windows Installer package that holds storages inside it was computed in the wrong order, so the signature written over such a package was one Windows refused with "the digital signature of the object did not verify", and a package somebody else had signed was reported as modified when it was not. Every .msp patch package holds storages, and so does an .msi carrying an embedded transform. The streams and the storages of a storage are now hashed together in name order, not every stream first and every storage afterwards, which is what the digest inside the signature of fifteen packages signed by Microsoft and Adobe says. An .msi with no storages inside it is unaffected and its digest is unchanged.
  • FixedSignature server: timing no longer goes wrong once Windows has been running for 49.7 days, when its millisecond counter wraps back to 0. Updating or removing a key provider waits for a signature in progress to finish, and around the wrap that wait gave up at once and reported the provider as busy, could last for weeks, or, in a build with overflow checking, raised an error. The duration reported for a signature that crossed the wrap was 0. Both now measure the time elapsed in a way that survives the wrap.
  • FixedPKCS#11 on a 64 bit platform that is not Windows. The Cryptoki types were declared with the Windows widths on every platform, so on 64 bit Linux, macOS and Android the token information call wrote 48 bytes past the end of the buffer and the slot list call ran past the end of the array, which brought the process down. They now follow the ABI of the platform. Windows is unchanged byte for byte. Off Windows the module is loaded with the platform loader and a failure carries the message the loader gave, and on iOS a module is refused by design with a clear message.
  • FixedOff Windows the library recorded local time as UTC with a zero offset, so a CAdES signing time, a XAdES signing time, an AWS request date and a VSIX timestamp were all out by the machine's offset from UTC. The time is now read from the system in UTC, daylight saving included. Windows was always right and is unchanged.
  • FixedOff Windows several checks were not performed at all. Verifying a signed DER structure, verifying a certificate signature, verifying a DER signature, the random value the server uses for authentication and the OCSP nonce were all stubs that did nothing or refused, and the certificate a signature has to be checked against could not be looked up. They all work now, and the issuing certificate is looked for in SSL_CERT_FILE and SSL_CERT_DIR first, then in the distribution CA bundles on Linux, the system and Homebrew bundles on macOS and the system anchor directories on Android. iOS has no such file to read and the API says so.
  • FixedCertificates whose key is on a Brainpool curve (brainpoolP256r1, brainpoolP384r1 or brainpoolP512r1), such as the ones used in the German gematik health network, could not be verified. VerifySignatureBy and MatchesIssuer with the signature check turned on returned False even when the issuer was the right one. These signatures are now verified on every platform, on Windows 10 and later through CNG. Signing with a Brainpool key is still not supported and is refused with a clear error. Reported by a customer, thank you.
  • FixedOn Linux, the response headers the HTTP transport hands back, the ones sgcSignHTTPHeaderValue reads, lost the SameSite, Max-Age and Expires attributes of every Set-Cookie line and could end with empty lines. They now carry the Set-Cookie lines exactly as the server sent them. On macOS, iOS and Android each line is still rebuilt from the parsed cookie, which now includes Expires but cannot carry SameSite.
  • FixedThe license tool could not issue a license anywhere but Windows, it stopped with "failed to build BCRYPT_RSAFULLPRIVATE_BLOB". It now signs through the library's own cryptography on every platform, and licenses issued before still verify. The issued_at time written into a license was the local time marked as UTC, it is now real UTC.
  • FixedAsking the server to check a Windows Installer package, an MSIX or APPX package or a catalog reported the file as not valid instead of checking it, even though signing those formats worked. All three are now checked properly, on every platform. Sending a file that is not what the request says it is now answers with an error that says so, instead of reporting a good signature as broken.
  • FixedA catalog file could not be checked by the library at all. It was read as if it were a program file and the check failed. A catalog is now recognised and its signature and content list are checked.
  • FixedSignature server admin console: a firewall rule that is not valid showed the general error page instead of saying what was wrong with it, and could leave the page unusable. Deleting a key, a user or a project that does not exist, or enabling a key that does not exist, reported success although nothing had changed. Both are fixed, and the console now says what went wrong.
  • FixedSigning with a version 1 certificate, the kind without extensions that is still common for test and internal certificates, produced CAdES, Authenticode, NuGet and signed timestamp request signatures that no verifier could read, OpenSSL stopped with a parse error on the issuer. The certificate's validity dates were written where its issuer name belongs. Version 1 certificates are now read correctly, and the same fix applies to OCSP revocation checks against a version 1 issuing certificate and to the signature verifier. PAdES was not affected.
  • FixedTsgcCatalogSigner, TsgcMSISigner, TsgcAppxSigner and TsgcPowerShellSigner could not be used through a variable of type TsgcAuthenticodeSigner. SignFile, SignStream and SignBytes were not virtual, so a call through the base type ran the EXE signer, which failed on a catalog, an installer, a package or a script with "Invalid DOS signature". They are now virtual and overridden, so each of the four signs its own format whichever type holds it. Code that calls them on the concrete class is unaffected.
  • FixedSignature server: the hash routes, /api/v1/sign/authenticode/hash, /api/v1/sign/msi/hash and /api/v1/sign/appx/hash, now send the X-Sgcsign-Duration-Ms and X-Sgcsign-Signer-Subject headers the upload routes already send. The command line tool read both, so after a hash route signature it printed "Duration: ms" with no value, and on the authenticode route an empty signer. Both are now filled in, and the OpenAPI description declares the two headers on the hash routes. The signer_subject field of the JSON body is unchanged.
  • FixedSignature server: a call refused by the per minute limit or by the total call quota no longer uses up the daily quota of its API key. Until now every refused call was still counted for the day, so a key that reached its per minute limit ran out of its daily quota early, for example after 40 calls on a quota of 60. Reported by a customer, thank you.
  • FixedTimestamps: when a timestamp server refused a request and wrote the reason with characters that are not valid UTF-8, for example Polish letters in an older code page, the reason was lost. On Windows the call stopped with a text decoding error instead of the timestamp error, and on Delphi 7 and Linux the error said only "rejection". The reason given by the server is now always part of the error message.
  • FixedSignature server: the Create User form of the admin console offered only the admin, operator and readonly roles, so a project admin or a delegated administrator had to be created with another role and changed afterwards. It now offers every role, project_admin and delegated_admin included. Requested by a customer, thank you.
  • FixedXML signature verification now takes the SignedInfo, the References and the SignatureValue from a single parsed document tree. Before this, a crafted document could make the verifier check one SignedInfo while digest checking different References, or hide a Reference URI inside a comment, and still be reported as valid. A document with more than one SignedInfo, with duplicate Id values, or that is not well formed is now rejected.
  • FixedXML signature verification no longer removes a plain element named Signature that is not in the XML Signature namespace. Documents that carry such a business field now verify correctly.
  • FixedEU trust lists: the certificate used for the pinned pivot and for the member state identity check is now always the one inside the signature that verified the list, never a certificate found elsewhere in the document, for example inside a comment. A list with more than one top-level signature is now refused. Without RequirePinnedPivot a list is only integrity checked, not authenticated, and the documentation now says so.
  • FixedLTV verification no longer judges an embedded OCSP response against the SigningTime written by the signer, since a signer holding a revoked key could backdate that value. Without a verified timestamp the current time is used instead, so an old embedded response can no longer skip the live revocation check.
  • FixedAuthenticode verification now checks the certificate table strictly and reports a file as tampered when data is hidden in it outside the signature. It previously reported such files as valid.
  • FixedCertificate chain building now always requires every issuing certificate to be a CA (basicConstraints cA, and keyCertSign when keyUsage is present), honours pathLenConstraint, checks issuer validity, and treats a critical extension it does not process, including a critical nameConstraints, as making the chain untrusted, regardless of the CheckKeyUsage setting. Before this, any end-entity certificate issued under a trusted CA could itself issue certificates that chained as trusted. X509 certificates gained PathLenConstraint and UnsupportedCriticalExtension properties.
  • FixedThe XML parser now limits element nesting to 1024 levels. A deeply nested document could previously overflow the stack and terminate the process.
  • FixedKSeF: extracting a downloaded pack now rejects entry names that would write outside the destination folder, checks every name before writing anything, and creates folder entries correctly.
  • FixedKSeF: a malformed JSON array in a server response no longer makes the parser loop forever. It now raises a parse error instead.
  • FixedThe PE parser now uses overflow safe bounds checks. A crafted header offset could previously pass the old checks and cause an access violation when signing or verifying.
  • FixedSignature server: an admin console session that reached its maximum lifetime, or that was ended from another tab, could previously still be used. Requests now work on a private copy of the session, and an expired session is sent back to the login page.
  • FixedXMLDSig and XAdES signing no longer remove an existing signature, or any element named Signature, from the document being signed. For an enveloped signature over the whole document, the digest now matches the output, so signing a document that already contains such an element produces a valid signature.
  • FixedSigning a file in place, covering Authenticode, PowerShell, catalog, MSI, MSIX and APPX, ClickOnce, NuGet, VSIX and PDF, now writes to a temporary file and replaces the target only once the write has succeeded, so a failed write can no longer leave the original truncated. NuGet, VSIX, ClickOnce and PDF can now be signed in place as well.
  • FixedSigning with a key provider shared by several threads could produce an invalid signature with no error, because each signer set the provider hash algorithm, signed and restored it without a lock, so one thread could sign with the digest another thread had just set. Signers now call the new SignDataWithHash method of the key provider, which sets, signs and restores the hash under a lock of the provider, and they no longer leave their digest behind in the provider. Code that shares a provider between threads should call SignDataWithHash instead of setting HashAlgorithm and calling SignData.
  • FixedSignature server: every admin console page showed its content below the menu instead of beside it, after the HTML components started drawing a menu that folds into a drawer on small screens by default. The menu is drawn the way the console expects again, and a page can no longer be broken this way by a future change in how the menu is drawn.
  • FixedPAdES: PDFs saved with a cross-reference stream (PDF 1.5 and later) could not be signed and failed with "cannot locate the document Catalog (/Root)". This is the default for files made from Microsoft Office through Acrobat PDFMaker, among others. They now sign, including LTV and archive timestamps, and the update written by the signer uses the same kind of cross-reference as the original file, so strict validators see a consistent structure. Reported by a customer, thank you.
  • FixedPAdES: the update written by the signer now keeps the document information and the document ID of the original file, as the PDF standard requires.
  • FixedPAdES: in a PDF whose form dictionary is stored as a separate object, the new signature field was not added to the form, so some viewers did not list the signature. The same applied to the document timestamp. Both are now added.
  • FixedPAdES: the signature widget is now placed on the real first page of the document. It used to go to the first page object found in the file, which in some files is not page 1.
  • FixedSignature server: audit.retention_days was never applied, so the audit log only ever grew. The retention now runs when the server starts and then once a day, and the log stays verifiable: the entries are checked before they are deleted, nothing is deleted when the hash chain is broken, and every purge is itself written to the log as audit.purge. Upgrade note: with the default of 365 days, the first start after upgrading deletes every audit entry older than one year. Set audit.retention_days to 0 before upgrading to keep every entry.
  • FixedSignature server: the Windows server needed a sqlite3.dll that was never shipped with it, so it could not open its database on a machine that did not already have one. SQLite is now built into the server and no DLL is needed.
  • FixedSignature server: CAdES signatures were never timestamped, even when a timestamp server was given. They are now CAdES-T whenever the request, the provider or the server configuration supplies a timestamp server, and CAdES-BES otherwise.
  • FixedSignature server: a tsa_url sent with a XAdES profile that does not timestamp was ignored without a word. It is now refused with 400 timestamp_not_supported, so a caller that expects a timestamp learns that it will not get one.
  • FixedSignature server: Windows paths written with forward slashes in the configuration file, such as C:/sgcsign/data/sgcsignserver.db, are now accepted.
  • BreakingSignature server: an approval can now be used only once. Executing an approval that has already signed answers 409 approval_already_used, where it used to sign again, so a script that reused one approval for several files has to request one for each signature.
  • BreakingThe sign verb of the command line tool no longer forces a signature without a timestamp when --tsa is not given. The server now decides, so it timestamps with the tsa_urls of the provider or the default timestamp servers. Add --no-timestamp to keep the old behaviour.
  • BreakingSignature server: a tsa_url on a XAdES profile that does not timestamp now fails with 400 timestamp_not_supported instead of being ignored. Remove the tsa_url or choose a profile that timestamps.

sgcSign 2026.9.0

  • 2026.9.0: 2026 September
  • NewCertificate lists now carry the SHA-1 thumbprint, the NIF, the serial number, the issuer and the validity dates, the same way for the Windows certificate store, a PKCS#11 token and a PFX file, and can leave out expired certificates and those without a private key. The thumbprint can be passed straight to SelectCertificateByThumbprint, and a new EnumerateCertificateList returns the same information as objects instead of text. The call without parameters is unchanged. Requested by a customer, thank you.
  • NewPKCS#11: a multi-slot card, common with Polish qualified-signature cards that put separate certificates behind separate PINs, can now be inventoried without any PIN. EnumerateCertificateList(aSlotIndex, aFilters, aLogin) reads one slot and EnumerateCertificateListAllSlots reads them all, each entry recording the slot and token it came from, and a new TokenSlotCount reports how many slots actually hold a token, which is the range to address. Requested by a customer, thank you.
  • NewKey providers: new GetIssuerCertificate and GetCertificateChain calls find the certificate that issued the one you are signing with, and the whole path above it. The match is checked cryptographically rather than by name, so an authority that has changed its signing key is not confused with its predecessor. Requested by a customer, thank you.
  • NewKey providers: new IssuerLookup and IssuerFiles properties decide where the issuing certificate is looked for. Most qualified signature cards carry only your own certificate, so the Windows certificate store is now searched as well by default, iluLocalStore searches PEM or DER files you ship with your application, and iluAIA downloads it from the address inside the certificate, which is off by default. Requested by a customer, thank you.
  • NewPAdES: two new profiles. spPAdESBasicT signs with just an embedded timestamp and no revocation data. spPAdESDocumentArchive adds an archive timestamp on top of the long term profile, covering the whole document including its revocation data, so the file stays checkable once the first timestamp's own validity window has passed. Requested by a customer, thank you.
  • NewPAdES: a new CRLFiles property, matching the one XAdES already had, embeds revocation lists you supply yourself, for the authority whose revocation lives in the list issued by its own root. When OCSPClient is assigned and IssuerCertificate is left empty, the issuer is now found automatically. Requested by a customer, thank you.
  • NewCertificates: the subject and the issuer now report every attribute they carry, not just the seven the parser recognised, and the postal address is decoded into readable lines. Any attribute can be read by its OID with GetSubjectAttribute and GetIssuerAttribute, and the full list, in order, through SubjectAttributeCount, SubjectAttributeOID and SubjectAttributeValue. Requested by a customer, thank you.
  • NewTSA: timestamp requests can now be signed, which some qualified authorities, the Polish ones in particular, require. Set RequestFormat to trfCMS and assign a KeyProvider, SignOptions exposes the parts that differ between authorities, and OnBeforeSendRequest and OnAfterReceiveResponse hand you the exact bytes sent and received. The default shape matches a request accepted by PWPW Sigillum's TSA, set SignOptions.IncludeSignedAttributes for an authority expecting the more common form. Existing code keeps sending a plain request. Requested by a customer, thank you.
  • NewAuthenticode: extra certificates can now be embedded in the signature, the same thing signtool /ac does, so a kernel-mode driver signature can chain to the Microsoft Code Verification Root through its cross-certificate. Add them with AddCertificate and AddCertificateFromFile on TsgcAuthenticodeSigner, and ClearCertificates empties the list. They flow into every nested signature, and adding nothing leaves the signature byte for byte what it was. The signing server takes an add_certs field and the CLI a repeatable --add-cert option. Requested by a customer, thank you.
  • NewSignature verification can now be given trust anchors, and it builds and checks the certificate chain. Until now the verifier took the signing certificate out of the document it was checking and confirmed that key had signed that document, which proves only that whoever wrote the document also wrote the signature in it. New TrustedCertificates and TrustedCertificateStore properties say which roots you trust, and RequireTrustedChain, CheckKeyUsage and RequireCompleteRevocationCheck decide how strict the outcome is. An anchor is matched by SHA-256 thumbprint or by verifying under its own key, never by name. A verifier with no anchor returns the verdict it returned before, but the ETSI TS 119 102-2 report no longer says total-passed for a signature that was never chained to an anchor, it says indeterminate with NO_CERTIFICATE_CHAIN_FOUND, so stored reports produced without an anchor need regenerating.
  • NewProxies, proxy authentication and client certificates. Every request the library makes now goes through one transport with a shared HTTPOptions property: the timestamp client, the OCSP and revocation list clients, the EU trust list download and the cloud key providers. It carries the proxy, which can be the system one, none, an explicit address or the one the machine resolves per address, the credentials for a proxy that asks for them, the client certificate, the lowest accepted TLS version and the user agent. Every setting defaults to what those requests did before, and a new OnHTTPRequest event replaces the transport completely for a gateway these settings cannot describe. Requested by a customer, thank you.
  • NewOCSP: the revocation request now carries a random nonce from the system cryptographic generator and the response is checked against it. A new NonceEnabled property turns the extension off for a responder that refuses it. A response echoing no nonce is still accepted, as RFC 6960 allows pre-produced responses, but one echoing a different nonce is refused.
  • NewEU trust list: a new RequirePinnedPivot property, with LOTLPivotPinned and LastPivotFingerprint reporting the outcome, decides whether the list of trusted lists has to chain to one of the pinned Official Journal pivot fingerprints. The check existed and was called from nowhere, and now runs on every download. The pinned constants shipped are still the documented placeholders, so a miss is reported through LastError until you fill in real fingerprints and turn RequirePinnedPivot on.
  • NewCAdES and PKCS#11 both gain a HashAlgorithm property, defaulting to SHA-256 so existing code produces the same bytes as before. CAdES wrote SHA-256 into every digest algorithm as a literal and PKCS#11 chose its DigestInfo header from the length of what it was handed, so no other digest could be expressed. A card can now sign with SHA-1, SHA-256, SHA-384 or SHA-512 as asked.
  • NewASiC: a new BuildCAdES overload takes a signing callback instead of finished signature bytes. It builds META-INF/ASiCManifest.xml first, hands those exact bytes to your callback and stores what it returns as META-INF/signature.p7s, which is the only order in which the signature can cover the manifest. For ASiC-S, which carries no manifest, the callback receives the data document itself. A new GetCAdESSignedData helper returns the same bytes for callers who prefer two explicit steps.
  • NewAWS KMS and Google Cloud KMS: new SetCertificate and SetCertificateFromFile methods, matching the pair HashiCorp Vault already had, to supply the X.509 certificate that belongs to the key. Both services hand out a bare public key, and there was no way to tell either provider which certificate to embed.
  • NewServer: an Authenticode signature can now carry more than two nested signatures, and a different certificate for each one. The upload endpoint accepts hash_algorithms, an ordered list such as sha1,sha256,sha384, and providers, an ordered list such as certA:sha256,certB:sha1, up to four entries either way, providers taking precedence and dual_sign remaining an alias for sha1,sha256. This is for shipping one file signed by an expiring certificate and its replacement. Every certificate is checked against the API key's permissions before any signing starts, and the hash digest endpoint gains a matching nest_into field. Requested by a customer, thank you.
  • NewServer: Windows catalog files can now be signed. The upload endpoint accepts catalog as a format, which signs an existing .cat file of the kind makecat produces, so a driver package can be signed the same way a program is. Creating the catalog itself is not included. Requested by a customer, thank you.
  • NewServer: API keys and the users who create them are now isolated per project. A project admin manages the keys in their own project, including creating, enabling, disabling, deleting and setting limits, the same as a full admin but scoped to that project. An admin can assign any user to a project from the Users page. Requested by a customer, thank you.
  • NewServer: API keys can now be enabled and disabled instead of only revoked one way, and deleted outright. Revoke keeps working as an alias for disable, and the per key rate limit and daily quota can now be edited after the key is created.
  • NewServer: a new SessionAbsoluteMaxMin setting caps the total lifetime of an administrator session, twelve hours by default. Every authenticated request pushed the expiry forward by the whole session timeout with no ceiling, so a session that kept being used never ended on its own.
  • NewServer: new server.firewall.forwarded_headers settings, off by default, which recover the real client address when the server runs behind a reverse proxy. The address in X-Forwarded-For or X-Real-IP is only believed when the connection itself arrives from an address listed in trusted_proxies, so a client cannot invent one, and the chain is read from the right, past the number of proxies given in trusted_hops, because the leftmost entry is the one the client supplied. Entries take IPv4, IPv6 and CIDR, so a dual-stack proxy that reaches the back end as ::1 can be written down. Once resolved, that address is what the firewall lists, the audit log, the webhook payloads and the administrator lockout all work from. Requested by a customer, thank you.
  • Newsgcsign CLI: a new --tsa-direct option asks the timestamp server directly from the machine running the CLI instead of going through the sgcSign Server. Pass it together with --tsa. Requested by a customer, thank you.
  • NewServer: the audit log can now be filtered by client address, both in the administration console and in the CSV export it produces. The address was recorded from the beginning and there was never a way to search it, so the one field an operator reaches for after an incident was the one field that could not be queried. A partial address matches from the left, so 203.0.113. selects a range and a complete address selects a single client, and the count behind the pager applies the same filter as the list.
  • NewServer: a new /api/v1/sign/raw endpoint signs a digest you have already computed and returns only the signature value, with no PKCS#7 wrapper, no signed attributes and no timestamp. This is exactly what signtool asks for through its /dlib callback, which builds the Authenticode signed attributes itself and expects back only the signature over their hash, which the existing hash endpoint cannot supply because it builds its own attributes and returns a finished PKCS#7. Since it will sign any digest handed to it, it is off by default and is turned on one provider at a time with allow_raw_sign in that provider's params. Nine of the ten key providers offer it, Certum SimplySign cannot because its service does the hashing on its own side, and it answers 422. Requested by a customer, thank you.
  • FixedSignatures made with a smart card, a USB token or a cloud key were wrong, and CAdES signatures were wrong with everything else. SignData had no written contract and the providers disagreed about whether its argument is the data to sign or a digest of it, so every CAdES signature was RSA over a hash of a hash, rejected on submission by OpenSSL, the EU DSS validator, Adobe and every national e-invoicing gateway, while a card signed without error and produced a file no verifier accepts and four of the five cloud providers could not sign at all. The argument is now the raw bytes and the provider hashes them with its configured digest. CAdES files, and anything signed with a card or a cloud key, should be signed again.
  • FixedEvery PAdES, CAdES, Authenticode, NuGet and RFC 3161 signature made with an EC key was structurally invalid. The standards require the signature value inside a CMS structure to be a DER ECDSA-Sig-Value, and the key providers produce the raw concatenation of r and s, which is what XML-DSig wants, with nothing converting it on the way into CMS, so Adobe, OpenSSL, Windows and every eIDAS validator rejected the result. It went unnoticed because the verifier was wrong in the same direction. P-256, P-384 and P-521 all work now, and the XAdES and XML-DSig paths are deliberately left alone. Files signed with an EC key by an earlier version have to be signed again.
  • FixedAuthenticode: verifying a signed program never checked a signature. Verify pulled the file hash out of the signature, recomputed the same hash and reported that comparison as the verdict, so forging a file that sgcSign called validly signed needed no private key, and the server's verify endpoint answered valid, admitting arbitrary binaries into any build pipeline using it as a gate. Verify now requires the recomputed digest to equal the messageDigest attribute, locates the signer certificate by the issuer and serial the signature names, and verifies the RSA or ECDSA signature over the signed attributes. The result gains HashValid, SignatureValid, CertificateExpired and ChainValidated, so an expired signer certificate is reported without invalidating the signature.
  • FixedRevocation checking did not work. On the signing side an OCSP response was accepted as good after reading a single tag byte, with no signature check and no freshness test, so a recorded reply from before the certificate was revoked, or a hand built unsigned one, was embedded into a long term signature as proof the certificate was good. On the verifying side an embedded response was matched on the serial number alone and used with no signature check, and that block sits outside the signed area, so anyone holding the file could rewrite it to keep a revoked certificate verifying without breaking a digest, while a match of any kind suppressed the live query. A response is now verified before any field is read, the identifier is compared byte for byte, thisUpdate and nextUpdate are enforced with five minutes of skew, and freshness is measured against the signature's own signing time so archived signatures still verify. An incomplete check does not change the verdict by default, and can be made to with the new RequireCompleteRevocationCheck.
  • FixedTSA: a timestamp token was embedded without being checked. The only thing verified was the nonce, and even that exited silently when the token could not be parsed, so a reply carrying an empty structure produced a PAdES-T, CAdES-T, XAdES-T or Authenticode file that reported success and carried a timestamp no validator can validate, a rejection was read as granted, and a correctly signed token covering a different document was accepted verbatim. The status is now read over its whole length, an unparseable token is a hard failure, the hash algorithm and hashed message must equal what was requested, and the signature over the signed attributes is verified.
  • FixedThe EU trust list was downloaded and used without verifying anything at all, and because the member state addresses come out of that same document one substituted list redirects every member state download in a single step, so anyone able to answer for those addresses, or to write into the cache directory, could have their own authority reported as qualified by IsQualifiedAtTime. The signature on the list of trusted lists is now verified before parsing, and each member state list is accepted only when its signing certificate is one of the service digital identities that list publishes for the territory, matched by SHA-256 and never by name. A territory publishing no identity is refused and named in LastError. All 31 member state lists bind by exact thumbprint, for 3,691 services.
  • FixedXML signatures: two ways the verifier could be made to check something other than the part of the document it was reporting on. A ds:Reference of the form URI="#x" was resolved by trying each candidate identifier attribute name in turn, ID first, then Id, then wsu:Id, so an element carrying ID="x" anywhere in the document outranked the genuine element carrying Id="x" that came first. That is signature wrapping, the standard break against SAML assertions and WS-Security messages. Separately, the enveloped signature transform removed the first child element whose local name was Signature and accepted an element in no namespace as one, so forged content could hide inside a business element written as <Signature xmlns="">, and two parallel signatures could neither be verified nor signed correctly. Identifiers are now resolved in a single pass, a duplicate identifier is a hard failure on both sides, and the transform requires the XMLDSig namespace and removes itself instead of the first signature it finds.
  • FixedA malformed file could make the library read or write outside its own buffers. The ASN.1 parser accumulated a declared length into a signed integer with no bound and no overflow test, so an impossible size came back negative and the walk went backwards out of the buffer, while a length working out to zero advance grew memory until the process died. The message builder then copied the issuer name using the length the certificate declared rather than the length present, so unrelated process memory was signed into the signature, which on the signing server means those bytes travelled back to whoever uploaded the crafted certificate. The parser now rejects a length that does not fit the bytes present and stops a walk that is not advancing, the copy sites are bounded, and a program whose security directory overlaps its headers is refused. Well formed input produces byte identical results to before.
  • FixedPAdES: a PDF could be signed with one digest and labelled with another, producing a file that sgcSign reports as signed and that Adobe, the EU DSS validator and pyHanko all reject, with no warning before the document was submitted. Profile.HashAlgorithm was written once in the constructor and never read again, and a key provider shared by two signers on the same form kept whatever the previous signer left on it, so a PDF signed after a Facturae or SAF-T signer was RSA over a SHA-1 digest inside a signature declaring SHA-256. The hash algorithm is now read at every digest site, and the PAdES signer pushes its own digest into the provider immediately before signing and restores the previous value afterwards.
  • FixedPAdES: a reason, location, contact or signer name containing a bracket produced a PDF that readers refuse to open. "Approved :-)" is enough, and so is a European address or a Windows path. On the signing server, where those values arrive as form fields, an unbalanced bracket closes the string early and the rest becomes PDF syntax inside the signature dictionary, which sits inside the range the signature covers, so a request could add a second signing date under a valid signature made with the server's own key. All four values, the certificate name used when no signer name is given and the signature field name are now escaped, extended to carriage return, line feed, tab, backspace and form feed.
  • FixedThe Google Cloud KMS provider could never authenticate, under any configuration. The assertion sent to obtain an access token declared RS256 and was in fact signed with HMAC-SHA256 keyed on the text of the private key, so Google answered invalid_grant and Connect never completed, with an error that reads like a bad service account or a missing role. The assertion is now a real RSASSA-PKCS1-v1_5 SHA-256 signature made with the service account key, accepting both PKCS#8 and PKCS#1 files.
  • FixedPAdES: long term validation did not work. Profile and TSAClient did nothing at all, so spPAdESLTV produced a signature identical to the basic profile with no timestamp and no revocation data, and setting a profile only recorded which one was requested. Once a timestamp was embedded the validation data still carried nothing about it, so Acrobat reported that the timestamp could not be verified. TSAClient now embeds a real timestamp, the new OCSPClient and IssuerCertificate properties add the signing certificate's revocation status, and the validation data carries the whole path of both the signing certificate and the timestamp with the revocation list covering every certificate in them. Reported by a customer, thank you.
  • FixedPAdES: a document signed with an invisible signature, which is the default, opened in Acrobat as "at least one signature is invalid" with nothing listed in the Signatures panel. The signature was correct, the field was never attached to a page, so Acrobat found it but could not place it. Documents whose page keeps its annotations in a separate object had the same problem and are handled too. Reported by a customer with a sample PDF, thank you.
  • FixedPAdES: the signing time was read from the computer clock but written as if it were UTC, so a signature made at 15:00 in Madrid was stamped as 15:00 UTC, two hours early. Both dates now use real UTC.
  • FixedOCSP: the responder address was read from the wrong entry of the certificate. A certificate publishes several addresses in the same extension, one for the responder and one for downloading the issuing certificate, and the code took the first one that merely looked like a web address, so on a certificate that lists the issuer download first, which many qualified certificates do, the request came back as "OCSPClient returned an empty OCSP response". The responder is now selected by its own identifier. Reported by a customer, thank you.
  • FixedXAdES: automatic resolution of the issuing certificate matched by name and authority key identifier alone with no cryptographic check, and silently fell back to whichever certificate was listed first, or to the signing certificate itself, so the revocation data could be built against the wrong certificate. It now uses the same verified match PAdES and the key providers use, can resolve the issuer through the KeyProvider as well as from listed files, and reports a clear error instead of guessing. Delphi and .NET both affected.
  • FixedTSA, OCSP and the EU trust list: the Timeout property was never applied to the connection and the trust list download had no timeout at all, so a server that went quiet held the call for the system default. An HTTP error page was also handed to the parser as if it were a response, reported as "Invalid TSA response: expected SEQUENCE" or a parse failure, and the status is now checked first and reported as it is. The TSA request nonce came from a generator reseeded from the system clock, so two requests in the same instant could carry the same predictable nonce, and it now comes from the system cryptographic generator.
  • FixedAuthenticode: a file signed with no timestamp server assigned still showed a signing time in its properties, with no timestamp certificate behind it, which could look like a fake timestamp. It is no longer written unless the new IncludeSigningTime property is turned on, and verifying a file now reports the real timestamp date and who issued it. Reported by a customer, thank you.
  • FixedPKCS#11: a login that failed, or was intentionally skipped, could leave the connection to the card open, after which every later certificate listing reported the first slot whichever slot was requested. Listing certificates now opens a read-only connection, which is less likely to be refused while another application also has the card open. EnumerateSlots and SlotIndex also numbered slots differently as soon as one reader was empty, and they agree now.
  • FixedWindows certificate store: the certificate list reported the subject and issuer as a short display name and the dates in local time, while the same list from a PKCS#11 token or a PFX file reported the full distinguished name and UTC, and it left the NIF empty for a qualified company seal. All three now report the same thing, with SubjectCN and IssuerCN for the short name and NotBeforeLocal and NotAfterLocal for local time.
  • FixedCertificates: a qualified company seal certificate reported no tax number. These certificates carry no serial number attribute at all and keep the company identity in the organization identifier as VATPL followed by the NIP, which until now only the KSeF helper knew about. GetNIF now falls back to it. Reported by a customer, thank you.
  • FixedCloud key providers: when the service rejected a request, the explanation it sent back was decoded one byte per character, so the message was unreadable exactly when it was most needed. AWS KMS, Azure Trusted Signing, Google Cloud KMS and HashiCorp Vault were affected.
  • Fixed.NET: signatures could not be verified by other software. The issuer name inside the signature was wrapped one time too many, so no reader could match the signature to the certificate that made it and verifiers reported the signer as unknown. This affected PDF, CAdES and Authenticode signatures produced by the .NET version, so documents signed with an earlier .NET version should be signed again. The Delphi version was never affected.
  • FixedServer: an XML document signed through the server was signed over the wrong bytes, and half of what it did sign was uninitialised memory. The helper that turns the uploaded body into text sized the destination in characters and copied that many bytes, so it allocated twice the space it filled, the second half being whatever the memory manager had last left there, which in this process is the heap of a daemon holding PFX passwords, PKCS#11 PINs and decoded private keys. The XAdES signer signs what it is handed without parsing it, so the caller received HTTP 200 and a genuine signature over a document that is not the one they uploaded. The same helper read the Google Cloud service account file, which is why a provider configured by file path never came up.
  • FixedServer: an administration page or a CSV export could return blank rows and then bring the process down. Every list query sized its result array from the record count before reading it, and the database layer fetches fifty rows at a time, so everything past the fiftieth row was written outside the allocated block. Exporting an audit log with more than fifty entries did it every time, usually surfacing as an access violation in a later, unrelated query. All eight list queries now grow their array as they read.
  • FixedServer: under concurrent use the sign and verify endpoints could return a signature over another request's file. The uploaded file was located by scanning a shared temporary directory and taking whichever file was newest, so under load a request could pick up a different request's upload, or a file the web server still had open, which showed up as an occasional error saying the file was in use. Every request now unpacks into a directory of its own, and leftover temporary files are cleaned up, which they never were.
  • FixedServer: the tamper evident audit log broke itself under ordinary load. Each entry reads the previous entry's hash, computes its own over it and inserts, and those were separate calls with the storage lock released between them, so two requests logging at the same moment both stored the same previous hash. The chain then reported a break at that entry for the life of the database, and since the verifier stopped at the first break everything after it was outside the verified region. The read, the hash and the insert now happen under one hold of the lock, and the verifier, which was never called from anywhere, is reachable at /admin/audit/verify.
  • FixedServer: demoting or deleting an administrator did not affect the session they were already using. The role was copied into the session at login and every later permission decision read that copy, so an account revoked in the morning could still create API keys, delete projects and change other users' passwords in the afternoon, while the console reported the change as successful. A role change, a password change and an account deletion now all end every session belonging to that account. The routine that removes expired sessions was called from nowhere, so the session list also grew by one entry per login, and the metrics timer now calls it.
  • FixedServer: the per project isolation this release introduces had two holes in the administration console. Any authenticated session, including an operator or an administrator of a different project, could open /admin/audit or download /admin/audit.csv and receive the complete history of every project, and could read every non secret provider setting, the AWS ARNs, the Azure tenant and client identifiers, the Vault address and key name, and the file paths of PFX, PEM and PKCS#11 material. A project administrator could also approve or reject a pending signing request belonging to another project simply by posting its number, and those numbers are sequential, so four eyes control could be defeated from a different tenant. The audit routes are now limited to administrators and project administrators and scoped to the caller's own project, taken from the session and not from the request, the providers page is limited to full administrators, and a decision on another project's approval is refused and logged as denied.
  • FixedServer: the theme switcher took the return address out of the query string and put it into the Location header without checking it, and that route is deliberately reachable with no session so the theme can be changed on the login page. Query parameters are already URL decoded by then, so a carriage return and line feed inside the value split the response into extra header lines, and anyone able to reach the port could make the server emit a Set-Cookie of their choosing, fixing the session cookie of an administrator on the console that drives code signing. Without the line breaks the same route was a plain open redirect wearing the signing server's own hostname. A redirect target is now accepted only when it is a server relative path beginning with a single slash and carrying no carriage return or line feed, and that check lives inside the redirect helper itself.
  • FixedServer: a dual signed PE file's first signature, the SHA-1 one, was rejected by Windows as invalid while the nested SHA-256 signature verified correctly, because the signature declared SHA-1 and the key provider hashed with SHA-256 regardless of what was requested. Every SHA-1 Authenticode signature was affected, not only the dual signed ones. Cloud and HSM key providers, which cannot be told which digest to use, now refuse a SHA-1, SHA-384 or SHA-512 request with a clear error instead of producing a signature that looks correct and is not. Reported by a customer, thank you.
  • FixedServer: an error reply whose message contained a double quote was not valid JSON, so a client trying to read the error failed to parse the reply instead. The verify reply and the webhook payload both carry the certificate subject, which can legitimately contain quotes and backslashes. Text in replies is now escaped properly.
  • FixedServer: the database was used from several request threads at the same time with nothing to keep them apart, which caused access violations inside the SQLite library, transaction errors and now and then a corrupted query. The first failure left the connection unusable, so the server carried on failing until it was restarted. Database access is now serialised, one request at a time.
  • Fixedsgcsign CLI: the signing certificate's name printed as question marks when it held non-Latin characters, Chinese in particular, while the verify command printed the same name correctly. The name travels back from the server in a response header, which can only carry plain ASCII. The server now encodes that header and the clients decode it. The .NET client was affected the same way and is fixed too. Reported by a customer, thank you.
  • FixedBase64 text was decoded into the wrong bytes, silently, whenever it arrived in the shape it normally arrives in. Anything the decoder did not recognise was treated as zero bits rather than refused, and that includes the line breaks that PEM files, XML signatures and HTTP payloads are full of, so a certificate wrapped across lines came back longer than it should and full of rubbish with no error at all. The same happened to the URL safe alphabet several qualified authorities return, which turned their signatures into corrupt bytes of exactly the right length. Line breaks and spaces are now skipped, the URL safe alphabet is understood, and anything else is refused with a clear error.
  • FixedA crafted ASiC container could make the library read outside its own memory. The offsets and sizes in a zip index are unsigned numbers supplied by whoever built the file and they were read into a signed type, so a large value became negative and the check meant to keep the read inside the file passed. Every one of those values is now held in a type that can represent it, and every bounds test is written so it cannot overflow. Legitimate containers are unaffected, checked against a set of real ASiC, Office, NuGet and VSIX files.
  • FixedA crafted program file could crash the signing service. The Authenticode hasher worked out how much of the file to hash by subtracting two unsigned numbers with no check that the result made sense, so a file with deliberately impossible header sizes produced a length of about four gigabytes over a small buffer. A second form of the same fault was quieter and worse: a section positioned to wrap around the end of the address space hashed bytes from before the buffer and returned a digest, so the signature covered the wrong bytes and nothing reported it. Both are refused now, and a program whose stated header size is smaller than its own headers is rejected when it is opened.
  • FixedA program or NuGet package signed with an EC key was reported by Windows as not signed at all. The signature structure named RSA whatever key had actually signed, so signtool could not pair the algorithm with the signature and answered "No signature found". The algorithm is now taken from the key that signed. Files signed with an EC key by an earlier version have to be signed again, and signatures made with an RSA key are byte for byte what they were.
  • FixedPAdES: a reason, location, contact or signer name containing anything outside plain English was written into the PDF one byte per character, so accented and non-Latin text arrived mangled and Polish, Cyrillic or Chinese metadata was unreadable in the Signatures panel. Text is now encoded the way the PDF specification defines. The visible signature stamp also never declared which encoding it used, so accented characters in a stamp drew the wrong letter even before this, and it does now. Plain English values produce exactly the bytes they produced before.
  • FixedA document signed with a cloud or smart card key could be signed with a different digest from the one the file declares. The check that refuses a digest such a key cannot produce existed only for Authenticode, and the XAdES, XML-DSig and SAF-T PT signers asked the key the same way without it, so with a cloud key the request was ignored in silence. The concrete case is the Portuguese SAF-T PT invoice, where the law requires SHA-1 and the file was signed with SHA-256, non compliant in a way only discovered on submission. All three now refuse with a clear error naming the provider.
  • FixedCloud key providers returned whatever the service sent back without checking it was a signature at all, and the PDF, XAdES and XML-DSig signers did not even check it was not empty. A truncated or corrupted answer therefore became a signed PDF carrying an empty signature, reported as success, which no validator accepts. All six providers now require the signature to be exactly the size the key produces, and the three signers refuse an empty one.
  • FixedData that was not a certificate was accepted as one. Anything shaped like a DER sequence passed, including a bare public key and a revocation list, and produced a certificate with an empty subject, issuer and serial number rather than an error, after which two such certificates compared as each other issuer. The structure is now checked properly before it is accepted. Every certificate in the Windows stores still parses, including the version 1 ones that need special care.
  • FixedXAdES: the signing time, the signing certificate digest and the signature policy were read out of the file and reported as signed without any check that the signature covered them. Anyone holding a validly signed document could add a second properties block ahead of the genuine one and have its signing time reported as authentic. Those properties are now found through the reference that covers them, and a signature that does not cover them is invalid.
  • FixedRevocation lists were believed without being checked. Whatever a distribution point returned was embedded into a long term signature as proof of revocation status, the only test being that the download was not empty, so an error page or a captive portal response became evidence. The lookup that answers whether a certificate is revoked matched serial numbers alone, never verifying the list signature, its dates, or that it came from the right authority, so an unsigned or out of date list confidently answered "not revoked". A list is now verified before it is believed or embedded, and a new CheckRevoked reports "cannot tell" as an answer of its own instead of returning the same value as "not revoked".
  • FixedSigning with a PEM or PFX key left a copy of the private key in the Windows key store, permanently, and nothing ever removed it. One container per signing operation, so a server signing continuously accumulated them without limit, and a count on one development machine found 2,311 of them. Saving to a P12 file left an exportable copy behind as well. Both providers now keep the key in memory only, and where the system will not allow that they delete what they created, including when signing fails part way through. Installations upgraded from an earlier version still hold the old containers and have to have them removed separately.
  • FixedA crafted private key file could make the library read outside its own memory, or hang forever. The length check in the PEM reader added two numbers that could overflow, so an impossible length passed as valid, and one shape of the same fault left a loop advancing by nothing at all, spinning at full CPU and allocating until the process died. One key file was enough, anywhere a key file is accepted, including the server setting and the command line client. Every real key file still loads, checked across RSA, EC, encrypted and unencrypted forms.
  • FixedServer: checking an administrator password wasted a quarter of a second, because the password derivation opened and closed a cryptographic provider two hundred thousand times, once per round. It opens one and reuses it now, taking the same check from 252 milliseconds to 8. Stored passwords are unchanged and nobody has to set a new one. The login page also had no limit on attempts, giving an attacker both unlimited guesses and an easy way to exhaust the machine, and it now locks an account or an address after five failures in five minutes. Every failed login takes the same time and returns the same page whatever the reason, so the limit cannot be used to discover which accounts exist.
  • FixedServer: two requests arriving at the same moment could be given the same temporary file name, and one request was then signed over the other request document. The name was built from the clock and a weak random number, and it now comes from a unique identifier, with the file created in a way that fails rather than overwrites if the name is somehow taken. Reproduced before the fix with eight threads, which collided.
  • Fixedsgcsign CLI: an option given without a value silently swallowed the option that followed it and the run reported success. Signing with --out followed by --verbose wrote the signature to a file called --verbose and exited with code 0, so a build pipeline was told the signing had worked while shipping an unsigned file. Every option taking a value now refuses one that looks like another option, and fails naming it. Two more paths that reported success on failure are fixed as well: an unrecognised hash name quietly fell back to SHA-256 while telling the server something different, and an empty reply from the server produced an empty output file, which with no --out given overwrote the file being signed.
  • FixedEvery outbound request the library makes could be used to exhaust the memory of the machine making it. The response body was read in a loop that appended until the server stopped sending, with no ceiling and no setting to impose one. That matters because a revocation list address and an issuer certificate address are read out of the certificate being checked, so an attacker who supplies a document chooses where those fetches go. A new maximum, 64 MB by default, is applied as the bytes arrive rather than after they have all been read, so an endless response is cut off rather than collected first. The number was chosen by measuring: the largest revocation list any public authority publishes is under 11 MB and the largest EU member state trusted list is under 6 MB. Set it to 0 for the old behaviour.
  • FixedA crafted signature container could make the library attempt an allocation of several gigabytes. Each entry declares how large it will be once decompressed, and that figure was believed and reserved before anything was read. A small file could therefore claim four gigabytes per entry. Decompression now grows its buffer as it goes and stops as soon as the real output passes a ceiling, and an entry whose declared size is already past it is refused before anything is reserved. The ceiling is generous, 256 MB per entry, and no legitimate container comes near it: the largest expansion measured across every sample in the tree is under 24 to 1 where the limit is 200 to 1.
  • FixedThe Authenticode hash covering a program file was computed wrongly for two layouts that occur in real software, so a validly signed file was reported as modified, and a file signed by sgcSign carried a hash Windows rejects. The trailing part of the file was located by adding up section sizes, which is only correct when the sections sit back to back. Programs built with the GNU linker leave a gap, and programs compressed with UPX overlap, so bytes were left out of the hash and others were counted twice. The file is now walked once from start to finish whatever its layout. Measured across 10,458 signed programs on one machine, 552 were affected. Anything already signed with one of those layouts has to be signed again.
  • FixedA certificate store entry that could not be read stopped the whole store being read. One unparseable entry abandoned the enumeration, so a trust store named in the configuration contributed nothing at all, and every verification then reported that no trusted chain could be built. The reason pointed at the certificate chain rather than at the store, which is where the real problem was. Unreadable entries are now skipped and the rest of the store is returned, and a new SkippedCertificates count tells an empty store apart from a store full of material the parser cannot read.
  • FixedSignatures made with an EC key declared the algorithm in a form the standard forbids. RFC 5758 requires the parameters field to be absent for the ECDSA algorithm identifiers, and PAdES, CAdES and the CMS format timestamp request all wrote an explicit NULL there. Authenticode and NuGet were corrected earlier in this release, so the product disagreed with itself. Files already signed with an EC key stay verifiable, because that field sits outside the signed data and never entered the hash, but they have to be signed again to conform for a verifier that enforces it.
  • FixedThe CSC key provider ignored every proxy, client certificate and TLS setting. It built its own HTTP request instead of using the shared transport the other providers use, so nothing set through HTTPOptions reached it and the interception event never fired. A customer behind a proxy, or one required to present a client certificate to their qualified authority, could not make it work and there was nothing in the API to say why. It now uses the same transport as every other provider. The bytes sent are unchanged apart from the user agent, which is now the product one and can be set.
  • FixedLicense tool: an option given without a value silently swallowed the option that followed it, and a license was issued against the wrong parameters with no error. The expiry date could end up set to the literal text of the next option. The tool now refuses a value that looks like another option and names the option that is missing one, understands the --option=value form, and examines the last argument on the line, which it previously ignored. A misspelled option, a stray argument and a non numeric limit are now errors rather than being dropped in silence.
  • FixedServer: the signing endpoints refused base64 in the shapes it usually arrives in. The URL safe alphabet that several qualified authorities return, a value wrapped across lines the way it appears in a PEM file or an XML document, and a value without padding were all rejected, although the library itself accepts all three. The endpoints now use the same decoder as the rest of the product. Nothing that was accepted before is refused now.
  • FixedCertificates: a malformed certificate could produce a public key fingerprint computed over the wrong bytes. The public key was taken from its usual position before that position had been checked to hold a key at all, so on a malformed certificate the extensions could be fingerprinted instead. The value looked entirely plausible and identified nothing, which matters because that fingerprint is what key pinning compares. Nothing is captured now unless it really is a public key.
  • FixedServer: when a webhook could not be delivered because the endpoint certificate could not be validated, the audit record and the console both reported it as a socket error, mentioning neither TLS nor a certificate nor which setting would fix it. Deliveries now report what actually failed, naming the certificate problem, the certificate itself, what it was checked against and the setting that resolves it.
  • FixedServer: a value saved through the console did not survive being read back. Text was written with JSON escaping and read without it, so a Windows path typed as C:\certs\ca.pem came back with its separators doubled, and any value holding a quotation mark, a tab or a line break was corrupted, a little further each time it was saved. Reading and writing now agree. A configuration file holding native Windows paths is repaired automatically on the first start after upgrading, with the original kept beside it.
  • FixedXAdES: a signature could be reported as valid without anything in it committing to which certificate signed it. The standard requires a signing certificate reference in the signed properties, and its absence was reported as a note rather than treated as a fault. A new RequireSigningCertificate setting makes it a fault. It is off by default, so nothing that verifies today changes unless you turn it on.
  • FixedRevocation lists published by a separate authority, which the standard permits and several government infrastructures use, could not be used at all, and neither could a list or an OCSP response signed with RSASSA-PSS. Both were reported as giving no answer rather than a wrong one, but the effect was that no revocation answer was available. Both now work, and PSS is understood for certificate chains as well. Ed25519 and the GOST algorithms are still not supported and still report that no answer is available.
  • FixedAuthenticode: a file whose digest algorithm the library does not implement was reported as having a hash mismatch, which says the file was modified. The truth was that it could not be checked at all, because any unrecognised algorithm was quietly treated as SHA-256 and a hash of the wrong size was compared. Such a file is now reported as using an unsupported algorithm, and the algorithm is named. Files affected in practice are old ones signed with MD5, which Windows also refuses.
  • FixedCatalog files could not be signed with a complete certificate chain. The option that attaches the intermediate certificates was only read by one of the two signing routes, and not by the one that handles .cat files, so a catalog signature could not chain up to the Microsoft Code Verification Root. It now works for catalogs as it already did for programs. Reported by a customer, thank you.
  • FixedCertificates attached to a signature were written in the order they were supplied rather than in the order the encoding rules require. Windows refused to read a catalog signed this way at all, reporting that it contained no signature, while the same certificates inside a program file were accepted. Any catalog signed with extra certificates by an earlier version has to be signed again. Signatures carrying no extra certificates are unchanged.
  • FixedServer: on the provider page, the name and kind of an existing provider were shown in boxes that looked editable but silently discarded anything typed into them. Both are deliberately fixed once a provider is created, because the name is what every API key permission, command line option and configuration entry uses to refer to it. They are now shown as plain values so that is visible before you spend time on it. The form for a new provider is unchanged. Reported by a customer, thank you.
  • FixedA timestamp request in the CMS signed format could carry a certificate set that is not valid DER. The signing certificate and its issuer were written in the order they were collected rather than in the order the encoding rules require, so an authority that checks strictly is entitled to reject the request. It affects a request made with SignOptions.IncludeChain turned on, a key provider that can resolve an issuer, which the PFX, Windows certificate store and PKCS#11 providers all can, and RequestFormat set to trfCMS, the signed format several qualified authorities ask for. The same ordering rule was corrected for signatures earlier in this release, but the timestamp client carried its own copy of the code and was missed. A request that carries a single certificate is unchanged, byte for byte.
  • FixedServer: the administrator login lockout counted failed attempts per source address, and behind a reverse proxy every administrator arrived from the same proxy address, so five failures from one attacker locked every administrator out for the whole lockout window. It counts against the real client address now, which needs server.firewall.forwarded_headers configured for the proxy in front.
  • FixedServer: the REST API read X-Forwarded-For by itself with no check on who sent it, so any client could write an address of its choosing into the audit trail and into the webhook payloads, while the administration pages ignored the header entirely and recorded the proxy address instead. Neither reads the header now. Both take the address the firewall resolved, which comes from the header only when the connection arrives from a configured trusted proxy.
  • FixedServer: the brute_force settings under server.firewall did nothing at all. The values were read from the configuration file, validated, applied to the firewall and shown in the administration console, and no failed attempt was ever reported to it, so no address was counted and none was ever banned. A server configured for brute-force protection has had none since the setting appeared in 2026.6.0. Failed administrator passwords and invalid API keys are now counted against the address they came from, a request carrying no key at all is deliberately not counted because an absent header is not a guess, and with server.firewall.forwarded_headers configured the ban falls on the client rather than on the proxy in front of it.
  • BreakingThere is now a single TsgcX509Certificate. The library declared three different classes under that name, and the one the certificate lists were built from was a small copy carrying ten fields, so reading anything else about a listed certificate meant parsing its raw data again through a different class of the same name. The lists returned by EnumerateCertificateList now hold the real certificate class, and TsgcX509CertificateList moved to sgcSign_X509 alongside it. Code that lists certificates needs sgcSign_X509 added to its uses clause, and in C++Builder the matching sgcSign_X509.hpp include. Reported by a customer, thank you.
  • BreakingASiC-E CAdES containers built by earlier versions carry no cryptographic link at all between the signature and the documents inside them. Every ds:DigestValue in META-INF/ASiCManifest.xml was written as an empty element, and the signature bytes were a parameter produced before the manifest existed, so anyone holding such a container can replace any document in it and repack the zip. The manifest now carries real base64 SHA-256 digests and an empty document name is refused. The old BuildCAdES that takes finished signature bytes still compiles, now marked deprecated, and still cannot produce a bound container, so callers producing ASiC-E have to move to the new overload that takes a signing callback. Containers already issued should be reissued.
  • BreakingTSA: a timestamp token is now accepted only when the signing certificate carries id-kp-timeStamping as a critical extended key usage, which is what RFC 3161 section 2.3 requires. An authority that marks it non critical will be refused where it was accepted before.
  • BreakingAn OCSP response or an RFC 3161 timestamp token signed with RSASSA-PSS is now refused rather than accepted, because the shared algorithm table used by the new checks does not cover PSS. It appeared to work before because nothing was being verified. Support for PSS in that table is tracked separately.
  • BreakingHashiCorp Vault: an ECDSA or Ed25519 transit key is now refused at Connect with a clear error, and only rsa- key types are accepted. Those keys were admitted before and then signed as if they were RSA, so a key that appeared to work was producing signatures no verifier accepts. Supporting them properly is a feature request rather than a fix.
  • BreakingKey providers: a credential typed into the Object Inspector is no longer written into the .dfm. Fourteen properties across eleven units are now marked as not stored, among them the AWS secret access key, the Azure client secret, the Google Cloud service account JSON, which carries the RSA private key itself, the Vault token, the CSC and Certum passwords, PINs and secrets, the PFX and PEM passwords, the PKCS#11 PIN and the proxy password. A design time value used to reach the .dfm in version control, the compiled executable as a plain text resource, and any crash dump. The properties stay visible in the Object Inspector and assignable from code, and an existing .dfm still loads, but the value it holds will disappear the next time the form is saved.
  • BreakingServer: the server.listen setting now binds the listener to the address you give it. It was parsed, defaulted, printed on the startup banner and never applied to anything, so a server configured to listen on 127.0.0.1 was in fact listening on every interface while the console said otherwise, and the whole network could reach /admin/login and the signing endpoints directly, skipping the reverse proxy and its client certificate check. A deployment that was quietly reachable from elsewhere becomes unreachable on upgrade, which is what the configuration was asking for. An address that is not a valid literal is now rejected at startup. The trial and community configuration files still say 0.0.0.0 with TLS disabled.
  • Breakingsgcsign CLI: the indy transport no longer connects without validating the server certificate. It never validated it. There was a branch for --insecure and a branch for --cacert and nothing in between, so the default accepted any certificate the far side offered and printed nothing, and since every request carries the API key in a header, anyone on the path collected a credential that authorises signing. The default path now looks for trust material in SSL_CERT_FILE and SSL_CERT_DIR, then for cacert.pem, ca-bundle.crt, ca-certificates.crt or curl-ca-bundle.crt beside the executable, then in the usual /etc/ssl and /etc/pki locations. When it finds nothing it raises an error naming --cacert and --insecure instead of connecting unvalidated, so on Windows --transport indy with no --cacert and no cacert.pem beside the executable now fails where it used to connect. WinHTTP, the transport chosen automatically on Windows, was never affected.
  • BreakingServer: every administration action that changes something now requires a form post carrying a one time token, and eleven of them that could be triggered by a plain link refuse one. Until now the only protection was a browser setting, so any page an administrator visited while logged in could delete an API key, change a user password or approve a pending signing request just by loading an address. Scripts that drove the console by fetching addresses such as /admin/users/delete?id=2 will stop working, and a script that posts to the console has to read the token out of the page first.
  • BreakingServer: webhook deliveries over HTTPS now check the certificate of the address they are sent to, and refuse to deliver when it cannot be validated. They never checked it and there was no way to turn checking on, so signing event data went to whoever could intercept the connection. A new verify_tls setting turns the check off for one webhook and a new ca_file names the authority for an internal endpoint. A list of public certificate authorities, cacert.pem, is now installed beside the server so this works without any configuration; on Windows there is usually no system list available to this check, and without that file deliveries to public addresses would stop as well. If you run the server from a copy you made yourself rather than from the installer, copy cacert.pem alongside it, or set SGCSIGN_WEBHOOK_CACERT. An endpoint whose certificate does not match the address it is reached at is now refused too.
  • BreakingServer: the max_upload_mb setting is now the real limit on how much a request can send, and it defaults to 64 MB. It was never applied to a request that did not declare its length up front, which any client can choose, and the underlying transport was imposing its own 64 MB limit regardless of what the setting said, so the setting was ignored in both directions. A server left on the default therefore accepts exactly what it accepted before. What changes is that a value you set yourself is now obeyed: if you had raised max_upload_mb above 64 and wondered why larger uploads were still refused, they now work.
  • Breakingsgcsign CLI: a value beginning with a dash can no longer be given after a space, because it cannot be told apart from a mistyped option. Write --option=value instead, or put the value after a bare --, which is now understood as the end of the options. In practice this affects the free text options only, such as --desc, --reason and --location.
  • BreakingXAdES: a signature whose signed properties are not covered by a reference carrying the type the standard defines is now invalid rather than valid. Signatures made by sgcSign have always carried it. A signature from another product that leaves the type attribute out, or that points at those properties in an unusual way, is now refused.
  • BreakingA revocation list signed with RSASSA-PSS, Ed25519 or a GOST algorithm is now reported as unusable rather than believed, because the table of algorithms these checks share does not cover them, and so is a list issued by a separate revocation authority rather than by the certificate own issuer, which the standard does permit. Neither gives a wrong answer, both report that no answer is available. The IsRevoked call that is given no issuing certificate now raises an error rather than answering "not revoked" for a list it has no way to check.
  • BreakingThe PFX key provider now keeps the private key in memory rather than in the Windows key store, on Windows 8 and later. Anything that expected to find the key in the user profile after signing, such as an external tool reading the key store, will no longer find it.
  • BreakingA response larger than 64 MB is now refused on every request the library makes, including timestamp, revocation, issuer certificate and EU trusted list downloads. Nothing published today comes close, the largest revocation list found anywhere is under 11 MB, but a deployment whose authority publishes something unusually large will need HTTPOptions.MaxResponseSize raised, or set to 0 for no limit at all.
  • BreakingA signature container entry that decompresses to more than 256 MB, or that expands by more than 200 to 1 above a floor of 1 MB, is now refused. The largest expansion measured across every sample in the tree is under 24 to 1, so no legitimate file is affected.
  • BreakingAuthenticode: a program with a section gap or an overlapping layout that was signed by an earlier version carries a hash Windows rejects, and has to be signed again. Programs built with the GNU linker and programs compressed with UPX are the two common cases. Verification of such files is now correct, so files that were wrongly reported as modified now verify.
  • BreakingCatalog files signed with extra certificates by an earlier version are not readable by Windows and have to be signed again. Signatures that carry no extra certificates are byte identical to before.
  • BreakingThe command line client now refuses --add-cert where it previously accepted it and quietly did nothing: with any format other than authenticode or catalog, and with authenticode in upload mode or with a provider chain. The signature was shipping without the certificates that were asked for, so this is now an error rather than a silent omission.
  • BreakingServer: a configuration file holding native Windows paths, such as a value written as C:\Users\name\cert.pem rather than with doubled separators, is repaired automatically on the first start after upgrading, and the original is kept beside it with a .pre-escape-migration.bak extension. Where a value is genuinely ambiguous the server refuses to start rather than guess, and names the file, the line and the fix. The realistic case is a path whose only escape is one of \b \f \n \r or \t, C:\temp being the obvious one.

sgcSign 2026.8.0

  • 2026.8.0: 2026 August
  • NewNew TsgcXMLDSigSigner component: signs XML with plain XML-DSig, no XAdES properties. One generic component driven entirely by configuration, so a signed SAML 2.0 assertion and a SOAP WS-Security message are two configurations of it rather than two different components.
  • NewSign any element by its ID attribute. The attribute name is configurable because it differs by standard: ID for SAML, wsu:Id for WS-Security, Id for XAdES. The signer can add it when the element does not have one.
  • NewSupport for the InclusiveNamespaces PrefixList of exclusive canonicalization, needed when a prefix appears only inside an attribute value such as xsi:type="xs:string". Without it the declaration is dropped and the digest changes, which is a common cause of a counterparty rejecting a signature.
  • NewSignature placement control: first or last child of any element, or immediately before or after a named sibling. SAML requires the signature between saml2:Issuer and saml2:Subject.
  • NewKeyInfo content is selectable: certificate, subject name, issuer and serial, RSA key value, or any combination.
  • NewTsgcDocumentSigner can produce plain XML-DSig, by setting Format to sfXMLDSig and configuring its XMLDSig property.
  • NewsgcSign Server: new /api/v1/sign/xmldsig endpoint with the same configuration as JSON, documented in the OpenAPI specification.
  • NewRSASSA-PSS signatures are now verified, covering the MGF1 forms and explicit PSS parameters. A variant that cannot be checked is reported as indeterminate with the reason. The German EU Trusted List now verifies.
  • NewDocuments carrying more than one signature are now fully verified, every signature checked.
  • Newsgcsign CLI: new WinHTTP transport, the default on Windows, which signs over HTTPS without any OpenSSL DLL. TLS 1.2 and 1.3 come from the operating system, trust comes from the Windows certificate store, and the system proxy settings are honoured. The new --transport option selects auto, winhttp or indy.
  • Newsgcsign CLI: new --openssl-api, --openssl-dir, --cacert and --tls-version options for the indy transport. --openssl-api defaults to auto, which probes OpenSSL 3.0, then 1.1, then 1.0, and uses the newest library that loads, so the client is no longer tied to OpenSSL 1.0.2. Each option also reads an environment variable: SGCSIGN_TRANSPORT, SGCSIGN_OPENSSL_API, SGCSIGN_OPENSSL_DIR, SGCSIGN_CACERT and SGCSIGN_TLS_VERSION.
  • NewsgcSign Server: new server.tls.provider setting, openssl or schannel. With schannel the HTTPS listener uses the Windows TLS stack and needs no OpenSSL DLL at all, taking either a PFX through cert_file and password, or a certificate already in the Windows store through cert_hash, cert_store_name and cert_store_path.
  • NewsgcSign Server: new server.tls.openssl_api setting, auto by default, which probes OpenSSL 3.0, then 1.1, then 1.0 and uses the newest library that loads. An explicit 1.0, 1.1 or 3.0 pins one generation. New server.tls.openssl_dir and server.tls.version_min settings, and the startup banner now reports the TLS provider and the API actually in use.
  • NewsgcSign Server: the TLS certificate password can be supplied through server.tls.password_env, which names an environment variable and takes precedence over the literal password key, matching how every other secret in the configuration file is handled.
  • FixedSecurity: a document with two or more signatures was reported as valid after checking only the first one. The enveloped-signature transform also removed the first signature in the document rather than the one being verified, and reused the first SignedInfo when checking any later signature.
  • FixedSecurity: a processing instruction whose target starts with "xml", such as the common xml-stylesheet, was discarded as if it were the XML declaration and left out of the digest, so it could be deleted or altered after signing while the signature still verified. Documents of that shape should be signed again.
  • FixedEU Trusted Lists and any document using xml:lang or another xml: attribute failed verification. The xml prefix is bound by the XML specification and never declared with xmlns, but was treated as undeclared, so canonicalization emitted a spurious xmlns:xml="" and sorted the attribute into the wrong group. Output now matches an independent implementation.
  • FixedSignature verification could be misled by a decoy. The signature was located with a plain text search, so something resembling a signature inside a comment, CDATA section, processing instruction or DOCTYPE internal subset could capture it, or capture a reference by its Id.
  • FixedCanonicalization emitted a line break for a comment before the root element even under a method that strips comments and produces no output for it, so signatures over such documents did not match what a conforming verifier computed.
  • FixedDocuments starting with a UTF-8 byte order mark failed to parse, so verification failed on signatures that were perfectly sound.
  • FixedSigning failed on a document with a comment, processing instruction or DOCTYPE before the root element, and a DOCTYPE with an internal subset failed to parse. With a signature parent element configured, a prolog comment containing text resembling a closing tag could place the signature inside that comment.
  • FixedSignatures referencing an element by its ID, and the SignedInfo element, are now canonicalized with the namespaces inherited from their ancestors, as the specification requires. Signatures made by earlier versions under an inclusive canonicalization profile are still accepted and reported as such, so they stay usable while telling you to sign again; the new TsgcSignatureVerifier.StrictCanonicalization property turns that acceptance off. The reference covering your document is always verified strictly.
  • FixedEU Trusted Lists were being damaged by our own downloader, which moved these signed documents as text and re-encoded them on the way to the cache, changing bytes and breaking the signature. They are now carried as bytes end to end, and a document that is not valid UTF-8 is reported as an error instead of being guessed. A list cached by an earlier version may already be damaged, so refresh the cache once after updating.
  • FixedDemos: a certificate provider could be released while an interface pointing at it was still alive, which could crash the demo. The Authenticode, ClickOnce, NuGet and VSIX demos leaked a provider on every signing operation, and EU_Employment reported its own containers as invalid by passing the whole signature file, envelope included, to the verifier.
  • FixedPFX certificates: fixed an error when signing on 64-bit Windows with a certificate that uses a modern CNG private key. Signing could fail with "NCryptSignHash failed: NTSTATUS=$200000000" even though the certificate and the password were correct. The signature was in fact created correctly, the problem was the check on the result, so nothing signed before the error appeared was affected. 32-bit applications were never affected.
  • Fixedsgcsign CLI: signing over HTTPS could fail with "server unreachable: server closed the connection without sending a response (server-side error)" when the fault was entirely on the client. Every OpenSSL failure, including being unable to load the library at all, was reported as a server error, which sent users looking at a server that was working correctly. Client side TLS failures are now reported as TLS errors, naming the libraries that were tried and the bitness of the process, and exit with the new code 7.
  • Fixedsgcsign CLI: the client could only load the OpenSSL 1.0 API, so it required libeay32.dll and ssleay32.dll and could not use OpenSSL 1.1 or 3.x. The server had the same restriction. Both now select the API generation, and both default to detecting the newest one available.
  • Fixedsgcsign CLI: the TLS connection offered SSL 2.0 and SSL 3.0 alongside the TLS versions. Only TLS 1.0 through 1.3 are offered now, and --tls-version raises the minimum.
  • FixedDocumentation: the technical guide stated that the server accepted the OpenSSL 1.1 and 3.x library names. That was never true, the server always loaded the OpenSSL 1.0 API. The guide now documents the TLS provider settings, the CLI TLS options and the full list of CLI exit codes.
  • FixedPAdES: signing never finished. It hung at 100% CPU on any PDF, because two loops that copy bytes out of the document never advanced their index and so kept reading the same byte. The first reads the document Catalog dictionary and runs on every signature, which is why no PDF could be signed. The second reads an object number and runs when the Catalog cannot be read from a classic trailer, as in PDFs that use a cross-reference stream, and on every visible signature to locate the page object; that one also grew a string on each pass, so it ended in an out of memory rather than only spinning. The .NET implementation was never affected, it uses counted loops in both places. Reported by a customer with a sample PDF, thank you.

sgcSign 2026.7.0

  • 2026.7.0: 2026 July
  • NewKSeF bulk client: a "save now, decrypt later" workflow. You can save a pack's encryption key and IV to a small JSON file, save the downloaded encrypted parts as one .zip.aes file, and later decrypt and unzip that saved file using the JSON key, all without a live order or bearer token.
  • NewKSeF bulk demo: new "Save Pack + Keys" button (writes the .zip.aes plus a .keys.json) and a "Decrypt Saved Pack..." button that picks the .aes, finds its matching .json automatically, then decrypts and extracts it.
  • NewCertificate decoder (X.509): now exposes the full set of fields you would see in an online certificate decoder, including key size, friendly public-key and signature algorithm names, the serial number in colon and decimal forms, certificate policies, subject and authority key identifiers, the issuer name sub-fields, MD5/SHA-1/SHA-256 thumbprints, and the SubjectPublicKeyInfo (SPKI) SHA-256 pin. A new helper turns common OIDs into readable names.
  • NewNew CertificateInfo demo: loads a certificate from PEM, Base64, DER or a file and shows every field grouped like a certificate decoder, then runs an OCSP revocation check that finds the responder URL from the certificate itself.
  • NewCertificate issuer checking with real cryptographic verification: new methods confirm a certificate was actually signed by a candidate issuer (RSA and ECDSA) and match the issuer name and key identifiers. The CA-issuer and OCSP URLs are now available separately, and the CertificateInfo demo can verify the issuer and auto-load the issuing CA before the OCSP check.
  • NewCertificate names in LDAP form: new properties show the Subject and Issuer names in RFC 2253 / RFC 4514 (LDAP) style (CN first, comma-separated), alongside the existing X.500 order, so it is easy to compare a certificate name against tools and XML that use the LDAP string form.
  • NewPKCS#12 (.p12 / .pfx) support: the certificate class can now load a certificate straight from a password-protected .p12 or .pfx file, and save a certificate to a password-protected .p12. If the file contains several certificates, the main certificate is loaded and the remaining CA certificates are available separately. The PFX and PEM key providers can now also save the certificate together with its private key to a password-protected .p12, which means a PEM certificate and key can be converted into a .pfx.
  • NewXAdES B-LT and B-LTA signature levels: the signer can now embed the full validation material (all certificates plus the timestamp authority's chain) and revocation data (CRLs and OCSP responses), and B-LTA adds an archive timestamp for long-term validity. New properties for the OCSP client, extra certificates and CRL files on both signers; the EU qualified profile now produces genuine XAdES-B-LTA, and outputs validate as BASELINE-T/-LT/-LTA on the EU DSS validator. The XAdES demo gained B-LT and B-LTA variants.
  • NewTicketBAI per-province profiles for Araba, Bizkaia and Gipuzkoa, each with its tax authority's official signature policy (Gipuzkoa policy v1.2). The original combined profile keeps the Bizkaia values for backward compatibility. Bizkaia signatures were validated end to end against the official Batuz/LROE test environment (accepted as "Correcto", with a tampered signature correctly rejected). The TicketBAI demo gained a province selector.
  • NewPortugal SAF-T (Portaria 363/2010) invoice signing: a new signer produces the required RSA-SHA1 signature over the invoice fields, exposes the four printable characters carried on the invoice and in the QR code, and was verified against the official worked example. The SAF-T PT demo gained a signing panel.
  • FixedZIP extraction now does a proper raw inflate on XE2 and later, instead of wrapping the data in a fake zlib stream with a placeholder checksum that newer zlib rejected with "data error". This affects every ZIP extraction path (ASiC, KSeF bulk export); the older D7..DXE path is unchanged.
  • FixedKSeF bulk client: HTTP errors now include the server's response text (shown as "HTTP - <body>", trimmed), so a 400 or 403 shows the KSeF explanation instead of just the status code.
  • FixedKSeF bulk client: the bearer token is no longer attached when downloading pre-signed part URLs. KSeF serves the parts from Azure storage authenticated by the query-string signature, so sending the Authorization header made Azure reject the download with 403. The token is now dropped whenever the part URL has a query string.
  • FixedKSeF bulk client: responses are now read as UTF-8, so Polish characters in status messages display correctly instead of garbled text.
  • FixedKSeF bulk demo: a not-yet-downloaded part now shows "Ready" once the export is complete, instead of the confusing "Pending".
  • FixedKSeF bulk demo: on an HTTP error the log now shows the status line, all response headers and the body, so even body-less gateway rejections (401/403) show a reason and validation errors (400) show their message.
  • FixedKSeF bulk demo: when an export finishes with no parts, the log now explains that no invoices matched the chosen date range, subject type or date type, instead of a later bare "No parts to download".
  • FixedKSeF bulk demo: the date range now defaults to the current month on startup, which stays within the KSeF 3-month export limit, instead of a fixed past month.
  • FixedVeriFactu profile: corrected the signature policy. It referenced the Facturae policy with a SHA-1-length digest labelled as SHA-256, which strict validators reject; it now uses the Spanish AGE policy with its official SHA-1 digest and inclusive canonicalization, per Orden HAC/1177/2024.
  • FixedTicketBAI profile: fixed a malformed policy URL and a corrupted policy digest; it now carries the official Bizkaia v1.0 policy identifier and SHA-256 digest.
  • FixedFatturaPA profile: removed the signature policy reference. Italy's SDI accepts plain CAdES-BES or XAdES-BES signatures with no policy, so the profile now emits pure XAdES-BES.
  • FixedFiskalizacija profile: updated to Fiskalizacija 2.0 (the eRacun channel, in force since January 2026): RSA-SHA256 with exclusive canonicalization. The old cash-register channel used RSA-SHA1 with the ZKI code and is a separate mechanism.
  • FixedSignature profiles now have a single source of truth: one configuration holds every profile's values and both the signer and the server admin dashboard read from it, so they can no longer drift apart.
  • FixedEnveloping XAdES signatures are now verifiable by outside validators. The embedded object's digest is now computed over the canonicalized element with an explicit transform declared (instead of over raw bytes), and the reference now carries the matching Id, so it no longer dangles.
  • FixedThe XAdES signature-timestamp imprint is now spec-correct at every level: the hash is taken over the canonicalized signature-value element (with the canonicalization method declared) instead of the raw Base64 text, so timestamps pass strict verification such as the EU DSS.
  • BreakingSigning at the B-LT or B-LTA level now raises a clear error when no timestamp authority is set, or no revocation source (OCSP client or CRL files) is available, instead of quietly producing a lower level. This affects the EU qualified profile and the B-LT employment profiles (DE/IT/AT/BE/PT); the EU_Employment demo and console generator ship wired with a TSA and the new test CA material.

sgcSign 2026.6.0

  • 2026.6.0: 2026 June
  • NewNew sgcSign Server: self-hosted REST signing server (TsgcSignServer) that signs executables and documents remotely over a TLS HTTP API. Signs Authenticode PE files (exe/dll/sys/msi/cab/ocx, optional dual SHA-1 + SHA-256), PDF (PAdES), XML (XAdES, with country e-invoicing profiles), CAdES (detached PKCS#7), ClickOnce manifests, NuGet packages, VSIX extensions and PowerShell scripts, all with optional RFC 3161 timestamping, plus a signature verify endpoint.
  • NewsgcSign Server: pluggable key providers selected per request: Windows Certificate Store, PFX, PEM, PKCS#11 / HSM (YubiKey), AWS KMS, Azure Trusted Signing, Google Cloud KMS, HashiCorp Vault and Certum SimplySign; passwords, PINs and cloud secrets are read from environment variables instead of the config file.
  • NewsgcSign Server: browser admin console (dashboard, API keys, providers, users, projects, audit), API-key authentication with per-key rate limits and daily quotas, multi-tenant projects, optional sign-approval workflow, tamper-evident hash-chained audit log, Prometheus metrics, outbound webhooks and an OpenAPI 3.1 document with built-in Swagger UI.
  • NewsgcSign Server: runs as a Windows service or console application, configured by a single JSON file (sgcSignServer.conf.json) with a built-in firewall (IP allow/deny, brute-force and rate limiting), TLS with optional ACME / Let's Encrypt challenge serving, and SQLite storage. New command-line client "sgcsign" (sign, verify, keys, health) talks to the server with --server / --apikey and supports Authenticode pre-hash (--prehash), so CI agents upload a hash instead of the whole binary.
  • NewTsgcKSeFBulkClient: bulk-invoice-export pipeline (sgcSign_KSeF_Bulk), 4-step async-init
  • NewNew demo KSeFBulk: standalone VCL, all design-time controls
  • NewTsgcPAdESSigner.VisibleSignature: on-page visible signature appearance (Form XObject renders signer name, reason, location and signing date), wires the widget /AP /N and the page /Annots; active when VisibleSignature.Enabled is True
  • FixedTsgcKSeFCrypto.RSAOAEPEncryptWithCert: non-RSA cert early rejection w/ clear OID error
  • FixedTsgcPAdESSigner: signed PDFs are now linked into the document AcroForm (Catalog /Fields + /SigFlags 3) so Adobe Acrobat and other viewers detect the signature. Previous versions wrote a cryptographically valid signature that no viewer displayed, because the incremental update never re-emitted the /Root catalog with an /AcroForm. The signer now parses the real /Root, merges or creates the AcroForm, wires the signature field, and builds a multi-subsection xref.

sgcSign 2026.5.0

  • 2026.5.0: 2026 May
  • NewTsgcAuthenticodeSigner: Microsoft Authenticode signer for Windows PE files (.exe, .dll, .sys) with SHA-1/256/384/512, RFC3161 timestamps and nested signatures.
  • NewTsgcAuthenticodeVerifier: Authenticode signature verification for Windows PE files.
  • NewTsgcCMSBuilder: shared CMS/PKCS#7 builder used by CAdES, PAdES and Authenticode signers.
  • NeweIDAS / EU compliance pack: new sgcSign_ASiC (ASiC-S/E containers per ETSI EN 319 162-1), sgcSign_TrustList (LOTL/EUTL fetch + cache + IsQualifiedAtTime, ~3600 services across 31 MS), sgcSign_KeyProvider_CSC (Cloud Signature Consortium v2 client for remote QTSPs); 9 country employment profiles spEmploymentDE/IT/ES/FR/PL/AT/BE/PT/NL pre-tuned per member-state labour law.
  • NewNew demo EU_Employment showing the new features.
  • NewsgcSign Server: self-hosted remote code-signing daemon (sgcSignServer.exe, console + Windows service) exposing the full signing engine over a REST API and a Bootstrap web admin console; FireDAC/SQLite storage, PBKDF2-SHA256 admin passwords and API-key auth, SHA-256 hash-chained audit log, thread-safe per-provider sign dispatcher and 9 supported provider kinds (WinCertStore, PFX, PEM, PKCS#11, AWS KMS, Azure Trusted Signing, Google Cloud KMS, HashiCorp Vault, Certum); requires Delphi 10 Seattle or newer.
  • Newsgcsign command-line client and esegece.sgcSign.Client .NET SDK (netstandard2.0 / net6.0 / net8.0 / net9.0), plus esegece.sgcsign .NET global tool, with sign / verify / keys / health verbs and a shared exit-code contract.
  • NewHash-only Authenticode signing: new POST /api/v1/sign/authenticode/hash endpoint accepts a precomputed PE hash and returns the unattached PKCS#7 SignedData blob for local embedding by the client; sgcsign sign --prehash (Delphi CLI) and TsgcSignClient.SignAuthenticodeHashAsync (.NET SDK) round-trip a 32-byte hash instead of the full binary, dropping multi-megabyte uploads to a few KB on bandwidth-constrained CI agents.
  • NewTsgcClickOnceSigner: ClickOnce / VSTO manifest signer (.application / .exe.manifest) using enveloped W3C XML-DSig per Microsoft mage.exe spec.
  • NewTsgcNuGetSigner: NuGet author package signer (.nupkg) producing PKCS#7 SignedData with optional RFC3161 timestamp.
  • NewTsgcVSIXSigner: VSIX (Open Packaging Convention) digital signature signer with per-part XML-DSig references.
  • NewCI/CD integrations: GitHub Actions composite Action, Azure DevOps native task, Jenkins pipeline DSL, Windows Server Core Dockerfile + docker-compose, Helm chart.
  • NewsgcSign_QRCode unit: pure-Pascal QR Code generator per ISO/IEC 18004, byte mode, all four ECC levels, versions 1-40, GF(256) Reed-Solomon, full mask-penalty scoring, TBitmap renderer; published GenerateQRCode + RenderQRMatrix + GetAlignmentPositions.
  • NewKSeF demo: Online vs Offline mode tabs.
  • NewTsgcPEMKeyProvider: ECDSA P-256/P-384/P-521 support via BCrypt CNG (BCryptImportKeyPair with ECCPRIVATEBLOB, raw r||s SignData output for XML-DSig); new SignDataPSS method (BCryptSignHash + BCRYPT_PAD_PSS, SHA-256, salt=32) for RSA-PSS signatures.
  • NewTsgcSignatureVerifier: ECDSA signature verification (ImportECDSAPublicKey from BCRYPT_ECCPUBLIC_BLOB + VerifyECDSASignature) for curves P-256/P-384/P-521 in both VerifySignatureValue (XAdES) and VerifyData code paths.
  • NewTsgcX509Certificate: KeyUsage extension parsed and exposed via KeyUsage property + HasKeyUsageDigitalSignature / HasKeyUsageNonRepudiation helpers; new PublicKeyParameters property exposes the raw AlgorithmIdentifier parameters TLV (named-curve OID for EC certs, used by the verifier to import EC public keys).
  • NewTsgcProfilePeppolBG: new Bulgarian Peppol BIS Billing 3.0 signature profile (XAdES B-T, SHA-256, exclusive C14N, timestamp on); spPeppolBG enum value, server admin profiles grid entry "Peppol BG / Bulgaria", Server REST string mapping peppolbg / peppol_bg, Delphi and C++Builder demos signing a Bulgarian UBL 2.1 Invoice (BGN, 20% VAT, BG VAT/EIK, BG IBAN, schemeID 9926 endpoint).
  • FixedTsgcPEMKeyProvider hardened end-to-end: Unicode ReadFileContent fix, two-step PKCS#8 decode, AT_KEYEXCHANGE keyspec, GUID-suffixed CSP container, native encrypted PKCS#8 (PBES2/PBKDF2/AES-CBC) via BCrypt, LoadCertificateOnly + EC marker recognition.
  • FixedTsgcXAdESSigner KSeF/ETSI conformance: V1 SigningCertificate wrapper, conditional SignaturePolicyIdentifier emission, decimal X509SerialNumber, SignedProperties built once (clock-race fix), explicit exc-c14n Transforms on SignedProperties Reference, new SignatureParentElement property; TsgcSignatureVerifier now resolves URI=#<Id> by element-Id lookup.
  • FixedTsgcPFXKeyProvider supports modern P12s: PKCS12_PREFER_CNG_KSP + multi-cert iterate-and-probe + two-stage acquire (ONLY_NCRYPT then PREFER_NCRYPT), CNG signing via NCryptSignHash. Design-time component linkage gains Notification(opRemove) auto-clear across all 9 signer/verifier components. KSeF demo migrated to FA(3) and PEM provider.
  • FixedTsgcX509Certificate ParseExtensions: the X.509v3 [3] EXPLICIT Extensions tag content was being double-wrapped before parsing, causing KeyUsage, ExtendedKeyUsage, AIA, CDP, SubjectAltName and BasicConstraints to be silently skipped on every certificate.
  • FixedBuild hygiene: W1000 (UTF8Decode deprecated) in sgcSign_ASiC fixed via {$IFDEF UNICODE} UTF8ToString fallback; H2077 (vTailLen unused) in sgcSign_XAdES; H2219 dead-code symbols BuildQualifyingProperties (sgcSign_XAdES) and ExtractAttribute (sgcSign_TrustList) removed.
  • FixedTsgcSignatureVerifier: ExtractFullElement now handles XML self-closing tags (<ds:DigestMethod Algorithm=".../sha1"/> etc.). Previous versions returned an empty string, causing URIToHashAlgorithm to default to SHA-256; FacturaeB2B (SHA-1) verification then reported "Digest length mismatch for Reference 0".
  • FixedTsgcSignatureVerifier: applies implicit Inclusive C14N to fragment / empty-URI references that omit an explicit C14N transform, per XML-DSig section 4.3.3.2. Fixes "Digest value mismatch" on the KeyInfo and body references in inclusive-C14N profiles (FacturaeB2B).
  • NewTsgcDocumentSigner: high-level facade now properly produces XAdES for AdES profiles. Internally delegates to TsgcXAdESSigner for the sfXAdES path; raises a clear error for sfPAdES/sfCAdES (use TsgcPAdESSigner / TsgcCAdESSigner). Added published Format: TsgcSignatureFormat property (default sfXAdES). Previous versions emitted plain XML-DSig regardless of profile, which national e-invoicing services rejected.
  • NewTsgcPFXKeyProvider: new published HashAlgorithm property (default haSHA256). TsgcXAdESSigner now pushes the active profile's hash into PFX providers, so FacturaeB2B-signed PFX-backed invoices are RSA-SHA1 as the profile requires; previous versions hardcoded SHA-256 in the PFX path and FACe rejected with INVALID_INVOICE-122 "los datos de la firma no son correctos".
  • NewWideString overloads on the public signing/verification API: TsgcXAdESSigner.SignXML/SignXMLDetached/SignXMLEnveloping, TsgcDocumentSigner.SignXML/SignXMLDetached/SignXMLEnveloping, TsgcSignatureVerifier.Verify. Lossless Unicode in/out on Delphi 7 (no ACP step); equivalent to the string overloads on Delphi 2009+. Recommended for callers passing non-ACP text such as Polish characters.

sgcSign 2026.4.0

  • 2026.4.0: 2026 April
  • NewTsgcDocumentSigner: high-level document signing component supporting XAdES, CAdES and PAdES formats.
  • NewTsgcXAdESSigner: XAdES XML Advanced Electronic Signature implementation.
  • NewTsgcCAdESSigner: CAdES CMS Advanced Electronic Signature implementation.
  • NewTsgcPAdESSigner: PAdES PDF Advanced Electronic Signature implementation.
  • NewTsgcSignatureVerifier: signature verification component.
  • NewTsgcXMLDSigEngine: XML Digital Signature engine.
  • NewTsgcC14NEngine: XML Canonicalization engine.
  • NewTsgcHashProvider: hash computation component.
  • NewTsgcTSAClient: Timestamp Authority client.
  • NewTsgcOCSPClient: OCSP certificate status verification client.
  • NewTsgcCRLCache: Certificate Revocation List cache.
  • NewTsgcX509Certificate: X.509 certificate handling.
  • NewTsgcASN1Parser: ASN.1 structure parser.
  • NewTsgcWindowsCertStoreProvider: Windows Certificate Store key provider.
  • NewTsgcPFXKeyProvider: PFX/PKCS#12 file key provider.
  • NewTsgcPEMKeyProvider: PEM file key provider.
  • NewTsgcPKCS11Provider: PKCS#11 hardware token key provider.
  • NewTsgcAWSKMSKeyProvider: AWS Key Management Service key provider.
  • NewTsgcAzureTrustedSigningProvider: Azure Trusted Signing key provider.
  • NewTsgcGCloudKMSKeyProvider: Google Cloud KMS key provider.
  • NewTsgcCertumSimplySignProvider: Certum SimplySign key provider.
  • NewTsgcHashiCorpVaultKeyProvider: HashiCorp Vault key provider.
  • NewTsgcProfileVeriFactu: Spanish VeriFactu e-invoicing profile.
  • NewTsgcProfileTicketBAI: Basque Country TicketBAI e-invoicing profile.
  • NewTsgcProfileFacturaeB2B: Spanish FacturaE B2B profile.
  • NewTsgcProfileEIDAS: eIDAS qualified electronic signature profile.
  • NewTsgcProfileFatturaPA: Italian FatturaPA e-invoicing profile.
  • NewTsgcProfileSAFTPT: Portuguese SAF-T e-invoicing profile.
  • NewTsgcProfileKSeF: Polish KSeF e-invoicing profile.
  • NewTsgcProfileFacturX: French Factur-X e-invoicing profile.
  • NewTsgcProfileEFactura: Romanian eFactura e-invoicing profile.
  • NewTsgcProfileNAVOnline: Hungarian NAV Online e-invoicing profile.
  • NewTsgcProfileFiskalizacija: Croatian Fiskalizacija e-invoicing profile.
  • NewTsgcProfilePeppolBE: Belgian Peppol e-invoicing profile.
  • NewTsgcProfileMyDATA: Greek myDATA e-invoicing profile.

Get the current release

Every licence includes a year of updates, and the trial is the full product.