cheat sheet

certutil

The dual-purpose Windows CLI for certificate-store management and as the most reliable built-in tool for file hashing, base64 encoding, and CRL/CTL handling — no install required.

certutil — Certificates, Hashing and Encoding

What it is

certutil.exe is the built-in Windows command-line tool for working with certificates, certificate stores, certificate revocation lists, and — almost by accident — the most reliable built-in utility for SHA-256 hashing and base64 encoding/decoding on a fresh Windows install. It was designed for AD CS (Active Directory Certificate Services) administrators, but every Windows machine since XP ships with it because the certificate-store APIs need a CLI front-end, and that front-end happens to expose -hashfile and -encode/-decode as side effects. On a Windows box with no Git Bash, no PowerShell module installed, and no third-party tooling, certutil is your only way to verify a download's SHA-256 from cmd.exe.

Two distinct workloads dominate real-world use:

  1. Hashing and encoding — verify installer integrity, base64-encode binary blobs for transport, decode a base64 PEM block back to DER.
  2. Certificate management — add, remove, view, and verify certificates in the Windows certificate stores, both per-user and machine-wide.

The PowerShell equivalents are Get-FileHash (hashing) and the Cert:\ PSDrive plus Import-Certificate / Export-Certificate (store ops). Both are more idiomatic on modern Windows, but certutil runs everywhere and predates them by 15 years.

Availability

certutil.exe ships as C:\Windows\System32\certutil.exe on Windows XP and later. Most store-modification verbs need elevation; hashing and encoding do not.

cmd
certutil -? | findstr /R "^[ ]*\-[a-zA-Z]"

Output:

lua
  -dump             -- Dump configuration information or files
  -hashfile         -- Generate and display cryptographic hash over a file
  -encode           -- Encode file by base64
  -decode           -- Decode base64-encoded file
  -store            -- Dump certificate store
  -addstore         -- Add certificate to store
  -delstore         -- Delete certificate from store
  -verify           -- Verify certificate, CRL or chain
  -repairstore      -- Repair key association or update certificate properties
  -urlcache         -- Display or delete URL cache entries
  ...

Syntax

