adding stuff to GPG ... i think i *can* use ctx.create_key()!
This commit is contained in:
parent
0dd54a604d
commit
69b6ec60d0
66
bdisk/GPG.py
66
bdisk/GPG.py
@ -1,3 +1,4 @@
|
||||
import datetime
|
||||
import gpg
|
||||
import os
|
||||
import psutil
|
||||
@ -14,6 +15,12 @@ _algmaps = {#'cv': 'cv{keysize}', # DISABLED, can't sign (only encrypt). Curren
|
||||
'rsa': 'rsa{keysize}', # Variable (1024 <> 4096), but we only support 1024, 2048, 4096
|
||||
'dsa': 'dsa{keysize}'} # Variable (768 <> 3072), but we only support 768, 2048, 3072
|
||||
|
||||
# This is just a helper function to get a delta from a unix epoch.
|
||||
def _epoch_helper(epoch):
|
||||
d = datetime.datetime.utcfromtimestamp(epoch) - datetime.datetime.utcnow()
|
||||
return(abs(int(d.total_seconds()))) # Returns a positive integer even if negative...
|
||||
#return(int(d.total_seconds()))
|
||||
|
||||
# http://files.au.adversary.org/crypto/GPGMEpythonHOWTOen.html
|
||||
# https://www.gnupg.org/documentation/manuals/gpgme.pdf
|
||||
# Support ECC? https://www.gnupg.org/faq/whats-new-in-2.1.html#ecc
|
||||
@ -125,11 +132,62 @@ class GPGHandler(object):
|
||||
# for p in plst:
|
||||
# psutil.Process(p).terminate()
|
||||
|
||||
def CreateKey(self, params): # TODO: explicit params
|
||||
def CreateKey(self, name, algo, keysize, email = None, comment = None, passwd = None, key = None, expiry = None):
|
||||
algo = _algmaps[algo].format(keysize = keysize)
|
||||
userid = name
|
||||
userid += ' ({0})'.format(comment) if comment else ''
|
||||
userid += ' <{0}>'.format(email) if email else ''
|
||||
if not expiry:
|
||||
expires = False
|
||||
else:
|
||||
expires = True
|
||||
self.ctx.create_key(userid,
|
||||
algorithm = algo,
|
||||
expires = expires,
|
||||
expires_in = _epoch_helper(expiry),
|
||||
sign = True)
|
||||
# Even if expires is False, it still parses the expiry...
|
||||
# except OverflowError: # Only trips if expires is True and a negative expires occurred.
|
||||
# raise ValueError(('Expiration epoch must be 0 (to disable) or a future time! '
|
||||
# 'The specified epoch ({0}, {1}) is in the past '
|
||||
# '(current time is {2}, {3}).').format(expiry,
|
||||
# str(datetime.datetime.utcfromtimestamp(expiry)),
|
||||
# datetime.datetime.utcnow().timestamp(),
|
||||
# str(datetime.datetime.utcnow())))
|
||||
return(k)
|
||||
# We can't use self.ctx.create_key; it's a little limiting.
|
||||
# It's a fairly thin wrapper to .op_createkey() (the C GPGME API gpgme_op_createkey) anyways.
|
||||
|
||||
pass
|
||||
flags = (gpg.constants.create.SIGN |
|
||||
gpg.constants.create.CERT)
|
||||
if not expiry:
|
||||
flags = (flags | gpg.constants.create.NOEXPIRE)
|
||||
if not passwd:
|
||||
flags = (flags | gpg.constants.create.NOPASSWD)
|
||||
else:
|
||||
# Thanks, gpg/core.py#Context.create_key()!
|
||||
sys_pinentry = gpg.constants.PINENTRY_MODE_DEFAULT
|
||||
old_pass_cb = getattr(self, '_passphrase_cb', None)
|
||||
self.ctx.pinentry_mode = gpg.constants.PINENTRY_MODE_LOOPBACK
|
||||
def passphrase_cb(hint, desc, prev_bad, hook = None):
|
||||
return(passwd)
|
||||
self.ctx.set_passphrase_cb(passphrase_cb)
|
||||
try:
|
||||
if not key:
|
||||
try:
|
||||
self.ctx.op_createkey(userid, algo, 0, 0, flags)
|
||||
k = self.ctx.get_key(self.ctx.op_genkey_result().fpr, secret = True)
|
||||
else:
|
||||
if not isinstance(key, gpg.gpgme._gpgme_key):
|
||||
key = self.ctx.get_key(key)
|
||||
if not key:
|
||||
raise ValueError('Key {0} does not exist'.format())
|
||||
#self.ctx.op_createsubkey(key, )
|
||||
finally:
|
||||
if not passwd:
|
||||
self.ctx.pinentry_mode = sys_pinentry
|
||||
if old_pass_cb:
|
||||
self.ctx.set_passphrase_cb(*old_pass_cb[1:])
|
||||
return(k)
|
||||
|
||||
def GetSigs(self, data_in):
|
||||
key_ids = []
|
||||
@ -153,3 +211,5 @@ class GPGHandler(object):
|
||||
def CheckSigs(self, keys, sig_data):
|
||||
try:
|
||||
self.ctx.verify(sig_data)
|
||||
except:
|
||||
pass # TODO
|
||||
|
@ -665,6 +665,34 @@
|
||||
<xs:element name="comment" type="xs:string" maxOccurs="1"
|
||||
minOccurs="0"/>
|
||||
<!-- END BDISK/PROFILE/GPG/KEY/COMMENT -->
|
||||
<!-- BDISK/PROFILE/GPG/KEY/SUBKEY -->
|
||||
<xs:element name="subkey" maxOccurs="1" minOccurs="0">
|
||||
<xs:complexType>
|
||||
<!-- See below for notes on attributes. -->
|
||||
<!-- TODO: convert into shared type for parent as well? -->
|
||||
<xs:attribute name="algo" use="optional">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value="rsa"/>
|
||||
<xs:enumeration value="dsa"/>
|
||||
<xs:enumeration value="ed"/>
|
||||
<xs:enumeration value="nist"/>
|
||||
<xs:enumeration value="brainpool.1"/>
|
||||
<xs:enumeration value="sec.k1"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="keysize" type="xs:positiveInteger" use="optional"/>
|
||||
<xs:attribute name="expire" use="optional">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:pattern value="(0|[0-9]{10})"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<!-- END BDISK/PROFILE/GPG/KEY/SUBKEY -->
|
||||
</xs:all>
|
||||
<xs:attribute name="algo" use="optional">
|
||||
<xs:simpleType>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import copy
|
||||
import os
|
||||
import pprint
|
||||
import re
|
||||
@ -210,16 +211,24 @@ class Conf(object):
|
||||
for attr in elem.xpath('./@*'):
|
||||
self.cfg['gpg'][attr.attrname] = transform.xml2py(attr)
|
||||
for key in elem.xpath('./key'):
|
||||
_key = {'algo': 'rsa',
|
||||
'keysize': '4096',
|
||||
'expire': '0',
|
||||
'name': None,
|
||||
'email': None,
|
||||
'comment': None}
|
||||
_keytpl = {'algo': 'rsa',
|
||||
'keysize': '4096'}
|
||||
_key = copy.deepcopy(_keytpl)
|
||||
_key['name'] = None
|
||||
_key['email'] = None
|
||||
_key['comment'] = None
|
||||
for attr in key.xpath('./@*'):
|
||||
_key[attr.attrname] = transform.xml2py(attr)
|
||||
for param in key.xpath('./*'):
|
||||
_key[param.tag] = transform.xml2py(param.text, attrib = False)
|
||||
if param.tag == 'subkey':
|
||||
# We only support one subkey (for key generation).
|
||||
if 'subkey' not in _key:
|
||||
_key['subkey'] = copy.deepcopy(_keytpl)
|
||||
for attr in param.xpath('./@*'):
|
||||
_key['subkey'][attr.attrname] = transform.xml2py(attr)
|
||||
print(_key)
|
||||
else:
|
||||
_key[param.tag] = transform.xml2py(param.text, attrib = False)
|
||||
self.cfg['gpg']['keys'].append(_key)
|
||||
return()
|
||||
|
||||
|
@ -135,7 +135,8 @@ class detect(object):
|
||||
return(salt)
|
||||
|
||||
def remote_files(self, url_base, ptrn = None, flags = []):
|
||||
soup = BeautifulSoup(Download(url_base, progress = False).bytes_obj, 'lxml')
|
||||
soup = BeautifulSoup(Download(url_base, progress = False).fetch().decode('utf-8'),
|
||||
'lxml')
|
||||
urls = []
|
||||
if 'regex' in flags:
|
||||
if not isinstance(ptrn, str):
|
||||
|
@ -136,13 +136,15 @@
|
||||
</subject>
|
||||
</client>
|
||||
</pki>
|
||||
<!-- If prompt_passphrase is "no" and passphrase attribute is not given for a gpg element, we will try to use a
|
||||
<!-- If prompt_passphrase is false and passphrase attribute is not given for a gpg element, we will try to use a
|
||||
blank passphrase for all operations. -->
|
||||
<gpg keyid="none" gnupghome="none" publish="false" prompt_passphrase="false">
|
||||
<!-- The below is only used if we are generating a key (i.e. keyid="none"). -->
|
||||
<key algo="rsa" keysize="4096" expire="0">
|
||||
<name>{xpath%../../../meta/dev/author/text()}</name>
|
||||
<email>{xpath%../../../meta/dev/email/text()}</email>
|
||||
<!-- If present, the subkey element will create a secondary key used *only* for signing. This is good security practice. Obviously, this is only used if we are creating a new (master) key. -->
|
||||
<subkey algo="ed" keysize="25519" expire="0"/>
|
||||
<comment>for {xpath%../../../meta/names/pname/text()} [autogenerated] | {xpath%../../../meta/uri/text()} | {xpath%../../../meta/desc/text()}</comment>
|
||||
</key>
|
||||
</gpg>
|
||||
|
Loading…
Reference in New Issue
Block a user