Verified Commit a9e09a75 authored by Torsten Grote's avatar Torsten Grote
Browse files

Initial commit

Pipeline #1600 passed with stages
in 26 minutes and 48 seconds
image: docker:git
- docker:dind
- build
- test
- release
TEST_IMAGE: briar/tor-reproducer:${CI_BUILD_REF_NAME}
RELEASE_IMAGE: briar/tor-reproducer:latest
- echo ${DOCKER_HUB_PASS} | docker login -u ${DOCKER_HUB_USER} --password-stdin
stage: build
- docker build -t ${TEST_IMAGE} .
- docker push $TEST_IMAGE
stage: test
- docker run ${TEST_IMAGE} ./
stage: release
- docker pull $TEST_IMAGE
- docker push $RELEASE_IMAGE
- master
FROM debian:stretch
ENV DEBIAN_FRONTEND=noninteractive
WORKDIR /opt/tor-reproducer
ADD ./
ADD install*.sh ./
ADD tor-versions.json ./
ADD ./
RUN ./
CMD ./
# Tor Reproducer
This is a tool you can use to verify that the version of Tor
used by [Briar]( was built exactly from the public source code
and no modifications (such as backdoors) were made.
More information about these so called reproducible builds is available at
The source code for this tool is available at
## How to use
Make sure the version of Tor you want to verify is included in `tor-versions.json`.
Verify that you have `docker` installed:
docker --version
If this command does not work,
please [install Docker](
and continue once it is installed.
### Using our pre-built image
If you trust that our pre-built Docker image was build exactly from *its* source,
you can use it for faster verification.
If not, you can read the next section to learn how to build the image yourself.
Then you are only trusting the official `debian:stable` which is out of our control.
Otherwise, you can skip the next section and move directly to *Run the verification*.
### Building your own image
Check out the source repository:
git clone
Build our Docker image:
docker build -t briar/tor-reproducer tor-reproducer
### Run the verification
To verify a specific version of Briar, run
docker run briar/tor-reproducer:latest ./ [tag]
Where `[tag]` is the git tag (source code snapshot) that identifies the version
of Tor you want to test, for example `tor-`.
You can find a list of tags in Tor's
[source code repository](
#!/usr/bin/env python3
import json
import os
import sys
from collections import OrderedDict
from shutil import move, copy, rmtree
from subprocess import check_call
from utils import get_sha256, fail
NDK_DIR = 'android-ndk'
REPO_DIR = 'tor-android'
def main():
if len(sys.argv) > 2:
fail("Usage: %s [Tor version tag]" % sys.argv[0])
tag = sys.argv[1] if len(sys.argv) > 1 else None
# get Tor version and versions of its dependencies
versions = get_build_versions(tag)
# setup Android NDK
# clone and checkout tor-android repo based on tor-versions.json
# build Tor for various architectures
# zip geoip database
geoip_path = os.path.join(REPO_DIR, 'external', 'tor', 'src', 'config', 'geoip')
check_call(['zip', '-X', os.path.join(REPO_DIR, ''), geoip_path])
# zip everything together
file_list = ['', '', '', '', '']
zip_name = '' % versions['tor'].split('-')[1]
check_call(['zip', '-X', zip_name] + file_list, cwd=REPO_DIR)
# print hashes for debug purposes
for file in file_list + [zip_name]:
sha256hash = get_sha256(os.path.join(REPO_DIR, file))
print("%s: %s" % (file, sha256hash))
def get_build_versions(tag):
# load Tor versions and their dependencies
with open('tor-versions.json', 'r') as f:
versions = json.load(f, object_pairs_hook=OrderedDict)
if tag is None:
# take top-most Tor version
tag = next(iter(versions))
print("Building Tor %s" % versions[tag]['tor'])
return versions[tag]
def setup_android_ndk(versions):
if os.path.isdir(NDK_DIR):
# check that we are using the correct NDK
from configparser import ConfigParser
config = ConfigParser()
with open(os.path.join(NDK_DIR, ''), 'r') as f:
config.read_string('[default]\n' +
revision = config.get('default', 'Pkg.Revision')
if revision != versions['ndk']['revision']:
print("Existing Android NDK has unexpected revision. Deleting...")
if not os.path.isdir(NDK_DIR):
# download Android NDK
print("Downloading Android NDK...")
check_call(['wget', '-c', '--no-verbose', versions['ndk']['url'], '-O', ''])
# check sha256 hash on downloaded file
if get_sha256('') != versions['ndk']['sha256']:
fail("Android NDK checksum does not match")
# install the NDK
print("Unpacking Android NDK...")
ndk_dir_tmp = NDK_DIR + '-tmp'
check_call(['unzip', '-q', '', '-d', ndk_dir_tmp])
content = os.listdir(ndk_dir_tmp)
if len(content) == 1 and content[0].startswith('android-ndk-r'):
move(os.path.join(ndk_dir_tmp, content[0]), NDK_DIR)
fail("Could not extract NDK: %s" % str(content))
os.putenv('ANDROID_NDK_HOME', os.path.abspath(NDK_DIR))
def prepare_tor_android_repo(versions):
if os.path.isdir(REPO_DIR):
# get latest commits and tags from remote
check_call(['git', 'fetch', 'origin'], cwd=REPO_DIR)
# clone repo
url = versions['tor_android_repo_url']
check_call(['git', 'clone', '--recurse-submodules', url, REPO_DIR])
# checkout tor-android version
check_call(['git', 'checkout', '-f', versions['tor-android']], cwd=REPO_DIR)
# undo all changes
check_call(['git', 'reset', '--hard'], cwd=REPO_DIR)
check_call(['git', 'submodule', 'foreach', 'git', 'reset', '--hard'], cwd=REPO_DIR)
# clean all untracked files and directories (-d) from repo
check_call(['git', 'clean', '-dffx'], cwd=REPO_DIR)
check_call(['git', 'submodule', 'foreach', 'git', 'clean', '-dffx'], cwd=REPO_DIR)
# check out versions of external dependencies
checkout('tor', versions['tor'], 'external/tor')
checkout('libevent', versions['libevent'], 'external/libevent')
checkout('openssl', versions['openssl'], 'external/openssl')
checkout('xz', versions['xz'], 'external/xz')
checkout('zstd', versions['zstd'], 'external/zstd')
def checkout(name, tag, path):
print("Checking out %s: %s" % (name, tag))
repo_path = os.path.join(REPO_DIR, path)
check_call(['git', 'checkout', '-f', tag], cwd=repo_path)
def build_architectures():
# build arm pie
# build arm
os.putenv('NDK_PLATFORM_LEVEL', '14')
os.putenv('PIEFLAGS', '')
# build x86 pie
os.putenv('APP_ABI', 'x86')
# build x86
os.putenv('NDK_PLATFORM_LEVEL', '14')
os.putenv('PIEFLAGS', '')
def build_arch(name):
check_call(['make', '-C', 'external', 'clean', 'tor'], cwd=REPO_DIR)
copy(os.path.join(REPO_DIR, 'external', 'bin', 'tor'), os.path.join(REPO_DIR, 'tor'))
check_call(['strip', '-D', 'tor'], cwd=REPO_DIR)
check_call(['zip', name, 'tor'], cwd=REPO_DIR)
if __name__ == "__main__":
#!/usr/bin/env bash
set -e
set -x
apt-get install -y --no-install-recommends \
python3-pip python3-setuptools python3-wheel \
python3-libarchive-c \
# Install latest diffoscope (version in Debian stable is outdated)
pip3 install diffoscope
\ No newline at end of file
#!/usr/bin/env bash
set -e
set -x
apt-get install -y --no-install-recommends \
git \
zip \
unzip \
wget \
make \
patch \
autopoint \
libtool \
automake \
#!/usr/bin/env bash
set -e
set -x
# update package sources
apt-get update
apt-get -y upgrade
# do not install documentation to keep image small
echo "path-exclude=/usr/share/locale/*" >> /etc/dpkg/dpkg.cfg.d/01_nodoc
echo "path-exclude=/usr/share/man/*" >> /etc/dpkg/dpkg.cfg.d/01_nodoc
echo "path-exclude=/usr/share/doc/*" >> /etc/dpkg/dpkg.cfg.d/01_nodoc
# install dependencies
# clean up for smaller image size
apt-get -y autoremove --purge
apt-get clean
rm -rf /var/lib/apt/lists/*
"": {
"tor": "tor-",
"libevent": "release-2.0.22-stable",
"openssl": "OpenSSL_1_0_2o",
"xz": "v5.2.3",
"zstd": "v1.3.2",
"tor-android": "tor-android-binary-",
"tor_android_repo_url": "",
"ndk": {
"url": "",
"revision": "15.2.4203891",
"sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
"": {
"tor": "tor-",
"libevent": "release-2.0.22-stable",
"openssl": "OpenSSL_1_0_2o",
"xz": "v5.2.3",
"zstd": "v1.3.2",
"tor-android": "tor-android-binary-",
"tor_android_repo_url": "",
"ndk": {
"url": "",
"revision": "15.2.4203891",
"sha256": "f01788946733bf6294a36727b99366a18369904eb068a599dde8cca2c1d2ba3c"
\ No newline at end of file
#!/usr/bin/env python3
import hashlib
import sys
def fail(msg=""):
sys.stderr.write("Error: %s\n" % msg)
def get_sha256(filename, block_size=65536):
sha256 = hashlib.sha256()
with open(filename, 'rb') as f:
for block in iter(lambda:, b''):
return sha256.hexdigest()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment