def evaluate_pgp(self, tree, check_sigs=True, decrypt=False): pgpdata = [] for part in tree['text_parts']: # Handle signed messages if check_sigs and GnuPG: if part['type'] == 'pgpbeginsigned': pgpdata = [part] elif part['type'] == 'pgpsignedtext': pgpdata.append(part) elif part['type'] == 'pgpsignature': pgpdata.append(part) try: message = ''.join([p['data'].encode(p['charset']) for p in pgpdata]) gpg = GnuPG().run(['--utf8-strings', '--verify'], create_fhs=['stdin', 'stderr']) gpg.handles['stdin'].write(message) gpg.handles['stdin'].close() result = '' for fh in ('stderr', ): result += gpg.handles[fh].read() gpg.handles[fh].close() gpg.wait() pgpdata[0]['data'] = result.decode('utf-8')+'\n' for p in pgpdata: p['type'] = self.PGP_OK.get(p['type'], p['type']) except IOError: part['data'] += result.decode('utf-8') except: part['data'] += traceback.format_exc() pgpdata = [] if decrypt and GnuPG: if part['type'] in ('pgpbegin', 'pgptext'): pgpdata.append(part) elif part['type'] == 'pgpend': pgpdata.append(part) try: message = ''.join([p['data'] for p in pgpdata]) gpg = GnuPG().run(['--utf8-strings'], create_fhs=['stdin', 'stdout', 'stderr']) gpg.handles['stdin'].write(message) gpg.handles['stdin'].close() results = {} for fh in ('stderr', 'stdout'): results[fh] = gpg.handles[fh].read() gpg.handles[fh].close() gpg.wait() pgpdata[0]['data'] = results['stderr'].decode('utf-8')+'\n' pgpdata[1]['data'] = self._decode_gpg(message, results['stdout']) for p in pgpdata: p['type'] = self.PGP_OK.get(p['type'], p['type']) except IOError: part['data'] += results['stderr'].decode('utf-8') except: part['data'] += traceback.format_exc() pgpdata = [] return tree
def fingerprints(self): """Fetch a key's fingerprints and other details.""" session, config, arg = self.session, self.session.config, self.args[0] keys = [] try: session.ui.mark('Listing available GPG keys') gpg = GnuPG().run(['--fingerprint', arg], create_fhs=['stderr', 'stdout']) keylines = gpg.handles['stdout'].readlines() raise Exception("IMPLEMENT ME!") session.ui.display_gpg_keys(keys) except IOError: return False return True
def parse_pgpmime(self, message): sig_count, sig_parts, sig_alg = 0, [], 'SHA1' enc_count, enc_parts, enc_ver = 0, [], None for part in message.walk(): mimetype = part.get_content_type() if (sig_count > 1) and (mimetype == 'application/pgp-signature'): sig = tempfile.NamedTemporaryFile() sig.write(part.get_payload()) sig.flush() msg = '\r\n'.join( sig_parts[0].as_string().splitlines(False)) + '\r\n' result = None try: gpg = GnuPG().run( ['--utf8-strings', '--verify', sig.name, '-'], create_fhs=['stdin', 'stderr']) gpg.handles['stdin'].write(msg) gpg.handles['stdin'].close() result = gpg.handles['stderr'].read().decode('utf-8') gpg.wait() summary = ('verified', result) except IOError: summary = ('signed', result or 'Error running GnuPG') for sig_part in sig_parts: sig_part.openpgp = summary # Reset! sig_count, sig_parts = 0, [] elif sig_count > 0: sig_parts.append(part) sig_count += 1 elif enc_count > 0: # FIXME: Decrypt and parse! pass elif mimetype == 'multipart/signed': sig_alg = part.get_param('micalg', 'pgp-sha1').split('-')[1].upper() sig_count = 1 elif mimetype == 'multipart/encrypted': enc_count = 1
def recv_key(self): """Fetch a PGP public key from a keyserver.""" session, config, arg = self.session, self.session.config, self.args[0] try: session.ui.mark('Invoking GPG to fetch key %s' % arg) keyserver = config.get('gpg_keyserver', 'pool.sks-keyservers.net') gpg = GnuPG().run([ '--utf8-strings', '--keyserver', keyserver, '--recv-key', arg ], create_fhs=['stderr']) session.ui.debug(gpg.handles['stderr'].read().decode('utf-8')) gpg.handles['stderr'].close() gpg.wait() session.ui.mark('Fetched key %s' % arg) except IOError: return self._error('Failed to fetch key %s' % arg) return True
def list_keys(self): """Get a list of available PGP public keys.""" session, config = self.session, self.session.config keys = [] try: session.ui.mark('Listing available GPG keys') gpg = GnuPG().run(['--list-keys'], create_fhs=['stderr', 'stdout']) keylines = gpg.handles['stdout'].readlines() curkey = {} for line in keylines: if line[0:3] == "pub": if curkey != {}: keys.append(curkey) curkey = {} args = line.split("pub")[1].strip().split(" ") if len(args) == 3: expiry = args[2] else: expiry = None keytype, keyid = args[0].split("/") created = args[1] curkey["subkeys"] = [] curkey["uids"] = [] curkey["pub"] = { "keyid": keyid, "type": keytype, "created": created, "expires": expiry } elif line[0:3] == "sec": if curkey != {}: keys.append(curkey) curkey = {} args = line.split("pub")[1].strip().split(" ") if len(args) == 3: expiry = args[2] else: expiry = None keytype, keyid = args[0].split("/") created = args[1] curkey["subkeys"] = [] curkey["uids"] = [] curkey["sec"] = { "keyid": keyid, "type": keytype, "created": created, "expires": expiry } elif line[0:3] == "uid": curkey["uids"].append(line.split("uid")[1].strip()) elif line[0:3] == "sub": args = line.split("sub")[1].strip().split(" ") if len(args) == 3: expiry = args[2] else: expiry = None keytype, keyid = args[0].split("/") created = args[1] curkey["subkeys"].append({ "keyid": keyid, "type": keytype, "created": created, "expires": expiry }) gpg.handles['stderr'].close() gpg.handles['stdout'].close() gpg.wait() session.ui.display_gpg_keys(keys) except IndexError, e: self._ignore_exception()
def parse_pgpmime(self, message): sig_count, sig_parts, sig_alg = 0, [], 'SHA1' enc_count, enc_parts, enc_ver = 0, [], None for part in message.walk(): mimetype = part.get_content_type() if (sig_count > 1) and (mimetype == 'application/pgp-signature'): sig = tempfile.NamedTemporaryFile() sig.write(part.get_payload()) sig.flush() msg = '\r\n'.join( sig_parts[0].as_string().splitlines(False)) + '\r\n' result = None try: gpg = GnuPG().run( ['--utf8-strings', '--verify', sig.name, '-'], create_fhs=['stdin', 'stderr']) gpg.handles['stdin'].write(msg) gpg.handles['stdin'].close() result = gpg.handles['stderr'].read().decode('utf-8') gpg.wait() summary = ('verified', result) except IOError: if not result: summary = ('signed', 'Error running GnuPG') else: reslines = [ g.split("gpg: ")[1] for g in result.strip().split("\n") ] matchgr = re.match( ".*made (.*) using (.*) key ID ([a-zA-Z0-9]{8}).*", reslines[0]) keyid = matchgr.groups()[2] keytype = matchgr.groups()[1] datetime = matchgr.groups()[0] # FIXME: This should understand what kind of UI we have. summary = ( 'signed', "Signed %s with %s key 0x%s (<a onclick=\"mailpile.gpgrecvkey('%s');\">fetch key</a>)" % (datetime, keytype, keyid, keyid)) for sig_part in sig_parts: sig_part.openpgp = summary # Reset! sig_count, sig_parts = 0, [] elif sig_count > 0: sig_parts.append(part) sig_count += 1 elif enc_count > 0 and (mimetype == 'application/octet-stream'): # FIXME: Decrypt and parse! crypt = tempfile.NamedTemporaryFile() crypt.write(part.get_payload()) crypt.flush() msg = '\r\n'.join(part.as_string().splitlines(False)) + '\r\n' print msg result = None try: gpg = GnuPG().run(['--utf8-strings', '--decrypt'], create_fhs=['stdin', 'stdout', 'stderr']) gpg.handles['stdin'].write(msg) gpg.handles['stdin'].close() result = gpg.handles['stdout'].read().decode('utf-8') gpg.wait() print "Decrypted:" print result summary = ('decrypted', result) # part.attach(result) s = StringIO.StringIO() s.write(result) m = Parser().parse(s) print m m = Message() m.set_payload(result) part.set_payload([m]) # print part.__module__ # enc_parts.append(part) except IOError: if not result: summary = ('encrypted', 'Error running GnuPG') else: #reslines = [g.split("gpg: ")[1] for g in result.strip().split("\n")] #matchgr = re.match(".*made (.*) using (.*) key ID ([a-zA-Z0-9]{8}).*", reslines[0]) #keyid = matchgr.groups()[2] #keytype = matchgr.groups()[1] #datetime = matchgr.groups()[0] # FIXME: This should understand what kind of UI we have. print "FAIL" summary = ('encrypted', result) for enc_part in enc_parts: enc_part.openpgp = summary # Reset! enc_count, enc_parts = 0, [] elif mimetype == 'multipart/signed': sig_alg = part.get_param('micalg', 'pgp-sha1').split('-')[1].upper() sig_count = 1 elif mimetype == 'multipart/encrypted': enc_count = 1