bdisk/bdisk/bGPG.py

159 lines
6.2 KiB
Python
Raw Normal View History

2016-12-16 03:16:48 -05:00
import os
import subprocess
import datetime
import jinja2
import gpgme
import psutil
def genGPG(conf):
# https://media.readthedocs.org/pdf/pygpgme/latest/pygpgme.pdf
build = conf['build']
gpghome = conf['gpg']['mygpghome']
distkey = build['gpgkey']
templates_dir = '{0}/extra/templates'.format(build['basedir'])
mykey = False
pkeys = []
if conf['gpg']['mygpgkey'] != '':
mykey = conf['gpg']['mygpgkey']
if gpghome == '':
# Let's try the default.
gpghome = '{0}/.gnupg'.format(os.path.expanduser("~"))
else:
# No key ID was specified.
if gpghome == '':
# We'll generate a key if we can't find one here.
gpghome = build['dlpath'] + '/.gnupg'
os.environ['GNUPGHOME'] = gpghome
gpg = gpgme.Context()
2016-12-16 04:28:53 -05:00
# do we need to add a keyserver?
if build['gpgkeyserver'] != '':
dirmgr = '{0}/dirmngr.conf'.format(gpghome)
if os.path.isfile(dirmgr):
with open(dirmgr, 'r+') as f:
findme = any(gpgmirror in line for line in f)
if not findme:
f.seek(0, os.SEEK_END)
f.write("\n# Added by {0}.\nkeyserver {1}\n")
2016-12-16 03:16:48 -05:00
if mykey:
try:
privkey = gpg.get_key(mykey, True)
except:
exit('{0}: ERROR: You specified using {1} but we have no secret key for that ID!'.format(
datetime.datetime.now(),
mykey))
else:
for key in gpg.keylist(None,True):
if key.can_sign:
pkeys.append(key)
break
if len(pkeys) == 0:
print("{0}: [GPG] Generating a GPG key...".format(datetime.datetime.now()))
loader = jinja2.FileSystemLoader(templates_dir)
env = jinja2.Environment(loader = loader)
tpl = env.get_template('GPG.j2')
tpl_out = tpl.render(build = build, bdisk = bdisk)
privkey = gpg.get_key(gpg.genkey(tpl_out).fpr, True)
pkeys.append(privkey)
2016-12-16 04:28:53 -05:00
# do we need to add a keyserver? this is for the freshly-generated GNUPGHOME
if build['gpgkeyserver'] != '':
dirmgr = '{0}/dirmngr.conf'.format(gpghome)
with open(dirmgr, 'r+') as f:
findme = any(gpgmirror in line for line in f)
if not findme:
f.seek(0, os.SEEK_END)
f.write("\n# Added by {0}.\nkeyserver {1}\n"
gpg.signers = pkeys
2016-12-16 03:16:48 -05:00
# Now we try to find and add the key for the base image.
gpg.keylist_mode = 2 # remote (keyserver)
try:
key = gpg.get_key(distkey)
except:
exit('{0}: ERROR: We cannot find key ID {1}!'.format(
datetime.datetime.now(),
distkey))
importkey = key.subkeys[0].fpr
gpg.keylist_mode = 1 # local keyring (default)
DEVNULL = open(os.devnull, 'w')
cmd = ['/usr/bin/gpg',
'--recv-keys',
'--batch',
'--yes',
'0x{0}'.format(importkey)]
subprocess.call(cmd, stdout = DEVNULL, stderr = subprocess.STDOUT)
sigkeys = []
for k in gpg.get_key(importkey).subkeys:
2016-12-16 04:28:53 -05:00
sigkeys.append(k.fpr)
cmd = ['/usr/bin/gpg',
'--batch',
'--yes',
'--lsign-key',
'0x{0}'.format(importkey)]
subprocess.call(cmd, stdout = DEVNULL, stderr = subprocess.STDOUT)
return(gpg)
2016-12-16 03:16:48 -05:00
2016-12-16 04:28:53 -05:00
def killStaleAgent(conf):
2016-12-16 03:16:48 -05:00
# Kill off any stale GPG agents running.
# Probably not even needed, but good to have.
2016-12-16 04:28:53 -05:00
chrootdir = conf['build']['chrootdir']
dlpath = conf['build']['dlpath']
2016-12-16 03:16:48 -05:00
procs = psutil.process_iter()
plst = []
for p in procs:
2016-12-16 04:28:53 -05:00
if (p.name() in ('gpg-agent', 'dirmngr') and p.uids()[0] == os.getuid()):
2016-12-16 03:16:48 -05:00
pd = psutil.Process(p.pid).as_dict()
2016-12-16 04:28:53 -05:00
for d in (chrootdir, dlpath):
if pd['cwd'].startswith('{0}'.format(d)):
plst.append(p.pid)
2016-12-16 03:16:48 -05:00
if len(plst) >= 1:
for p in plst:
psutil.Process(p).terminate()
def signIMG(path, conf):
if conf['build']['gpg']:
# If we enabled GPG signing, we need to figure out if we
# are using a personal key or the automatically generated one.
if conf['gpg']['mygpghome'] != '':
gpghome = conf['gpg']['mygpghome']
else:
gpghome = conf['build']['dlpath'] + '/.gnupg'
if conf['gpg']['mygpgkey'] != '':
keyid = conf['gpg']['mygpgkey']
else:
keyid = False
# We want to kill off any stale gpg-agents so we spawn a new one.
killStaleAgent()
## HERE BE DRAGONS. Converting to PyGPGME...
# List of Key instances used for signing with sign() and encrypt_sign().
gpg = gpgme.Context()
if keyid:
gpg.signers = gpg.get_key(keyid)
else:
# Try to "guess" the key ID.
# If we got here, it means we generated a key earlier during the tarball download...
# So we can use that!
pass
# And if we didn't specify one manually, we'll pick the first one we find.
# This way we can use the automatically generated one from prep.
if not keyid:
keyid = gpg.list_keys(True)[0]['keyid']
print('{0}: [BUILD] Signing {1} with {2}...'.format(
datetime.datetime.now(),
path,
keyid))
# TODO: remove this warning when upstream python-gnupg fixes
print('\t\t\t If you see a "ValueError: Unknown status message: \'KEY_CONSIDERED\'" error, ' +
'it can be safely ignored.')
print('\t\t\t If this is taking a VERY LONG time, try installing haveged and starting it. ' +
'This can be done safely in parallel with the build process.')
data_in = open(path, 'rb')
gpg.sign_file(data_in, keyid = keyid, detach = True,
clearsign = False, output = '{0}.sig'.format(path))
data_in.close()
def gpgVerify(sigfile, datafile, conf):
pass
2016-12-16 04:28:53 -05:00
def delTempKeys(conf):
pass
killStaleAgent(conf)