tkey-verification
is a tool used for signing a TKey identity and
verifying that it still has the same identity as it did when it was
provisioned, typically by Tillitis the
original vendor.
Note well: If your TKey has been provisioned by you or someone else,
like your IT department, you will need to run their version of the
tkey-verification
program instead of this one.
Official instructions on Tillitis' web.
You can download a release of the tool at:
https://github.com/tillitis/tkey-verification/releases
Or do:
$ go install github.com/tillitis/tkey-verification/cmd/tkey-verification@latest
if you have a Go compiler. Please note that if you install like this
you won't get the tag in --version
.
- "device under verification": The device the vendor is provisioning or the user is verifying.
- "device signature": A signature made on the device under verification with the signer device app.
- Unique Device Identifier (UDI): A unique identifier present in all TKeys. The 1st half identifies the revision of the hardware, the 2nd half is a serial number.
- "signing server": An HSM-like machine providing signatures over messages and producing files to be uploaded to some database.
- "signer": A device app used for confirming the TKey's identity, right now either verisigner (source in older versions in this repository, look for verisigner tags) or tkey-device-signer.
- "signer public key": The public key of signer running on the device under verification.
- "vendor signature": A signature made by the signing server.
- Retrieve the UDI from the device under verification.
- Run the signer with a specific tag on the device under verification. This creates a unique key pair.
- Retrieve signer public key from the device under verification.
- Ask signer to sign a random challenge.
- Verify the signature of the random challenge with the retrieved public key to let the device prove that it has the corresponding private key.
- Ask signer for a digest of the firmware binary (in ROM). Consult the internal firmware database to verify that the TKey, according to its hardware revision, is running the expected firmware.
- Sign a message consisting of the UDI, firmware digest, and signer public key, with a vendor signature.
- Publish the Verification file, which includes the UDI, the tag and digest of the signer program used, the vendor signature, and the timestamp when signature was made.
- Retrieve the UDI from the device under verification.
- Get the Verification file with the vendor signature, signer tag and digest for this UDI.
- Run the signer with the same tag and digest on the device under verification.
- Retrive the signer public key.
- Ask signer to sign a random challenge.
- Verify the signature of the random challenge with the signer public key thus proving that the device under verification has access to the corresponding private key.
- Ask signer for a digest of the firmware binary (in ROM). Consult the internal firmware database to verify that the TKey, according to its hardware revision, is running the expected firmware.
- Recreate the message of UDI, firmware digest and signer public key. Verify the vendor signature of the message, thus proving that the UDI, the firmware, and this private/public key pair was the same during vendor signing.
Note that the exact same signer binary that was used for producing the signer signature during provisioning must be used when verifying it. If a different signer is used then the device private/public key will not match, even if the TKey is the same. A verifier must check the "hash" field and complain if it does not have a signer binary with the same digest.
Build the tkey-verification
tool with the test file containing
public key(s) for vendor signing/verify.
$ cp test-vendor-signing-pubkeys.txt cmd/tkey-verification/vendor-signing-pubkeys.txt
$ make
See below if you need to get hold of a different public key.
The device apps used for signing is included in binary form under
cmd/tkey-verification/bins/
. See more info under Building included
device apps if you want to build them
yourself.
See Implementation notes for more in-depth notes on the program.
tkey-verification
contains an in-code database mapping known hardware revisions (first half of the Unique Device Identifier) to their expected firmware size and hash. This needs to be maintained in cmd/tkey-verification/firmwares.go inNewFirmwares()
.
The device apps used for signing is included in binary form under
cmd/tkey-verification/bins/
.
Reproducible versions of the device app verisigner
binary included
in this repo can be built from earlier verisigner tags. Checkout the
wanted tag and follow the instructions there.
The signer binary
can be built reproducible from the tags mentioned in the bins
directory. Please note that you have to build without touch
requirement.
For your convenience we include a test CA and some test certificates
in certs
. They expire 10 years after being generated.
If you need to rebuild CA, server, and client certs you can use any ordinary X.509 certificate tools like GnuTLS's certtool or OpenSSL to generate your certificates.
You can also install the small certstrap tool and run:
$ make certs
-
You need 1 TKey and 1 QEMU machine running to try this out (or 2 TKeys, or 2 QEMU machines, if you manage to get that working). One is Tillitis' (vendor's) signing TKey, and the other is a TKey that you want to sign and then verify as genuine. You need to know the serial port device paths for these.
-
Run the signing server on QEMU (see the Tillitis Developer Handbook for more information on how to run QEMU). Notice the port QEMU provides when starting.
./tkey-verification serve-signer --config tkey-verification.yaml.example-serve-signer --port /dev/pts/12
-
Insert the device under verification, the TKey to be signed and verified.
-
Get the signing server to sign for a device under verification (here a hardware TKey)
$ ./tkey-verification remote-sign --config tkey-verification.yaml.example-remote-sign Auto-detected serial port /dev/ttyACM0 Connecting to device on serial port /dev/ttyACM0 ... Firmware name0:'tk1 ' name1:'mkdf' version:4 Loading verisigner-app built from tag:verisigner-v0.0.1 hash:9598910ec9ebe2504a5f894de6f8e067… ... App loaded. App name0:'veri' name1:'sign' version:1 TKey UDI: 0x0001020304050607(BE) VendorID: 0x0010 ProductID: 8 ProductRev: 3 TKey firmware with size:3204 and verified hash:31accb1c40febc2bf02f48656a943336… Remote Sign was successful
-
The signing server should now have signed and saved a verification file under
signatures
with a filename generated from the Unique Device Identifier, typically something like0133704100000015
if from Tillitis, but0001020304050607
if the bitstream has been built directly from tillitis-key1. -
Before trying to verify you need to remove and re-insert the device under verification to get it back to firmware mode.
tkey-verification
always requires to load the signer itself. Then try to verify against local files in a directory usingverify -d signatures
(the default is to query a web server):$ ./tkey-verification verify -d signatures TKey UDI: 0x0001020304050607(BE) VendorID: 0x0010 ProductID: 8 ProductRev: 3 Reading verification data from file signatures/0001020304050607 ... TKey is genuine!
For the complete set of commands, see the manual page tkey-verification(1).
The vendor's public key is built into the tkey-verification binary from a text file.
For each public key, the tag and hash digest of the device app used when extracting the public key is also provided. The signing server needs this so that its TKey can have the correct private key when signing. Note that these tags per public key are independent from and can be different from the tag used for device signing.
A test file is provided in test-vendor-signing-pubkeys.txt
. It
contains the default public key of our QEMU machine, which is
generated when running verisigner v0.0.3.
If you want to use some other key(s) this is how:
If you're just testing start a QEMU as a signing endpoint. See above.
Get the public key from the TKey in the signing server. We provide a
command in tkey-verification
, show-pubkey
, for that. The path to
the app binary to use must be given as an argument.
Example:
./tkey-verification show-pubkey --port /dev/pts/10 --app cmd/tkey-verification/bins/signer-v1.0.1.bin
Public Key, app tag, and app hash for vendor-signing-pubkeys.txt follows on stdout:
03a7bd3be67cb466869904ec14b9974ebcc6e593abdc4151315ace2511b9c94d signer-v1.0.1 cd3c4f433f84648428113bd0a0cc407b2150e925a51b478006321e5a903c1638ce807138d1cc1f8f03cfb6236a87de0febde3ce0ddf177208e5483d1c169bac4
Enter that line into a file, for instance other-pubkey.txt
. Then build everything with this file:
$ cat other-pubkey.txt >> cmd/tkey-verification/vendor-signing-pubkeys.txt
$ make
The computer running tkey-verification serve-sign
generates files
in a directory signatures/
which is named after the Unique Device
Identifier (in hex), for example signatures/0133704100000015
. This
file is needed in order to be able to verify a TKey.
The file contains:
- timestamp: RFC3339 UTC timestamp when the signature was done.
- apptag: The Git tag of the signer app used on the device under verification,
- apphash: The hash of the signer app binary used on the device under verification. Stored in hexadecimal.
- signature: Vendor signature of the message (described above). Stored in hexadecimal.
Example file content:
{
"timestamp": "2023-03-03T09:31:51Z",
"apptag": "verisigner-v0.0.1",
"apphash": "9598910ec9ebe2504a5f894de6f8e0677dc94c156c7bd6f7e805a35354b3c85daa4ca66ab93f4d75221b501def457b4cafc933c6cdcf16d1eb8ccba6cccf6630",
"signature": "db4e7a72b720b33f6d4887df0f9dcdd6988ca8adb6b0042d8e8c92b5be3e4e39d908f166d093f3ab20880102d43a2b0c8e31178ab7cdb59977dcf7204116cc0c"
}
tkey-verification
is released with the help of GoReleaser, see
.goreleaser.yaml
in the root of the repo.
Currently this has to be done on a computer running Darwin, at least
for Tillitis' official releases. The reason is that tkeyclient
needs
CGO enabled for Darwin to enumerate USB-devices, and that the Darwin
binary is signed with Tillitis' Apple Developer Certificate, which
at the moment also needs to be done using Darwin. We are looking into
solutions for both those points.
You should be able to build a binary that is a exact copy of our release binaries if you use the same Go compiler, at least for the statically linked Linux and Windows binaries.
Please see the official releases for digests and details about the build environment.
Note that tar.gz
and such files are not reproducible since they contain
a timestamp.
For the universal Darwin file, the signature produced by Tillitis
needs to be removed before it can be compared to one not built and
released by Tillitis. This can be done using codesign --remove-signature path/to/binary
, at least on a Darwin machine.
The releases are published at https://github.com/tillitis/tkey-verification/releases with the binaries and checksum files.
Release v0.0.2-v0.0.3 were built with make podman
and the
release-builds directory contains digests of
released versions.