Skip to content

Commit

Permalink
Verifies signatures in CI
Browse files Browse the repository at this point in the history
Small scripts that iterates through files in the workstation repo and verifies their signature. Specifies `--test` in this repo as this is the dev repo signed with the test key.
  • Loading branch information
emkll committed Jan 23, 2020
1 parent 347b33a commit af92b36
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
version: 2.1
jobs:
tests:
docker:
- image: circleci/python:3.7-buster
steps:
- checkout
- run:
name: Install Debian packaging dependencies
command: |
sudo apt install rpm git-lfs
git-lfs install
- run:
name: workaround for git-lfs in circle with deploy key
command: git config --global --unset url.ssh://[email protected]

- run:
name: Clone the repository with LFS
command: git clone -b ${CIRCLE_BRANCH} //github.com/freedomofpress/securedrop-workstation-dev-rpm-packages-lfs
- run:
name: Verify the signatures of all rpm artifacts
command: |
cd securedrop-workstation-dev-rpm-packages-lfs
./scripts/check.py --dev --verify --all
workflows:
build-packages:
jobs:
- tests
62 changes: 62 additions & 0 deletions pubkeys/prod.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQINBFpk6aABEAC+isLGnbBjULB3h+5dhBGTsEFawSlxtTuOWq5biRId7SKvzXG6
PKh7+slh0XwPBYi1184pGyngs2zz15/hsfF8boGdi3ZebX/RPTMvnb3LVduNDcik
+MHAbBt6+65Fou1y7WEck8Ly0jDkohVLa5GEWRsyIlT9wBxViJAbg//yXPSx9zgn
KJqK9njN6sA2uFsvlqfnUDH/rWnuYXN0zxZ10ulYhpyp2CRLZVI+yoWNB8QsPyja
RoA5vnXb3LOQaJxTrrZFbJYWwAci1N4TpSPJ6UiAFbCdb9g+aJxoNO2sBZx1h8ik
l6S95glKRriw2kMOGrnFSAN2nvn9WfiOoysjNMQdf/7y38Ig8myRcgSVZjWmv3J9
eMToAOrDSyWqq3uAkoNMb9bmszHs4GhSHI7z77GVXF1P1UW49XFRLbWzyV0kUOoh
TeghQ1AR/oDmiT8pPICKbaPfmZJaQpG9SGof8j+Iv4jwDfl/Gvq+PRcc1W6X5Zgs
iR74QFp/ob9zMgZPlK7jUakZ2ZHdgVHepXnFO2Tf+2NBC30AFwsIpwj+ACx8uKic
hUYRhCKJEPtHkyhKYGz30dLLbNEZ3xK7iJIY57B6krDlPagUTlD2DULXyHmFLneG
mzy+I2UR+BykZAJMN6RyDxLo1Op9hXlz53pE7jxIU1G/BuJyykspH/qHLwARAQAB
tEVGUEYgQXV0aG9yaXR5IChGcmVlZG9tIG9mIHRoZSBQcmVzcyBGb3VuZGF0aW9u
IEF1dGhvcml0eSBTaWduaW5nIEtleSmJAZwEEAEKAAYFAlp6tc0ACgkQEjBgqAl5
G1Xa4AwAnnsKXASJpzzspWHtWOmgReG6zOrRh3aT+tNYPWyDbV1TltAPIXZfsuZ6
epFdUDNXqkPXlCxN+WpoOLHyPe6I7M8exIZo95qOYP+NQn0kk3jIfQQ/k1fgnhnV
I05jMwhpkMpNqJC8iszH2loh9u2IOSy7tMo5bn5uVYtZ/TfSfQFfNwO5cfqPkc2G
v5WLzihdvd5WtlYIm2NlT4EvC3f/xT58NeZQ4RP8lGYf+v2gkJM2tRS2/Fa2A2T9
QwOP75tfscaqEq4+iJNqjT8AIfLyVROamS7YiKjAmOft2JGSglYaNluNOkY17sCx
Bq2pI/o367sSGS023w5s5wSb22+4levaPZhDgo7O+GZ1yFGfZP6C2vMAujyjRUn/
WQAuNKs5bhSlunuQqvYV/GQ7i5m99Q21GDS9enjNzexeuSun0KdEcQbPRhcuoG0R
gq/+eRg/t4HC2O8dpV98TPizidKEQlAcDOi+PMD/6usE8fiGVqSEO+wrXjdLRfkS
QEXb4ZvsiQIzBBABCAAdFiEEFyLyKGzZClUk4ZsyaZyZ3HEx/YEFAlp8wZYACgkQ
aZyZ3HEx/YGxRw//foK1oO2e3k8447GBsfOK3VgTWsY65ckP9CtX37hQ9zdr+9Jt
WW1OhZUOgo2uMdcV4Xvvwl+GvWaAYmJPl37y5ow9VjnSAzMHWzEYbqLaUUR1fUlC
AoEHjlvDkJD9ygYAiHEtIhKCZyKfcmLruURgzrHOfUXsifTsqUbNb6nYoYCz1/MZ
KE5Eyi+ig/zQHHr9jMmCPCoBoVZHZ/C4nscVjWZo0UVFsmj1V/albKqx+PMTDQxt
nQiKxyQbvYZMPtgqDSIMSFYXI4dcBwJkfWYC//fLZdhdPP4ypqE2YFymR5KKH1te
m0XMSbw4IFrR0dkP5YrmEYP5OBFh1nKgSUB+HRVvlcaCZBMjnBKl68IkRNIjImqR
uZgrEnORysMjVwB4MaRhCuXyhbv8KtZv4ZLYzmstnc2Ea27z7TBeXxBH6w1/Ta92
nM5AGgutSo3ECwmRomCDVvecVkLgf0laeVT6ByeW9QVbM+QII0DVUuTUpg/IDhcl
MyuXl6MVBkGV4zFpzqEOVxOLfiE7bVYjeeR6DgRI0Uh504rLoz+oOhBBIcsH4+n1
Saec02ly4ckx4f4ZMt+x9Ix3a9qIoVXrkxvYkuTFiD9KL234Eu6xXpwNMyEUbLv0
W0lge7/thBnO4FQ/o0Nv/0WCNv0D/h0irmPCUMDsyPqY5MrlEhKkBm86HmSJAjME
EAEIAB0WIQSvd1eClJ0mPaq7M4eq+zV1+sgnRQUCWnzDfgAKCRCq+zV1+sgnRVEp
EACGY7evHZSeJWPYs2zs4YYfPdnLJLsGAtC8mtfGpRqCBGKup5Xx5mBBv7KCTHU5
BsVAiOjZR+Lj0HWHO1V3V+xaEdLPEcdZzbfeKyEu//mZWT0u1PeEDNDGJfqEY/5v
Ba1uI05FcldABeRhWWWmXXTUOaq9R56wu7SCJKYv9inw3fzdm8gn7c35MTNEA2IH
S7v+3jnc7b/mBi69QjbrzEkV0vMKyoYEZ1phqkrl9urlq02ffJcNB0lfTo1w84jP
nEQvfDQUwp1ymwb4HAwrrr/SrkFwHn5NV/u1Ed3IKrsg4G7GTeqWW+6r2x1TWDw0
MlFALD33pU046HoHuHA8B0FYOW8Ha4EmsfjMAyjMvdNrY0vTZ7aA+Q8pOXXnkldx
JSjYV1EyMk0fTZ+WXonX+NYCQHjtJ1QUG9TSBMMNEGGg4PelsyeE+0GRiKKEfzvm
rV1RRIlKyyxip2GZI+M32eRR4ZAS8zZbmJ1OL9odz9Vjg1OShJhH6Ila/ASwLEtn
Vutr6QH6OzJ4CkDqQUoqsGWS6ymbGDFXIRj/G2/OEO1RuhZj7wuoprU2kd7Vpazj
Qz6s4mn5JxkzeS/JbF+lpXsb5MIUIXs6HLLfno1AowUmE18J4FWDrz9sH68yIoeM
8AJQhs89Tt7eFZZkE/Ypsow3T44cHzXUW/bVvDWRR73qu4kCVAQTAQoAPhYhBPgZ
YqVJAjAPcuy4OqH8H2rS0JBJBQJaZOmgAhsDBQkFo5qABQsJCAcDBRUKCQgLBRYC
AwEAAh4BAheAAAoJEKH8H2rS0JBJp6AP/26tlai94v5vDgWm7MQ6U6GRUec1Jh6D
FgTEaTe0a+KwGdxH0PM1G42EK1M4G0zQv0cUrDkhlLX53KG51pd17ZzHOt/7Y6WZ
S80iwIKjeTAiavI8YD4TexkfWjyjZVb5JLIdALGbXZU2c2Cui/7V7fuWfZoGrXm9
Zc8r/9iXwFj/TxbptxjwExOsdVHkIKnqkmw874Klxpm3GoVNtaNcjPSEga1TcM+9
5pMnEuiIYNUEuqPdb8RACXSYGD3qtzP62Kaimn6OkjBIBhWiKoddMHith/s6pm1L
T0hdwA1d4Y518n2dPnRZDAKTrjliHrzE/I0W0HLKBju/ZqsnHm3WAW6gbtKwWHMw
zZ+EsvoPorwdCE6E5y9BP71xAdz6NaM9UII9j6o5ISEZuxBsCthX7OZDWkxzZypj
lNlVFDvOA6Kj/npKF96vswSIvVkuS8A9Whv/KOalubi7IxZQT0Xt8cTWlzwM45GV
v5qvfvXDvZAe7xfZH272v65+NT4J1q5yvGz9zy0I3tEReSH2oZP0rmzV2VPp5Zr1
dXPr/7eCo4ELStqP0wj/A17Djm3CD3QjPYI2dc4aBHQaQ52VzHUoO5gnjH0eOfyS
tHfw7eyX/bbPI1jjmW0z0LQZTpWEiCOe2es7itbL3NGhJzR3zZHVlbICNUo55NiQ
wX2j+Ii4ZpUH
=WaCA
-----END PGP PUBLIC KEY BLOCK-----
30 changes: 30 additions & 0 deletions pubkeys/test.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----

