Last active
July 27, 2017 12:45
-
-
Save ShikherVerma/9204060b545c00597e7ad9b694cfeb9c to your computer and use it in GitHub Desktop.
verify git push ceritifcates $ verify-certificate.py path-to-latest-push-certificate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
import os | |
import zlib | |
import re | |
import gnupg | |
import subprocess | |
def verify_signature(gpg, signature, content): | |
"""This function exists because python-gnupg failed me.""" | |
# write signature to a file and get file stream 'rb' | |
sign_file = open("/tmp/signature.txt", "wb") | |
sign_file.write(bytes(signature, "utf-8")) | |
sign_file.close() | |
sign_file = open("/tmp/signature.txt", "rb") | |
# write certificate to a file and get path | |
cert_path = "/tmp/cert.txt" | |
cert_file = open(cert_path, "wb") | |
cert_file.write(bytes(content, "utf-8")) | |
cert_file.close() | |
verified = gpg.verify_file(sign_file, cert_path) | |
return verified | |
def main(): | |
if (len(sys.argv) != 2): | |
sys.exit("Usage verify-certificate.py path") | |
# Load the certificate file from arguments | |
path = sys.argv[1] | |
fileDir = os.path.dirname(os.path.realpath('__file__')) | |
filename = os.path.join(fileDir, path) | |
cert_compressed = open(filename, 'rb').read() | |
cert_text = zlib.decompress(cert_compressed).decode("utf-8") | |
cert_text = re.search("(?<=)(certificate.*?)(?=$)", cert_text, re.S).group(1) | |
# Get the information apart. | |
signature = re.search("(?<=)(-----BEGIN PGP SIGNATURE-----.*?)(?=$)", cert_text, re.S).group(1) | |
content = re.search("(?<=)(certificate.*?)(?=-----BEGIN)", cert_text, re.S).group(1) | |
key_id = re.search("(?<=pusher )(.*?)(?= )", cert_text, re.S).group(1) | |
push_data = re.search("(?<=nonce.{32}\n\n)(.*?)(?=-----BEGIN PGP SIGNATURE-----)", cert_text, re.S).group(1) | |
# get the gpg key using the public key id | |
gpg = gnupg.GPG() | |
gpg.recv_keys('keys.gnupg.net', key_id) | |
# verify the signature for the certificate | |
verified = verify_signature(gpg, signature, content) | |
if not verified: | |
raise ValueError("Signature failed to verify") | |
else: | |
print("GOOD SIGNATURE") | |
# verify the state of the repo from the push certificate | |
print("Assuming that this certificate is the latest one") | |
for line in push_data.splitlines(): | |
commit_hash = line.split(" ")[1] | |
ref = line.split(" ")[2] | |
branch = ref.split("refs/heads/")[1] | |
output = subprocess.check_output(["git", "rev-parse", branch]).decode("utf-8").strip('\n') | |
# git rev-parse the branch to check that the hash is correct | |
if(output == commit_hash): | |
print(f"Branch {branch} is at correct hash.") | |
else: | |
print(f"ERROR : Branch {branch} should be at {commit_hash} but currently at {output}") | |
sys.exit(2) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment