diff --git a/.github/workflows/reproducible.yml b/.github/workflows/reproducible.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5a1e61bd0c5b2f7dddc9a9e73c3edc9358316d33
--- /dev/null
+++ b/.github/workflows/reproducible.yml
@@ -0,0 +1,39 @@
+---
+name: Check that binaries are reproducible
+on:
+  push:
+  pull_request:
+    types: [opened, synchronize, reopened]
+
+jobs:
+  check_hashes:
+    strategy:
+      matrix:
+        os: [ubuntu-18.04, macos-10.15]
+    runs-on: ${{ matrix.os }}
+    steps:
+      - uses: actions/checkout@v2
+      - uses: actions-rs/toolchain@v1
+        with:
+          target: thumbv7em-none-eabi
+      - uses: actions/setup-python@v1
+        with:
+          python-version: 3.7
+      - name: Install Python dependencies
+        run: python -m pip install --upgrade pip setuptools wheel
+      - name: Set up OpenSK
+        run: ./setup.sh
+
+      - name: Use sample cryptographic material
+        run: rm -R crypto_data/ && cp -r reproducible/sample_crypto_data crypto_data
+      - name: Computing cryptographic hashes
+        run: ./reproduce_hashes.sh
+
+      - name: Upload reproduced binaries
+        uses: actions/upload-artifact@v1
+        with:
+          name: reproduced-${{ matrix.os }}
+          path: reproducible/reproduced.tar
+
+      - name: Comparing cryptographic hashes
+        run: git diff --no-index reproducible/reference_binaries_${{ matrix.os }}.sha256sum reproducible/binaries.sha256sum
diff --git a/deploy.py b/deploy.py
index 57b7b867ca872415a8f191213c3f9c22603c230f..3b7e89ff8f6ae2e6c97f83b1c0d04bb7d74c1189 100755
--- a/deploy.py
+++ b/deploy.py
@@ -392,19 +392,17 @@ class OpenSKInstaller:
     assert self.args.application
     info("Generating Tock TAB file for application/example {}".format(
         self.args.application))
-    package_parameter = "-n"
     elf2tab_ver = self.checked_command_output(["elf2tab", "--version"]).split(
-        " ", maxsplit=1)[1]
-    # Starting from v0.5.0-dev the parameter changed.
-    # Current pyblished crate is 0.4.0 but we don't want developers
-    # running the HEAD from github to be stuck
-    if "0.5.0-dev" in elf2tab_ver:
-      package_parameter = "--package-name"
+        "\n", maxsplit=1)[0]
+    if elf2tab_ver != "elf2tab 0.5.0":
+      fatal("Unsupported elf2tab version {!a}. Please use 0.5.0.".format(
+          elf2tab_ver))
     os.makedirs(self.tab_folder, exist_ok=True)
     tab_filename = os.path.join(self.tab_folder,
                                 "{}.tab".format(self.args.application))
     elf2tab_args = [
-        "elf2tab", package_parameter, self.args.application, "-o", tab_filename
+        "elf2tab", "--deterministic", "--package-name", self.args.application,
+        "-o", tab_filename
     ]
     if self.args.verbose_build:
       elf2tab_args.append("--verbose")