mQENBFhPGZsBCACzn00s3+i5HdGIldDGYXxY2HKL9Qhk0DhiRrNPaQemhNijuFlC
geCeKN/smDAUyM5mfEoxmWy3V7n8SEQUpqI4dIS2AohReLkyKEKiIpTuXW7F9kO3
vcXHgrTka+8B4ZQxDuTHNFJLmBwJnP24LrL6BzkDIUNeQFwM0EFTDOJlW1QV6qkm
9WGizo2sR0VBJJabfRWrTWd8llYOVcc+LptErVNADPaX6iqb+QnZVJ/nYmCTgABj
lD3aZ4EPZ+ioVOcOxbgBkAX76COObUUw/XahBGwj4fJ5kyzvDSBCHHlRzN39LKpM
Y+HfSc1scAOWN+Dd0N/joIa0j0U4SGHo1NdzABEBAAG0MVNlY3VyZURyb3AgVEVT
VElORyBrZXkgPHNlY3VyZWRyb3BAZnJlZWRvbS5wcmVzcz6JAU4EEwEIADgWIQRO
15zDNi19EoNwRgJKO+SpIhGwPAUCWE8ZmwIbAwULCQgHAgYVCAkKCwIEFgIDAQIe
AQIXgAAKCRBKO+SpIhGwPCb9B/9SuVoxbe3nLlU0bHDQtoq5P7adyTZK+5gKIiAo
mtAkc/EuiF6jYIDLo+DBB1GBJVjyD5igTt14XR3JpMe6nLtztD5zgGk47gYQk3y5
6f5ydd7zRo9OxulRYDvU1mXMUc0EmqfzuSxY55HJy5KQvjeKIU0fTvwbPYXdhFCC
42iyBIkp4e4/C5oO4lNrNY2DJEZ+a8H5LHasJ4g9A78f/D5q0HWO1HutzfDeiMvq
WFwlGMD2OzTEQA2MGlVRIYvLHAG1aV9fXY8kjCFT8ri5hxlQeTkKISfbW3pFSq6s
Ow4r975zWLTPJNm+WTbBpfIOFBVAW34EHkcb/QmntlvqkNM+uQENBFhPGZsBCAC4
VEtCQEuZ3WzCNL/0yQFih1EjT/AsS3j3++xvSOYWF+c7AjR9X0MkJFTnUZBHs6MX
PM33bbkWbBBE2ILdDCEF72Uc5HyyC2lW2DvPY9ZLVSGcMCUsKARv5rbeNdgiLVP5
8AMkmG48q0Pxrr6UVX14M34Jm5G91c/dj9zHtVwkLg4RG/rcumQdlpQhNmMycB2X
lat48atmEkutfLEQizXIlgiCdNEpgfUBy/jZZcCOjwr8PUPmSUWjKOVMv6CSLx8K
z2cP4We7tyq4qhc0cWjJOWOmJpu5tbmi6XEEWGaIJyN+POhHEcb0tI1rTJ88nrMb
DI/NF/35kuWIIkADOb2vABEBAAGJATYEGAEIACAWIQRO15zDNi19EoNwRgJKO+Sp
IhGwPAUCWE8ZmwIbDAAKCRBKO+SpIhGwPC3fB/0TfuScS718FiEcVRI3F2wBbzTQ
VARhGzEvPSU5Z3Cur/EB8ihpWvwi39tUMeg5HTheDl/8A7f1QCjIFSVEr1slGNLh
YFF07XGWhy837z6kiihK2z6/w6Q9QJqjE+QVZCKr97aIPejvEoHoslZTU5pJ52qF
J7KQd1hEvVs00DxY6VlyK0FzXqByKYq6Arl2tzlCZ6RPEHKXV2xSP06jLEagzgYe
DylVo9Xahenj4n/Mtq7Am6tGgU9Vy9cGbWNBdUND/mFQEEZSh9RJabPeluH12sir
5/tfsDr4DGHSz7ws+5M6Zbk6oNJEwQZ4cR+81qCfXE5X5LW1KlAL8wDl7dfS
=fYUi
-----END PGP PUBLIC KEY BLOCK-----
75 changes: 75 additions & 0 deletions scripts/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
import argparse
import os
import subprocess
import sys
import json