Almost every certutil command follows the pattern certutil [-verb] [args]. Flags are double-letter shortforms (e.g. -f for force) or full word forms (-user to scope to the current user's store rather than the machine).

cmd
certutil [-verb] [-flags] <arg1> [arg2 ...]

Output: (none — exits 0 on success)

Essential options

SwitchMeaning
-?Brief help — append a verb for verb-specific help (certutil -hashfile -?)
-userOperate on the current user's certificate store (default is local machine)
-fForce — overwrite existing entries without prompting
-silentSuppress prompts and progress
-vVerbose
-config "ca\name"Target a specific Certificate Authority
-enterpriseTarget the enterprise (AD-replicated) store

Hashing files (-hashfile)

certutil -hashfile computes a cryptographic hash of a file. The algorithm is supplied as a positional argument; SHA256 is overwhelmingly the most common for verifying installer downloads.

cmd
certutil -hashfile C:\Downloads\setup.exe SHA256

Output:

bash
SHA256 hash of C:\Downloads\setup.exe:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
CertUtil: -hashfile command completed successfully.

Supported algorithms

The full list of algorithms certutil supports as the second argument to -hashfile:

AlgorithmOutput bitsNotes
MD2128Obsolete; do not use
MD4128Obsolete; do not use
MD5128Cryptographically broken, but still common for non-security file fingerprints
SHA1160Deprecated for security use
SHA256256The default choice for download verification
SHA384384Common for code signing
SHA512512Common for archive integrity

If the algorithm is omitted, certutil -hashfile returns SHA1 (legacy default) — always specify SHA256 explicitly.

cmd
rem MD5 fingerprint for cross-referencing legacy mirror lists
certutil -hashfile C:\Downloads\old.zip MD5

rem SHA512 for very-long-lived integrity records
certutil -hashfile C:\Downloads\bigarchive.tar.gz SHA512

Output:

bash
MD5 hash of C:\Downloads\old.zip:
d41d8cd98f00b204e9800998ecf8427e
CertUtil: -hashfile command completed successfully.
SHA512 hash of C:\Downloads\bigarchive.tar.gz:
cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
CertUtil: -hashfile command completed successfully.

Stripping the surrounding noise

certutil -hashfile prints three lines: a header, the hash, and a "command completed" footer. For scripting, you want just the hash. The middle line is reliably the second of three, so a for /f "skip=1" pull works on every Windows locale.

cmd
@echo off
for /f "skip=1 tokens=*" %%H in ('certutil -hashfile setup.exe SHA256') do (
    if not defined HASH set "HASH=%%H"
)
echo %HASH%

Output:

code
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

PowerShell Get-FileHash — when to prefer it

PowerShell's Get-FileHash is cleaner — it returns an object you can compare directly — but adds 50–100 ms of startup time and isn't available in pure cmd.exe or recovery environments.

powershell
Get-FileHash setup.exe -Algorithm SHA256 | Select-Object -ExpandProperty Hash

Output:

code
E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855

The hex case differs (Get-FileHash returns upper-case, certutil lower-case); always lowercase both sides before comparing.

Base64 encoding and decoding (-encode / -decode)

certutil -encode wraps a binary file in PEM-style base64 with -----BEGIN CERTIFICATE----- headers. -decode reverses it. Despite the name, both work on any binary file — useful for transporting binaries through systems that mangle non-printable bytes (email, chat, GPO scripts, registry REG_SZ values).

cmd
certutil -encode binary.bin binary.b64

Output:

ini
Input Length = 1024
Output Length = 1438
CertUtil: -encode command completed successfully.
cmd
certutil -decode binary.b64 binary_restored.bin
fc /b binary.bin binary_restored.bin

Output:

yaml
Input Length = 1438
Output Length = 1024
CertUtil: -decode command completed successfully.

Comparing files binary.bin and binary_restored.bin
FC: no differences encountered

Encoded file format

The output of -encode is not raw base64 — it's PEM-style with headers and 64-char line wrapping. This matters when interoperating with non-Windows tools:

text
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEFhlH...lots of base64...4tlEZQIDAQAB
...
-----END CERTIFICATE-----

For raw, headerless base64, pipe through findstr /v "-----" or use PowerShell:

powershell
[Convert]::ToBase64String([IO.File]::ReadAllBytes('binary.bin')) | Set-Content binary.raw.b64

Output: (none — file written)

Hex dump of a binary file

certutil -dump (no verb argument) dumps the contents of certificate-like files in human-readable form. For arbitrary binary, certutil -encodehex produces a clean side-by-side hex+ASCII dump — much faster to type than installing xxd or hexdump. certutil -decodehex reverses it, turning a hex-encoded text file back into binary.

cmd
certutil -encodehex binary.bin binary.hex
type binary.hex

Output:

yaml
0000  7f 45 4c 46 02 01 01 00  00 00 00 00 00 00 00 00   .ELF............
0010  02 00 3e 00 01 00 00 00  d0 30 40 00 00 00 00 00   ..>......0@.....
0020  40 00 00 00 00 00 00 00  20 19 00 00 00 00 00 00   @....... .......
...
cmd
rem Round-trip: encode, then decode back, then compare
certutil -encodehex binary.bin binary.hex
certutil -decodehex binary.hex binary_restored.bin
fc /b binary.bin binary_restored.bin

Output:

vbnet
CertUtil: -encodehex command completed successfully.
CertUtil: -decodehex command completed successfully.
Comparing files binary.bin and binary_restored.bin
FC: no differences encountered

Certificate stores — overview

Windows organises certificates into named storesMy (user/computer personal certs with private keys), Root (trusted root CAs), CA (intermediate CAs), TrustedPublisher, Disallowed, AuthRoot, plus many others. Each store exists in three scopes:

ScopeSwitchPath in mmc/regedit
Local Computer(default)Cert:\LocalMachine\* / Computer Account snap-in
Current User-userCert:\CurrentUser\* / User Account snap-in
Service / Enterprise-enterpriseAD-replicated, computer-scoped
cmd
rem List names of every store under the local machine
certutil -store -? | findstr /R "^[ ]*\""

Output:

arduino
  "My"
  "Root"
  "Trust"
  "CA"
  "TrustedPublisher"
  "Disallowed"
  "AuthRoot"
  "TrustedPeople"
  ...

Viewing certificates in a store (-store)

-store <storename> [serialnum|thumb|cn] dumps the contents of a store. With no second argument it lists everything; with an argument, it shows only the matching cert(s).

cmd
rem List every trusted root CA on this machine
certutil -store Root | findstr "Subject:"

Output:

ini
    Subject: CN=Microsoft Root Certificate Authority 2011, O=Microsoft Corporation
    Subject: CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
    Subject: CN=GlobalSign, O=GlobalSign, OU=GlobalSign Root CA - R3
    Subject: CN=USERTrust RSA Certification Authority, O=The USERTRUST Network
    ...
cmd
rem User-scope personal certificates
certutil -user -store My

Output:

ini
My
================ Certificate 0 ================
Serial Number: 4a52b06d000200000017
Issuer: CN=ACME Issuing CA, DC=corp, DC=example
 NotBefore: 2025-09-01 14:22
 NotAfter: 2026-09-01 14:32
Subject: CN=Alice Dev, CN=Users, DC=corp, DC=example
Non-root Certificate
Cert Hash(sha1): 71 6a 4f 8d 92 a3 ...
Key Container = ...
  Provider = Microsoft Strong Cryptographic Provider
Signature test passed
CertUtil: -store command completed successfully.

Looking up a specific cert by serial number, hash, or CN

The second argument to -store is a flexible matcher — serial number, SHA1 thumbprint, common-name substring, all work.

cmd
certutil -store Root "DigiCert Global Root CA"

Output:

yaml
Root
================ Certificate ... ================
Serial Number: 083be056904246b1a1756ac95991c74a
Issuer: CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
 NotBefore: 2006-11-10 00:00
 NotAfter: 2031-11-10 00:00
Subject: CN=DigiCert Global Root CA, OU=www.digicert.com, O=DigiCert Inc, C=US
Signature matches Public Key
Root Certificate: Subject matches Issuer
Cert Hash(sha1): a8985d3a65e5e5c4b2d7d66d40c6dd2fb19c5436
No key provider information
Cannot find the certificate and private key for decryption.
CertUtil: -store command completed successfully.

Adding and removing certificates (-addstore / -delstore)

-addstore imports a certificate from a .cer, .crt, .p7b, or .sst file into the named store. Requires admin if the target store is machine-scoped.

cmd
rem Trust a corporate root CA machine-wide
certutil -addstore Root C:\Certs\acme-root-ca.cer

Output:

vbnet
Root
Signature matches Public Key
Certificate "CN=ACME Root CA, O=Acme Inc, C=US" added to store.
CertUtil: -addstore command completed successfully.
cmd
rem User-scope (no admin needed)
certutil -user -addstore Root C:\Certs\acme-root-ca.cer

Output:

vbnet
Root "Trusted Root Certification Authorities"
Signature matches Public Key
Certificate "CN=ACME Root CA, O=Acme Inc, C=US" added to store.
CertUtil: -addstore command completed successfully.

-delstore removes by serial number, hash, or substring match against the cert subject.

cmd
certutil -delstore Root "ACME Root CA"

Output:

bash
Root "Trusted Root Certification Authorities"
================ Certificate ... ================
...
CertUtil: -delstore command completed successfully.

Verifying a certificate or chain (-verify)

-verify does a full chain build and revocation check. Use it before deploying a new cert to confirm Windows will accept it.

cmd
certutil -verify -urlfetch mycert.cer

Output:

ini
Issuer:
    CN=ACME Issuing CA
    DC=corp, DC=example
Subject:
    CN=www.example.com
    O=Acme Inc, C=US

CertUtil: -verify command completed successfully.

-urlfetch follows AIA and CRL distribution points online — without it the check is offline-only. A successful build through every link of the chain is reported; any broken link (revoked cert, expired intermediate, untrusted root) prints the failing step.

Common verify failures

ErrorMeaning
0x80092004 (Cannot find object or property)Certificate not found in store, or chain missing intermediate
0x800B0109 (CERT_E_UNTRUSTEDROOT)Root CA not in trusted-roots store
0x800B010A (CERT_E_CHAINING)Cannot build a chain from leaf to a trusted root
0x80092012 (CRYPT_E_NO_REVOCATION_CHECK)CRL/OCSP unreachable; revocation check skipped
0x80092013 (CRYPT_E_REVOKED)Cert is revoked

URL cache (-urlcache)

Windows caches CRLs, AIA fetches, and downloaded intermediate certs in a per-user URL cache. Stale entries can cause -verify to falsely report failures. Clear the cache with -urlcache * delete.

cmd
rem List cached entries
certutil -urlcache | findstr "URL"

rem Clear all
certutil -urlcache * delete

Output:

bash
URL: http://crl.digicert.com/DigiCertGlobalRootCA.crl
URL: http://ocsp.digicert.com/...
URL: http://crl3.digicert.com/sha2-extended-validation-server-g3.crl

CertUtil: -URLCache command completed successfully.

Personal Information Exchange (PFX/PKCS#12)

.pfx (a.k.a. .p12) files bundle a certificate together with its private key, encrypted with a password. certutil -importpfx adds them to a store; -exportpfx writes them out. The private key handling is what distinguishes PFX from the plain .cer files used in -addstore.

cmd
rem Import a PFX with private key into the machine's My store
certutil -p "PFXpassword" -importpfx My C:\Certs\webserver.pfx

Output:

vbnet
Certificate "CN=www.example.com" added to store.
CertUtil: -importpfx command completed successfully.
cmd
rem Export a cert + private key out of the store (must be marked exportable)
certutil -exportpfx -p "newPassword" My "CN=www.example.com" C:\Certs\export.pfx

Output:

ini
================ Certificate 0 ================
...
CertUtil: -exportpfx command completed successfully.

PFX encryption algorithm — CryptoAlgorithm=Aes256-Sha256

By default -exportpfx uses the legacy TripleDES-Sha1 encryption for the PFX payload, which fails to import on systems running in FIPS-restricted mode or on hardened OpenSSL 3.x readers. Pass CryptoAlgorithm=Aes256-Sha256 as an -exportpfx modifier to produce a modern AES-256 / SHA-256 protected PFX that OpenSSL 3.x, .NET 8+, and current macOS Keychain accept without warnings.

cmd
rem Modern PFX (AES-256 / SHA-256) — required for FIPS and interop with OpenSSL 3.x
certutil -p "newPassword" -exportpfx My "CN=www.example.com" C:\Certs\export.pfx CryptoAlgorithm=Aes256-Sha256

Output:

ini
================ Certificate 0 ================
...
CertUtil: -exportpfx command completed successfully.

The same modifier is accepted by -importpfx on the way back in, alongside ,Exportable (mark private key as exportable from the destination store) and ,VSM (store the private key in a Virtual Smart Card container).

cmd
rem Import with private key marked exportable, into the user My store
certutil -user -p "PFXpassword" -importpfx My C:\Certs\webserver.pfx Exportable

Output:

vbnet
Certificate "CN=www.example.com" added to store.
CertUtil: -importpfx command completed successfully.

Common pitfalls

  1. Hash output noisecertutil -hashfile always prints three lines, and the hash itself is the second. Don't naive-grep for hex; use findstr /V ":" or for /f "skip=1" to pull the hash cleanly.
  2. Localised output — on non-English Windows, the surrounding text ("hash of", "command completed successfully") is translated. The hash line itself is unchanged, but pattern matching for SHA256 hash of will fail. Always anchor on position (second line), not on English strings.
  3. Default algorithm is SHA1certutil -hashfile foo (no algorithm) returns SHA1. Old habits aside, always specify SHA256 explicitly.
  4. -encode produces PEM, not raw base64 — the output includes -----BEGIN CERTIFICATE----- headers and 64-char line breaks. Tools expecting raw base64 will reject it; strip the wrapper or use PowerShell's [Convert]::ToBase64String.
  5. -user vs default machine scope — every store operation needs the right scope. Forgetting -user while looking for a user's personal cert is the #1 reason for "I imported it but it's not there".
  6. -importpfx requires the private key be exportable — and modern Windows defaults to non-exportable for security. Pass ,Exportable after the password when importing, or use -csp to pick an exportable provider.
  7. Cached CRLs survive cert deletion — after deleting a CA from the Root store, run certutil -urlcache * delete to clear any cached chain data, otherwise -verify may still pass.
  8. The Root store on a domain machine is GPO-managed — values added with -addstore may be wiped at next GPO refresh. For permanent corporate trust, use a Certificates GPO that publishes the cert.

Real-world recipes

Verify an installer matches the publisher's published SHA256

The canonical use case. Always compare in lowercase to avoid case mismatches.

cmd
@echo off
set EXPECTED=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
for /f "skip=1 tokens=*" %%H in ('certutil -hashfile setup.exe SHA256') do (
    if not defined ACTUAL set "ACTUAL=%%H"
)
if /I "%ACTUAL%" == "%EXPECTED%" (
    echo MATCH
) else (
    echo MISMATCH
    echo Expected: %EXPECTED%
    echo Actual:   %ACTUAL%
    exit /b 1
)

Output:

sql
MATCH

Embed a binary into a batch/PS1 deployment script

Encode the binary at packaging time, store the base64 in the script, decode at runtime — useful for shipping a single self-contained installer file.

cmd
rem At packaging time:
certutil -encode payload.exe payload.b64

rem In the deployment script, write the b64 into a temp file and decode:
echo -----BEGIN CERTIFICATE----- > %TEMP%\p.b64
echo MIIDdzC...LOTSOFBASE64...4tlEZ >> %TEMP%\p.b64
echo -----END CERTIFICATE----- >> %TEMP%\p.b64
certutil -decode %TEMP%\p.b64 %TEMP%\payload.exe
%TEMP%\payload.exe /silent

Output:

ini
Input Length = 1438
Output Length = 1024
CertUtil: -decode command completed successfully.
(installer runs)

Trust a corporate root CA on every machine via Group Policy script

Stand-alone machines get the CA via this provisioning script; domain-joined machines should use a GPO instead.

cmd
@echo off
if not exist "C:\Certs\acme-root.cer" (
    echo Certificate file missing.
    exit /b 1
)
certutil -addstore -f Root "C:\Certs\acme-root.cer"
echo Root CA installed. Verifying...
certutil -verify "C:\Certs\acme-root.cer" | findstr /I "successfully"

Output:

vbnet
Root "Trusted Root Certification Authorities"
Signature matches Public Key
Certificate "CN=ACME Root CA, O=Acme Inc, C=US" added to store.
CertUtil: -addstore command completed successfully.
Root CA installed. Verifying...
CertUtil: -verify command completed successfully.

Audit every trusted root CA on a workstation

Useful in compliance audits — list every root CA, their subject, and their expiry date.

cmd
certutil -store Root | findstr /R /C:"Subject:" /C:"NotAfter:"

Output:

yaml
    Subject: CN=Microsoft Root Certificate Authority 2011
     NotAfter: 2036-03-22 23:13
    Subject: CN=DigiCert Global Root CA
     NotAfter: 2031-11-10 00:00
    Subject: CN=ACME Root CA
     NotAfter: 2030-01-15 12:00
...

Decode a base64 PEM cert and view it

A .pem file is just -----BEGIN CERTIFICATE----- + base64 + -----END CERTIFICATE-----. certutil -decode turns it into a DER .cer you can then dump or import.

cmd
certutil -decode incoming.pem incoming.cer
certutil -dump incoming.cer

Output:

yaml
Input Length = 1438
Output Length = 1024
CertUtil: -decode command completed successfully.

X509 Certificate:
Version: 3
Serial Number: 4a52b06d...
Signature Algorithm:
    Algorithm ObjectId: 1.2.840.113549.1.1.11 sha256RSA
Issuer:
    CN=ACME Issuing CA
 NotBefore: 2025-09-01 14:22
 NotAfter: 2026-09-01 14:32
Subject:
    CN=www.example.com
...

Force a cert chain rebuild (clear caches)

When -verify reports a stale revocation error, clear caches and retry.

cmd
certutil -urlcache * delete
certutil -setreg chain\ChainCacheResyncFiletime @now
certutil -verify -urlfetch mycert.cer

Output:

bash
CertUtil: -URLCache command completed successfully.
... (revocation freshly fetched)
CertUtil: -verify command completed successfully.

Compute the SHA256 of every file in a directory

cmd
@echo off
for %%F in (*.exe) do (
    for /f "skip=1 tokens=*" %%H in ('certutil -hashfile "%%F" SHA256') do (
        if not defined H_%%~nF set "H_%%~nF=%%H"
    )
)
set H_

Output:

ini
H_setup=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
H_updater=2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae

Sources

Microsoft Learn — certutil command — Authoritative verb reference covering -dump, -dumpPFX, -hashfile, -encode / -decode, -encodehex / -decodehex, store ops (-store, -addstore, -delstore, -enumstore, -importpfx, -exportpfx with the modern CryptoAlgorithm=Aes256-Sha256 modifier), -verify, and CA backup / restore.

Tips

If you need to verify a download but only have cmd.exe, no PowerShell, and no third-party tools, certutil -hashfile foo SHA256 is your tool. It's been there since XP and will be there in WinPE recovery environments.

certutil -dump accepts almost any cert-like file — .cer, .crt, .p7b, .pfx, .csr, .crl, even raw DER. Reach for it before guessing a file's format.

For modern automation in PowerShell, prefer Get-FileHash, Import-PfxCertificate, and the Cert:\ PSDrive over certutil. Reserve certutil for batch scripts, MSI custom actions, and recovery environments where PowerShell isn't guaranteed to be available.