<developers/>

How StackRegent release signatures are checked

Every StackRegent package is signed with the StackRegent release key and checked for size, SHA-256 and signature before anything is installed. Here is exactly what is signed and how to check it yourself.

Last changed 13 Nov 2026

What a StackRegent release signature covers#

A control panel runs with administrator rights, so an altered update would be as bad as a break-in. StackRegent therefore installs a package only when it is exactly the one that was published. Each release is described by three values and a signature:

ValueExample
Version0.17.15
SHA-256 of the package zip, lower-case hex64 hex characters
Size of the package zip in bytes48211234
SignatureBase64 of a DER-encoded ECDSA signature

The signature is made over this statement, five lines joined by line feeds, with no line feed at the end:

cil-release-v1
stackregent
VERSION
SHA256
SIZE

The algorithm is ECDSA on the NIST P-256 curve with SHA-256. Because the statement contains the package's SHA-256 and size, signing the statement signs the package: change one byte of the zip and its SHA-256 no longer matches the signed one. The version is signed too, so an old package cannot be passed off as a new one.

The StackRegent release key#

The public half of the release key is built into every copy of the panel and printed in the install script. The private half stays with the publisher, offline.

-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0u2k1eyugnpAAJKRNsXBES085JgL
ZU2SRHlVKci5/yTzOnN0kBzFijAs84XLprRmo/AZE3oNjwYs3ljYhoshnA==
-----END PUBLIC KEY-----

Its key ID is 4kybuaOI7rGnp0qC. The key ID is the first 16 characters of the URL-safe Base64 (without padding) of the SHA-256 of the key's DER encoding, so you can recompute it from the key above. The panel shows the same ID under Tools & Settings › Updates next to Comes from.

How the panel verifies an update#

Updates come only from the license server and only while the license is in order. When the panel checks for updates (daily, or when you click Check now under Tools & Settings › Updates):

  1. It asks the license server for the releases offered to this server's license, on the stable or beta channel chosen in Update Settings.
  2. It ignores releases that are not newer than the installed version.
  3. For the newest one, it checks that the size is above zero and at most 1 GiB, that the SHA-256 has 64 hex characters, that the version has the expected form, and that the signature verifies with the built-in release key. A release that fails is reported as an error, not offered.
  4. The Updates page then shows the release as signature verified.

When you click Install, or automatic updates run at night, the panel:

  1. Asks the license server again, because download addresses are valid for 15 minutes only, and repeats every check above.
  2. Downloads the package only from the license server's own address, refusing redirects, and computes the size and SHA-256 while downloading. A mismatch deletes the file.
  3. Checks the file on disk once more right before opening it.
  4. Unpacks it, refusing any entry whose path would leave the update folder, and requires an install.ps1.
  5. Starts install.ps1 as a one-time scheduled task named StackRegent Update under SYSTEM, writing its output to install-VERSION.log in the update folder of the installation.

The task log says Size, SHA-256 and release signature verified before anything is unpacked.

How the install script verifies a fresh install#

The install script makes the same checks before it installs anything. It activates the license, asks for the newest stable release, checks the version form, that the download address is on the license server, and the size and SHA-256 form, downloads without redirects, compares the size and SHA-256 of the file, and verifies the signature with the release key printed at the top of the script. It works on the .NET Framework of every supported Windows Server version, including the .NET 4.6 that Windows Server 2016 ships with. If any check fails, it stops with an error and nothing is installed.

Verify a package yourself#

You do not need to do this for normal updates; the panel does it. It is useful when you keep packages in your own software repository, audit a server, or want to see the mechanism work.

Step 1: Get a verified package and its release data#

The simplest way is -DownloadOnly, which runs every check above and keeps the files:

[Net.ServicePointManager]::SecurityProtocol='Tls12'; & ([scriptblock]::Create((New-Object Net.WebClient).DownloadString('https://panel.stackregent.com/get/stackregent.ps1'))) -LicenseKey SR-XXXXX-XXXXX-XXXXX-XXXXX -DownloadOnly

The package is left as release.zip in a stackregent-get-... folder under %TEMP%, next to the unpacked release.

To check the signature independently, you also need the version, SHA-256, size and signature as the license server announces them. On the licensed server, this asks for them the same way the install script does:

[Net.ServicePointManager]::SecurityProtocol = 'Tls12'
$key = 'SR-XXXXX-XXXXX-XXXXX-XXXXX'
$raw = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Cryptography' -Name MachineGuid).MachineGuid
$sha = [Security.Cryptography.SHA256]::Create()
$machine = -join ($sha.ComputeHash([Text.Encoding]::UTF8.GetBytes("cil-machine`nstackregent`n" + $raw.Trim())) | ForEach-Object { $_.ToString('x2') })
$body = @{ key = $key; product = 'stackregent'; machine = $machine; channel = 'stable'; current = '0' } | ConvertTo-Json -Compress
$rel = Invoke-RestMethod -Method Post -Uri 'https://panel.stackregent.com/license/v2/releases' -Body $body -ContentType 'application/json'
$r = @($rel.releases)[0]
$r | Select-Object version, size, sha256, signature