PROD_SIGNING_KEY_FPR="pubkeys/prod.key"
DEV_SIGNING_KEY_FPR="pubkeys/test.key"
RPM_DIR="workstation"

def verify_sig_rpm(path, dev=False):

key_path = ""
if dev:
key_path = DEV_SIGNING_KEY_FPR
else:
key_path = PROD_SIGNING_KEY_FPR
try:
subprocess.check_call(["rpmkeys", "--import", key_path])
except subprocess.CalledProcessError as e:
fail("Error importing key: {}".format(str(e)))

# Check the signature
try:
output = subprocess.check_output(["rpm", "--checksig", path])
# rpm --checksig returns 0 if there is *no* signature. I couldn't
# find a way other than parsing stdout
print(str(output))
if "digests signatures OK" not in str(output):
fail("Signture verification failed for {}:{}".format(path, output))
except subprocess.CalledProcessError as e:
fail("Error checking signature: {}".format(str(e)))


def verify_all_rpms(dev=False):
for root, dirs, files in os.walk(RPM_DIR):
for name in files:
verify_sig_rpm(os.path.join(root,name), dev)

def remove_keys_in_rpm_keyring():
try:
subprocess.check_call(["rpm", "--erase", "--allmatches", "gpg-pubkey"])
except subprocess.CalledProcessError:
pass

def fail(msg):
print(msg, file=sys.stderr)
sys.exit(1)

def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--dev', action='store_true', default=False)
parser.add_argument('--verify', action='store_true', default=True)
parser.add_argument('--all', action='store_true', default=False)
parser.add_argument('packages', type=str, nargs='*', help='Files to sign/verify')
args = parser.parse_args()

print(args)

# Since we can't specify with which key to check sigs, we should clear the keyring
remove_keys_in_rpm_keyring()

if args.verify:
if args.all:
verify_all_rpms(args.dev)
else:
for package in args.packages:
assert os.path.exists(package)
verify_sig_rpm(package, args.dev)

sys.exit(0)

if __name__ == "__main__":
main()

0 comments on commit af92b36

Please sign in to comment.