diff --git a/reproduce_board.sh b/reproduce_board.sh
new file mode 100755
index 0000000000000000000000000000000000000000..19730e8f83b5f5cf082bfb8d8c86b7ea30909ccb
--- /dev/null
+++ b/reproduce_board.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+# Copyright 2019 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+echo "Board: $BOARD"
+./deploy.py --verbose-build --board=$BOARD --no-app --programmer=none
+./third_party/tock/tools/sha256sum/target/debug/sha256sum third_party/tock/target/thumbv7em-none-eabi/release/$BOARD.bin >> reproducible/binaries.sha256sum
+tar -rvf reproducible/reproduced.tar third_party/tock/target/thumbv7em-none-eabi/release/$BOARD.bin
+
+./deploy.py --verbose-build --board=$BOARD --opensk --programmer=none
+./third_party/tock/tools/sha256sum/target/debug/sha256sum target/${BOARD}_merged.hex >> reproducible/binaries.sha256sum
+tar -rvf reproducible/reproduced.tar target/${BOARD}_merged.hex
diff --git a/reproduce_hashes.sh b/reproduce_hashes.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9480472bb6aabbd6745ce272915ec2dd876cabcd
--- /dev/null
+++ b/reproduce_hashes.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# Copyright 2019 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -ex
+
+rm -f reproducible/binaries.sha256sum
+
+echo "Creating reproducible/reproduced.tar"
+touch empty_file
+tar -cvf reproducible/reproduced.tar empty_file
+rm empty_file
+
+echo "Building sha256sum tool..."
+cargo build --manifest-path third_party/tock/tools/sha256sum/Cargo.toml
+
+echo "Computing SHA-256 sums of the boards..."
+for board in nrf52840dk nrf52840_dongle nrf52840_dongle_dfu nrf52840_mdk_dfu
+do
+  BOARD=$board ./reproduce_board.sh
+done
+
+echo "Computing SHA-256 sum of the TAB file..."
+./third_party/tock/tools/sha256sum/target/debug/sha256sum target/tab/ctap2.tab >> reproducible/binaries.sha256sum
+tar -rvf reproducible/reproduced.tar target/tab/ctap2.tab
diff --git a/reproducible/reference_binaries_macos-10.15.sha256sum b/reproducible/reference_binaries_macos-10.15.sha256sum
new file mode 100644
index 0000000000000000000000000000000000000000..935573c09166a34249cbd98fc6f51c3fb8785dee
--- /dev/null
+++ b/reproducible/reference_binaries_macos-10.15.sha256sum
@@ -0,0 +1,9 @@
+b113945b033eb229e3821542f5889769e5fd2e2ae3cb85c6d13a4e05a44a9866	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
+b16a815411e4dfdd8ceb8588b47861e33f9282b0ffa10660692783b4e2cd6179	target/nrf52840dk_merged.hex
+346016903ddf244a239162b7c703aafe7ec70a115175e2204892e874f930f6be	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
+5ba6bdd42d1036df6347119020925404029999bcba51409a56327070bca1ff62	target/nrf52840_dongle_merged.hex
+adcc4caaea86f7b0d54111d3080802e7389a4e69a8f17945d026ee732ea8daa4	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
+bf6aeafe25197ca500e7c39abf713b85d748722a6a65edefe8a9093d4d1f8100	target/nrf52840_dongle_dfu_merged.hex
+97a7dbdb7c3caa345307d5ff7f7607dad5c2cdc523b43c68d3b741ddce318e92	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
+45631c7fb72d56446a966a3b58a6ff5513f94a6052641938cd49e9a9498b959f	target/nrf52840_mdk_dfu_merged.hex
+5ae401ae89f6155820527d5099948f337f8e3fc93da18ccdd150c645b6a53ea9	target/tab/ctap2.tab
diff --git a/reproducible/reference_binaries_ubuntu-18.04.sha256sum b/reproducible/reference_binaries_ubuntu-18.04.sha256sum
new file mode 100644
index 0000000000000000000000000000000000000000..408b7d4b69d9fb3865aabb7a398dce49fa1ac094
--- /dev/null
+++ b/reproducible/reference_binaries_ubuntu-18.04.sha256sum
@@ -0,0 +1,9 @@
+921d6fc31f7235456dd41abc7e634a37ee87b5016b80c979d20ac5d3fcfc6b6b	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840dk.bin
+450c3775cc16e812519b9a65aaaa21c9cd8cc89881735f2c2c5f540793f54fe1	target/nrf52840dk_merged.hex
+aab5bdc406b1e874b83872c9358d310070b3ce948ec0e20c054fb923ec879249	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin
+bdc557bedaedb39e74d234a243a86fbf15623498a47a8941ec588cfc83fb4f56	target/nrf52840_dongle_merged.hex
+26b8513e76058e86a01a4b408411ce429834eb2843993eb1671f2487b160bc9a	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_dongle_dfu.bin
+4d5dee48187600023bbac889d61ca0f626891590cafff45f73dcbcf4ef9875e5	target/nrf52840_dongle_dfu_merged.hex
+7cc558a66505e8cf8170aab50e6ddcb28f349fd7ced35ce841ccec33a533bea1	third_party/tock/target/thumbv7em-none-eabi/release/nrf52840_mdk_dfu.bin
+34adf76fec8502d86a298607bf74d559710e4e8c644dc19d2e41e2f830cf9203	target/nrf52840_mdk_dfu_merged.hex
+89b80eccf75175f9a8c9be2c3adccbe7d2ee9b7cbca896bf0605c3a6b8a09cf6	target/tab/ctap2.tab
diff --git a/reproducible/sample_crypto_data/opensk.key b/reproducible/sample_crypto_data/opensk.key
new file mode 100644
index 0000000000000000000000000000000000000000..5b68558de1ac7bce1bbb8a48d6f66119950c3b58
--- /dev/null
+++ b/reproducible/sample_crypto_data/opensk.key
@@ -0,0 +1,8 @@
+-----BEGIN EC PARAMETERS-----
+BggqhkjOPQMBBw==
+-----END EC PARAMETERS-----
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEICMfnFy7L3y5p2MOGezavAeS+noKYtT21mDcWllN7Y1zoAoGCCqGSM49
+AwEHoUQDQgAEhZflF2Fq4xmAofKOxG/0sx8bucdpJPRLR4HXArAFXJzdLF9ofkpn
+gzsVWzTYFr+nNiyxySyJsdkH/qQv4rCV0A==
+-----END EC PRIVATE KEY-----
diff --git a/reproducible/sample_crypto_data/opensk_cert.pem b/reproducible/sample_crypto_data/opensk_cert.pem
new file mode 100644
index 0000000000000000000000000000000000000000..169321eaae8c1536a1e30321e0be8a29a43e743b
--- /dev/null
+++ b/reproducible/sample_crypto_data/opensk_cert.pem
@@ -0,0 +1,9 @@
+-----BEGIN CERTIFICATE-----
+MIIBPDCB4wIUTEbgPPL3tr2rLkI83EyzyQJQmYEwCgYIKoZIzj0EAwIwGzEZMBcG
+A1UEAwwQR29vZ2xlIE9wZW5TSyBDQTAeFw0yMDA0MTQxNTM5MDRaFw0zMDA0MTQx
+NTM5MDRaMCcxJTAjBgNVBAMMHEdvb2dsZSBPcGVuU0sgSGFja2VyIEVkaXRpb24w
+WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASFl+UXYWrjGYCh8o7Eb/SzHxu5x2kk
+9EtHgdcCsAVcnN0sX2h+SmeDOxVbNNgWv6c2LLHJLImx2Qf+pC/isJXQMAoGCCqG
+SM49BAMCA0gAMEUCIBKkHijpTbjlPDv3oFw/nW/ta8jEMhY8iNCBp9N0+NNYAiEA
+ywzrGpmc0reEUFCGHBBdvC2E2SxIlvaefz7umT8ajy4=
+-----END CERTIFICATE-----