The SHA-256 of a release is also listed in the release notes when the store publishes it.

Step 2: Check the size and SHA-256#

$zip = (Get-ChildItem "$env:TEMP\stackregent-get-*\release.zip" | Sort-Object LastWriteTime | Select-Object -Last 1).FullName
(Get-Item $zip).Length                                     # must equal $r.size
(Get-FileHash $zip -Algorithm SHA256).Hash.ToLowerInvariant()   # must equal $r.sha256

Step 3: Verify the signature with OpenSSL#

Save the public key above as stackregent-release.pem. Then, with the values from step 1 (in a Unix-like shell, Git Bash or WSL):

# the key ID must print 4kybuaOI7rGnp0qC
openssl pkey -pubin -in stackregent-release.pem -outform DER | openssl dgst -sha256 -binary | openssl base64 | tr '+/' '-_' | cut -c1-16

# the signed statement, without a final line feed
printf 'cil-release-v1\nstackregent\n%s\n%s\n%s' "$VERSION" "$SHA256" "$SIZE" > statement.txt

# the signature from Base64 to DER
printf '%s' "$SIGNATURE" | openssl base64 -d -A > signature.der

openssl dgst -sha256 -verify stackregent-release.pem -signature signature.der statement.txt

The last command prints Verified OK for a genuine release and Verification failure for anything else. Use the lower-case SHA-256 and the size in bytes exactly as announced.

Step 3 (alternative): Verify the signature in PowerShell#

This uses the same method as the install script and works in Windows PowerShell 5.1 on .NET Framework 4.7 or later. .NET expects the signature as the two 32-byte numbers r and s side by side, so the DER signature is unpacked first:

$spki = [Convert]::FromBase64String('MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0u2k1eyugnpAAJKRNsXBES085JgLZU2SRHlVKci5/yTzOnN0kBzFijAs84XLprRmo/AZE3oNjwYs3ljYhoshnA==')
$q = $spki[($spki.Length - 64)..($spki.Length - 1)]          # X and Y of the public point
$der = [Convert]::FromBase64String($r.signature)
$i = 2; if ($der[1] -band 0x80) { $i = 2 + ($der[1] -band 0x7f) }
$parts = @()
foreach ($n in 1..2) {
    $len = $der[$i + 1]; $v = $der[($i + 2)..($i + 1 + $len)]; $i += 2 + $len
    while ($v.Length -gt 32 -and $v[0] -eq 0) { $v = $v[1..($v.Length - 1)] }
    $parts += , ([byte[]](@(0) * (32 - $v.Length) + $v))
}
$sig = [byte[]]($parts[0] + $parts[1])
$p = New-Object Security.Cryptography.ECParameters
$p.Curve = [Security.Cryptography.ECCurve]::CreateFromValue('1.2.840.10045.3.1.7')
$pt = New-Object Security.Cryptography.ECPoint; $pt.X = [byte[]]$q[0..31]; $pt.Y = [byte[]]$q[32..63]; $p.Q = $pt
$ec = [Security.Cryptography.ECDsa]::Create($p)
$statement = "cil-release-v1`nstackregent`n$($r.version)`n$($r.sha256.ToLowerInvariant())`n$($r.size)"
$ec.VerifyData([Text.Encoding]::UTF8.GetBytes($statement), $sig, [Security.Cryptography.HashAlgorithmName]::SHA256)

True means the release is signed with the StackRegent release key.

What signatures do not cover#

  • Hosting components such as PHP, MariaDB or Web Deploy come from their own publishers. Server Components checks them with their published checksums or Microsoft signatures, not with the StackRegent release key.
  • The install script itself is fetched over HTTPS from panel.stackregent.com and carries the release key; it is not separately signed. If you want to review it before running it, download it, read it, and run the saved copy.
  • TLS protects the connection to the license server. The release signature is a second layer: even a package served from the right address is refused if its signature does not match.

If a signature check ever fails on a package you received from StackRegent, do not install it by other means. Report it privately to support@stackregent.com, or through the security contact form. More on how StackRegent handles security is on the security page.

Frequently asked questions

Are StackRegent updates signed?

Yes. Every release is signed with the StackRegent release key using ECDSA P-256 and SHA-256. The panel and the install script check the package's size, SHA-256 and signature before installing anything.

What is the StackRegent release key ID?

4kybuaOI7rGnp0qC. It is shown under Tools & Settings › Updates and can be recomputed from the public key printed on this page.

What happens if an update fails the signature check?

It is not installed. The update task reports the error, and the installed version keeps running unchanged.

Can I verify a StackRegent package with OpenSSL?

Yes. Rebuild the signed statement from the version, SHA-256 and size, decode the Base64 signature to DER, and run openssl dgst -sha256 -verify with the release key. The steps are above.

Where do StackRegent updates download from?

Only from the license server at panel.stackregent.com, and only while the license is in order. The panel refuses packages from any other address and does not follow redirects.

Can an older version be installed as an update?

No. The panel installs a release only when its signed version number is newer than the installed one.