Code signing
All RADKit packages and installers available externally are cryptographically signed by Cisco.
Danger
You should NEVER install a RADKit component whose code signature you have not been able to find and verify. See below for information pertaining to the different platforms and types of installation we support.
Windows installer
The Windows EXE installer contains an embedded software signature. The verification is performed by Windows at installation time. No additional Windows configuration is necessary; in particular, it is not necessary to install additional trusted certificates for this verification to work.
To inspect the signature manually, right-click the installer EXE, select Properties, then Digital Signatures, then Details.
macOS installer
The macOS PKG installer and its payload both contain embedded software signatures, as well as a stapled notarization ticket from Apple. The verification is performed by macOS, both at installation time and at run time. No additional macOS configuration is necessary; in particular, it is not necessary to install additional trusted certificates for this verification to work.
To verify the signature manually and display the signing identity, run the following command on the PKG installer in a Terminal:
spctl --assess --ignore-cache --no-cache -vv --type install PKG_FILE
where PKG_FILE
should be replaced with the path to the RADKit PKG installer, for example:
% spctl --assess --ignore-cache --no-cache -vv --type install cisco_radkit_1.6.11_macos_x86_64_signed.pkg
cisco_radkit_1.6.11_macos_x86_64_signed.pkg: accepted
source=Notarized Developer ID
origin=Developer ID Installer: Cisco Systems, Inc (9X38D433RE)
Linux installer
Starting with RADKit 1.7.0, each RADKit release includes a single .sig256
file that contains
signed hashes for all distribution files in that release, including the Linux installer.
In RADKit 1.6.x releases, the Linux installer used to ship with its own specific .sig
signature
file (bearing the same file name + a .sig
extension).
Both the .sig
and .sig256
signature types must be verified before installation
(see below for details).
Python wheels
Starting with RADKit 1.7.0, each RADKit release includes a single .sig256
file that contains
signed hashes for all distribution files in that release, including the wheel tarballs as well
as each individual wheel file (i.e. it is possible to verify individual .whl
file signatures
even after unpacking the tarballs or downloading those from a PyPI index).
In RADKit 1.6.x releases, the wheel tarballs used to ship with their own specific .sig
signature
files (bearing the same file name + a .sig
extension).
Both the .sig
and .sig256
signature types must be verified before installation
(see below for details).
Verifying .sig256
signatures
Warning
This only applies to RADKit 1.7.0 and later. For older 1.6.x releases, please see Verifying .sig signatures (obsolete).
The RADKit .sig256
signature file is a CMS/PKCS#7 bundle containing a cryptographic signature,
the signing and subordinate authority certificates needed for signature verification, and a data
payload that contains the SHA-256 hashes of all the files in a given RADKit distribution.
When verifying the CMS signature, the root certificate must be provided separately, to ensure that the trust anchor comes from a different source than the signature files and the verification script.
Step 1: Get the Cisco code signing root CA certificate from Cisco
Browse to https://www.cisco.com/security/pki/
Check that the HTTPS session is secure and that you are on
www.cisco.com
(this is important)Click the link: Cisco Root CA M2 (crcam2) - PEM (make sure you select PEM, not CER)
Copy/Save the entire contents to a local file named
crcam2.pem
Place the file in the same directory as the files to be verified
This operation can be performed once and the same file can be reused for subsequent verifications.
Step 2: automated verification using radkit_verify_sig256.py
Use the simple radkit_verify_sig256.py
Python 3 script that is provided with RADKit downloads.
Its contents are also copied below. Make sure to read and understand the script before
you run it. It will simply unpack and verify the list of signed hashes in the .sig256
file,
then iterate over each file in argument and check whether it has the correct hash on disk.
The path to the .sig256
file for the RADKit release must be passed as the --sig
argument, and the path to the crcam2.pem
file may optionally be passed as the --root
argument (otherwise it is loaded from the current directory).
$ ./radkit_verify_sig256.py --sig cisco_radkit_1.7.0.sig256 cisco_radkit_1.7.0b6_pip_linux_x86.tgz
Verifying: cisco_radkit_1.7.0.sig256
Parsing checksums
5956f5e39ed8420f407eeb2f893821162bf74246b64af1ff10dc32c1c8c25c90 cisco_radkit_1.7.0b6_doc_html.tgz
19bd7a5a84c7864e21f3afdab775a4aa3add6919d602c14a785d47022cdab943 cisco_radkit_1.7.0b6_linux_x86_64.sh
e47764fb398036d4f29356fc7b9c71483855f8cc2b304a90e1abda851bb486f1 cisco_radkit_1.7.0b6_pip_linux_arm.tgz
f91563cfc0c95ed4f8b11991c772c3139f834bca07c9982971509a373a895686 cisco_radkit_1.7.0b6_pip_linux_x86.tgz
f0da6af26617368cbf5d7678fd4d3ec80ab82a3bcfb873b6440b224823983bf2 cisco_radkit_1.7.0b6_pip_macos.tgz
f1def4b2a826dc7ba55c3aa777d313c31a7c243c7185aab58f46189f5c48721d cisco_radkit_1.7.0b6_pip_win.tgz
[...]
Verifying: cisco_radkit_1.7.0b6_pip_linux_x86.tgz
Base name: cisco_radkit_1.7.0b6_pip_linux_x86.tgz
Expected : f91563cfc0c95ed4f8b11991c772c3139f834bca07c9982971509a373a895686
Computed : f91563cfc0c95ed4f8b11991c772c3139f834bca07c9982971509a373a895686
SUCCESS: All files verified successfully
If a verification fails, the script will exit immediately with an ERROR:
message.
If all verifications are successful, it will print a SUCCESS:
message.
Please go through the entire output and double-check that there is a “Verification successful”
message displayed and that the checksums actually match for each of the files that you
intended to verify.
Warning
The radkit_verify_sig256.py
can actually verify its own hash from the
.sig256
file. Please do make sure however, that you understand the script and that it
shows no sign of tampering, as self-verifying scripts cannot be fully trusted by definition.
Source code for radkit_verify_sig256.py
#!/usr/bin/env python3
# This file is part of RADKit / Lazy Maestro <radkit@cisco.com>
# Copyright (c) 2018-2025 by Cisco Systems, Inc.
# All rights reserved.
# This script verifies RADKit *.sig256 cryptographic signatures.
# It requires OpenSSL command-line tools and a Python version supported by RADKit.
# Make sure that the `openssl` CLI tools in your PATH come from a trusted source.
#
# The signature file is a CMS/PKCS#7 bundle containing the SHA-256 hashes of all files
# that are part of a given RADKit release. It contains a signature, a data payload and
# the signing and subordinate authority certs. The root cert must be provided separately.
#
# Step 1: get the Cisco code signing root CA certificate from cisco.com
# - Go to https://www.cisco.com/security/pki/certs/crcam2.pem
# - Check in your browser that the HTTPS session is secure (this is important)
# - Copy/Save the entire contents to a file named `crcam2.pem`
# - Place the file in the same directory as this script
#
# Step 2: run the script for one or more RADKit downloads
# - Each RADKit release has an accompanying `.sig256` file that can be downloaded with it
# - Place this script, the .sig256 file, and the RADKit release files you want to verify
# together in the same directory (this also works for individual wheels files obtained
# using "pip download" from a PyPI index)
# - Run this script with "--sig" pointing to the .sig256 file, and each file to verify as argument:
# python3 radkit_verify_sig256.py --sig <sig256-file> <file1> <file2> ...
#
# Example:
# python3 radkit_verify_sig256.py --sig cisco_radkit_1.7.0.sig256 \
# cisco_radkit_1.7.0_pip_linux.tgz cisco_radkit_1.7.0_pip_macos.tgz
#
# If a verification fails, the script will exit immediately with an "ERROR" message.
# If all verifications are successful, it will print a "SUCCESS" message.
# Please go through the entire output and double-check that there is a "Verification successful"
# message displayed and that the checksums actually match for EACH of the files that you
# intended to verify.
# ruff: noqa
# fmt: off
from argparse import ArgumentParser
from pathlib import Path
from re import search
from subprocess import CalledProcessError, run
ROOT = "crcam2.pem"
DGST_REGEX = r"^(SHA2-256|SHA256)\((\S+)\)= ([0-9a-f]+)$"
def must_exist(file: Path) -> None:
if not file.exists():
raise RuntimeError(f"ERROR: File not found: {file}")
if __name__ == "__main__":
parser = ArgumentParser(
prog="radkit_verify.py",
description="Verify RADKit cryptographic signatures",
)
parser.add_argument("--root", type=Path, default=Path(ROOT), help="root certificate (crcam2.pem)")
parser.add_argument("--sig", type=Path, help="release signature file (*.sig256)", required=True)
parser.add_argument("files", nargs="+", type=Path, help="files to verify")
options = parser.parse_args()
print(f"Verifying: {options.sig}")
must_exist(options.root)
must_exist(options.sig)
try:
cms_result = run(
args=["openssl", "cms", "-verify", "-binary", "-inform", "der",
"-CAfile", options.root, "-in", options.sig ],
capture_output=True,
check=True,
)
except CalledProcessError:
raise RuntimeError(f"ERROR: Signature check failed: {options.sig}") from None
print("Parsing checksums")
checksums = {}
for line in cms_result.stdout.decode().splitlines():
match = search(DGST_REGEX, line)
if match is None:
raise RuntimeError(f"ERROR: Malformed checksum entry: {line}")
_, name, checksum = match.groups()
checksums[name] = checksum
print(f" {checksum} {name}")
print()
for file in options.files:
print(f"Verifying: {file}\nBase name: {file.name}")
must_exist(file)
if file.name not in checksums:
raise RuntimeError(f"ERROR: Unknown file (no known checksum): {file}")
expected = checksums[file.name]
print(f"Expected : {expected}")
try:
dgst_result = run(
args=["openssl", "dgst", "-sha256", file],
capture_output=True,
check=True,
)
except CalledProcessError:
raise RuntimeError(f"ERROR: Checksum computation failed: {file}") from None
match = search(DGST_REGEX, dgst_result.stdout.decode().strip())
computed = match.group(3)
print(f"Computed : {computed}")
if expected != computed:
raise RuntimeError(f"ERROR: Checksum is incorrect: {file}")
print()
print("SUCCESS: All files verified successfully")
Verifying .sig
signatures (obsolete)
Warning
This only applies to RADKit 1.6.x releases. For newer releases, please see Verifying .sig256 signatures.
Each RADKit .sig
signature file is a CMS/PKCS#7 bundle containing a cryptographic signature,
an empty data payload, plus the signing and subordinate authority certificates needed for
verification. The root certificate must be provided separately, to ensure that the trust
anchor comes from a different source than the signature files and the verification script.
Step 1: Get the Cisco code signing root CA certificate from Cisco
Browse to https://www.cisco.com/security/pki/
Check that the HTTPS session is secure and that you are on
www.cisco.com
(this is important)Click the link: Cisco Root CA M2 (crcam2) - PEM (make sure you select PEM, not CER)
Copy/Save the entire contents to a local file named
crcam2.pem
Place the file in the same directory as the files to be verified
This operation can be performed once and the same file can be reused for subsequent verifications.
Step 2, Option 1: automated verification using radkit_verify.py
Use the simple radkit_verify.py
Python 3 script that is provided with RADKit downloads.
Make sure to read and understand the script before you run it. It will simply iterate over
each file in argument and run the command described in Option 2 below. For example:
$ python3 radkit_verify.py cisco_radkit_1.6.0_pip_linux.tgz cisco_radkit_1.6.0_pip_macos.tgz
Verifying: cisco_radkit_1.6.0_pip_linux.tgz
Signature: cisco_radkit_1.6.0_pip_linux.tgz.sig
CMS Verification successful
Verifying: cisco_radkit_1.6.0_pip_macos.tgz
Signature: cisco_radkit_1.6.0_pip_macos.tgz.sig
CMS Verification successful
SUCCESS: All files verified successfully
Note
The script expects crcam2.pem
from Step 1 to be located in the current working directory.
If a verification fails, the script will exit immediately with an ERROR:
message.
If all verifications are successful, it will print a SUCCESS:
message.
Please go through the entire output and double-check that there is a “Verification successful” message displayed for each of the files that you intended to verify.
Step 2, Option 2: manual verification using OpenSSL
Alternatively, you can use the openssl cms
command to verify each signature in turn.
This method does not require Python. The syntax is:
openssl cms -binary -verify -noout -inform der -CAfile crcam2.pem -in FILE.sig -content FILE >/dev/null
where FILE
and FILE.sig
should be replaced with the downloaded file name and its
accompanying signature file. The command will return a zero status and print
Verification successful
on success.
Warning
You must redirect the standard output of the openssl cms
command to /dev/null
on
Linux/macOS, or to NUL
on Windows. Errors are still printed on standard error.
Source code for radkit_verify.py
#!/usr/bin/env python3
# This file is part of RADKit / Lazy Maestro <radkit@cisco.com>
# Copyright (c) 2018-2025 by Cisco Systems, Inc.
# All rights reserved.
# This script verifies RADKit *.sig cryptographic signatures.
# It requires OpenSSL command-line tools and a Python version supported by RADKit.
# Make sure that the `openssl` CLI tools in your PATH come from a trusted source.
#
# The signature file is a CMS/PKCS#7 bundle containing the signature, an empty data payload,
# plus the signing and subordinate authority certs. The root cert must be provided separately.
#
# Step 1: get the Cisco code signing root CA certificate from cisco.com
# - Go to https://www.cisco.com/security/pki/certs/crcam2.pem
# - Check in your browser that the HTTPS session is secure (this is important)
# - Copy/Save the entire contents to a file named `crcam2.pem`
# - Place the file in the same directory as this script and the files to be verified
#
# Step 2: run the script for one or more signed RADKit downloads
# - Each signed file has an accompanying `.sig` file that must be downloaded with it
# - Place this script, `<file>`, `<file>.sig` and `crcam2.pem` in the same directory
# (`<file>` is a placeholder for the name of the actual file you are about to verify)
# - Run this script with each file to verify as argument, without the `.sig` extension:
# python3 radkit_verify.py <file1> [<file2> ...]
#
# Example:
# python3 radkit_verify.py cisco_radkit_1.6.0_pip_linux.tgz cisco_radkit_1.6.0_pip_macos.tgz
#
# If a verification fails, the script will exit immediately with an "ERROR" message.
# If all verifications are successful, it will print a "SUCCESS" message.
# Please go through the entire output and double-check that there is a "Verification successful"
# message displayed for EACH of the files you intended to verify.
# ruff: noqa
# fmt: off
from argparse import ArgumentParser
from pathlib import Path
from subprocess import DEVNULL, CalledProcessError, check_call
ROOT = "crcam2.pem"
def must_exist(file: Path) -> None:
if not file.exists():
raise RuntimeError(f"ERROR: File not found: {file}")
if __name__ == "__main__":
parser = ArgumentParser(
prog="radkit_verify.py",
description="Verify RADKit *.sig cryptographic signatures",
)
parser.add_argument("files", nargs="+", help="Paths to files to verify", type=Path)
options = parser.parse_args()
must_exist(Path(ROOT))
for file in options.files:
sig = file.with_suffix(file.suffix + ".sig")
print(f"Verifying: {file}\nSignature: {sig}")
must_exist(file)
must_exist(sig)
try:
check_call(
args=["openssl", "cms", "-verify", "-binary", "-inform", "der",
"-CAfile", ROOT, "-in", sig, "-content", file],
stdout=DEVNULL,
)
except CalledProcessError:
raise RuntimeError(f"ERROR: Signature check failed: {file}") from None
print()
print("SUCCESS: All files verified successfully")