Qualified Timestamping in PowerShell (.NET Integration)
Learn how to request and verify qualified RFC 3161 timestamp tokens (.tsr) directly in PowerShell 7+ using native .NET cryptographic assemblies without external tools.
- PowerShell 7.0+ (Core) recommended (built on .NET 5+).
- Built-in .NET assembly:
System.Security.Cryptography.Pkcs. - TSA Certificate Chain (for offline verification): Download TSAChain.zip.
Step 1: Request and Save a Timestamp Token (.tsr)
Compute the SHA-256 hash of your file, generate an Rfc3161TimestampRequest object, send it via Invoke-RestMethod, and write the binary response token to disk.
function Request-Rfc3161Timestamp {
param (
[Parameter(Mandatory = $true)]
[string]$FilePath,
[Parameter(Mandatory = $true)]
[string]$OutputTsrPath,
[Parameter(Mandatory = $true)]
[string]$TsaUrl
)
# 1. Compute SHA-256 hash of the target file
$fileBytes = [System.IO.File]::ReadAllBytes($FilePath)
$hash = [System.Security.Cryptography.SHA256]::HashData($fileBytes)
# 2. Build RFC 3161 request
$hashAlgorithm = [System.Security.Cryptography.HashAlgorithmName]::SHA256
$request = [System.Security.Cryptography.Pkcs.Rfc3161TimestampRequest]::CreateFromHash(
$hash,
$hashAlgorithm,
$null,
$true # Request TSA certificate in response
)
$encodedRequest = $request.Encode()
# 3. Send HTTP POST request to the TSA endpoint
$tsrBytes = Invoke-RestMethod -Uri $TsaUrl `
-Method Post `
-ContentType "application/timestamp-query" `
-Body $encodedRequest `
-ResponseHeadersVariable responseHeaders
# 4. Save timestamp response (.tsr)
[System.IO.File]::WriteAllBytes($OutputTsrPath, $tsrBytes)
Write-Host "[SUCCESS] Timestamp saved to: $OutputTsrPath" -ForegroundColor Green
}
Step 2: Verify the Timestamp Token (.tsr)
Parse the saved .tsr response using Rfc3161TimestampToken and validate its hash matching against the original file.
function Test-Rfc3161Timestamp {
param (
[Parameter(Mandatory = $true)]
[string]$FilePath,
[Parameter(Mandatory = $true)]
[string]$TsrPath
)
# 1. Read original file and compute SHA-256 hash
$fileBytes = [System.IO.File]::ReadAllBytes($FilePath)
$hash = [System.Security.Cryptography.SHA256]::HashData($fileBytes)
$tsrBytes = [System.IO.File]::ReadAllBytes($TsrPath)
# 2. Parse RFC 3161 Timestamp Token
$bytesRead = 0
$token = [System.Security.Cryptography.Pkcs.Rfc3161TimestampToken]::ReadIfTimestampToken(
$tsrBytes,
[ref]$bytesRead
)
if ($null -eq $token) {
Write-Error "[ERROR] Invalid timestamp token format."
return $false
}
# 3. Verify hash integrity
$hashAlgorithm = [System.Security.Cryptography.HashAlgorithmName]::SHA256
$isHashValid = $token.VerifyHash($hash, $hashAlgorithm, [ref]$null)
if ($isHashValid) {
$signingTime = $token.AsSignedCms().SignerInfos[0].SigningTime
Write-Host "[SUCCESS] Timestamp is valid! Signed at (UTC): $($signingTime.UtcDateTime)" -ForegroundColor Green
return $true
} else {
Write-Error "[ERROR] File hash does not match timestamp imprint."
return $false
}
}
Execution Example
Run the functions in your PowerShell session or script file:
$fileToSign = "document.pdf"
$tsrOutput = "document.pdf.tsr"
$tsaUrl = "https://tsaexample.com/myserver.aspx"
# 1. Request Timestamp Token
Request-Rfc3161Timestamp -FilePath $fileToSign -OutputTsrPath $tsrOutput -TsaUrl $tsaUrl
# 2. Verify Timestamp Token
$isValid = Test-Rfc3161Timestamp -FilePath $fileToSign -TsrPath $tsrOutput
Write-Host "Verification Result: $isValid"
Why use native PowerShell? PowerShell 7+ exposes .NET’s built-in
Rfc3161TimestampRequest classes directly, making it ideal for CI/CD pipelines, automated system deployment, and administrative scripting without installing extra executables.