def get_public_key_data(fpr, keyring=None): """Returns keydata for a given fingerprint In fact, fpr could be anything that gpg happily exports. """ if not keyring: keyring = Keyring() keydata = keyring.export_data(fpr) return keydata
def get_public_key_data(fpr, homedir=None): """Returns keydata for a given fingerprint In fact, fpr could be anything that gpg happily exports. """ keyring = Keyring(homedir=homedir) keydata = keyring.export_data(fpr) if not keydata: s = "No data to export for {} (in {})".format(fpr, homedir) raise ValueError(s) return keydata
def get_public_key_data(fpr, homedir=None): """Returns keydata for a given fingerprint In fact, fpr could be anything that gpg happily exports. """ keyring = Keyring(homedir=homedir) keydata = keyring.export_data(fpr) if not keydata: s = "No data to export for {} (in {})".format(fpr, homedir) raise ValueError(s) return keydata
def __init__(self, base_keyring=None, *args, **kwargs): # Not a new style class... if issubclass(self.__class__, object): super(TempSigningKeyring, self).__init__(*args, **kwargs) else: TempKeyring.__init__(self, *args, **kwargs) if base_keyring is None: base_keyring = Keyring() # Copy the public parts of the secret keys to the tmpkeyring for fpr, key in base_keyring.get_keys(None, secret=True, public=False).items(): self.import_data(base_keyring.export_data(fpr))
def __init__(self, base_keyring=None, *args, **kwargs): # Not a new style class... if issubclass(self.__class__, object): super(TempSigningKeyring, self).__init__(*args, **kwargs) else: TempSplitKeyring.__init__(self, *args, **kwargs) if base_keyring is None: base_keyring = Keyring() # Copy the public parts of the secret keys to the tmpkeyring for fpr, key in base_keyring.get_keys(None, secret=True, public=False).items(): self.import_data (base_keyring.export_data (fpr))
class KeySignSection(Gtk.VBox): def __init__(self): '''Initialises the section which lets the user choose a key to be signed by other person. ''' super(KeySignSection, self).__init__() self.log = logging.getLogger(__name__) self.keyring = Keyring() # these are needed later when we need to get details about # a selected key self.keysPage = KeysPage() self.keysPage.connect('key-selection-changed', self.on_key_selection_changed) self.keysPage.connect('key-selected', self.on_key_selected) self.keyDetailsPage = KeyDetailsPage() self.keyPresentPage = KeyPresentPage() # create back button self.backButton = Gtk.Button('Back') self.backButton.set_image( Gtk.Image.new_from_icon_name("go-previous", Gtk.IconSize.BUTTON)) self.backButton.set_always_show_image(True) self.backButton.connect('clicked', self.on_button_clicked) # set up notebook container self.notebook = Gtk.Notebook() self.notebook.append_page(self.keysPage, None) vbox = Gtk.VBox() # We place the button at the top, but that might not be the # smartest thing to do. Feel free to rearrange # FIXME: Consider a GtkHeaderBar for the application vbox.pack_start(self.backButton, False, False, 0) vbox.pack_start(self.keyPresentPage, True, True, 10) self.notebook.append_page(vbox, None) self.notebook.set_show_tabs(False) self.pack_start(self.notebook, True, True, 0) # this will hold a reference to the last key selected self.last_selected_key = None # When obtaining a key is successful, # it will save the key data in this field self.received_key_data = None self.keyserver = None def on_key_selection_changed(self, pane, keyid): '''This callback is attached to the signal which is emitted when the user changes their selection in the list of keys ''' pass def on_key_selected(self, pane, keyid): '''This is the callback for when the user has committed to a key, i.e. the user has made a selection and wants to advance the program. ''' log.debug('User selected key %s', keyid) key = list(self.keyring.get_keys(keyid).values())[0] keyid = key.keyid() fpr = key.fpr self.keyring.export_data(fpr, secret=False) keydata = self.keyring.context.stdout self.log.debug("Keyserver switched on! Serving key with fpr: %s", fpr) self.setup_server(keydata, fpr) self.switch_to_key_present_page(key) def switch_to_key_present_page(self, key): '''This switches the notebook to the page which presents the information that is needed to securely transfer the keydata, i.e. the fingerprint and its barcode. ''' self.keyPresentPage.display_fingerprint_qr_page(key) self.notebook.next_page() # This is more of a crude hack. Once the next page is presented, # the back button has the focus. This is not desirable because # you will go back when accidentally pressing space or enter. self.keyPresentPage.fingerprintLabel.grab_focus() # FIXME: we better use set_current_page, but that requires # knowing which page our desired widget is on. # FWIW: A headerbar has named pages. def on_next_button_clicked(self, button): '''A helper for legacy reasons to enable a next button All it does is retrieve the selection from the TreeView and call the signal handler for when the user committed to a key ''' name, email, keyid = self.keysPage.get_items_from_selection() return self.on_key_selected(button, keyid) def on_button_clicked(self, button): page_index = self.notebook.get_current_page() if button == self.backButton: if page_index == 1: self.log.debug("Keyserver switched off") self.stop_server() self.notebook.prev_page() def setup_server(self, keydata, fingerprint): """ Starts the key-server which serves the provided keydata and announces the fingerprint as TXT record using Avahi """ self.log.info('Serving now') self.log.debug('About to call %r', Keyserver.ServeKeyThread) self.keyserver = Keyserver.ServeKeyThread(str(keydata), fingerprint) self.log.info('Starting thread %r', self.keyserver) self.keyserver.start() self.log.info('Finsihed serving') return False def stop_server(self): self.keyserver.shutdown()
def sign_key_async(self, fingerprint=None, callback=None, data=None, error_cb=None): self.log.debug("I will sign key with fpr {}".format(fingerprint)) keyring = Keyring() keyring.context.set_option('export-options', 'export-minimal') tmpkeyring = TempSigningKeyring(keyring) # Eventually, we want to let the user select their keys to sign with # For now, we just take whatever is there. secret_keys = get_usable_secret_keys(tmpkeyring) self.log.info('Signing with these keys: %s', secret_keys) keydata = data or self.received_key_data if keydata: stripped_key = MinimalExport(keydata) fpr = fingerprint_for_key(stripped_key) if fingerprint is None: # The user hasn't provided any data to operate on fingerprint = fpr if not fingerprint == fpr: self.log.warning('Something strange is going on. ' 'We wanted to sign fingerprint "%s", received ' 'keydata to operate on, but the key has fpr "%s".', fingerprint, fpr) else: # Do we need this branch at all? if fingerprint is None: raise ValueError('You need to provide either keydata or a fpr') self.log.debug("looking for key %s in your keyring", fingerprint) keyring.context.set_option('export-options', 'export-minimal') stripped_key = keyring.export_data(fingerprint) self.log.debug('Trying to import key\n%s', stripped_key) if tmpkeyring.import_data(stripped_key): # 3. for every user id (or all, if -a is specified) # 3.1. sign the uid, using gpg-agent keys = tmpkeyring.get_keys(fingerprint) self.log.info("Found keys %s for fp %s", keys, fingerprint) assert len(keys) == 1, "We received multiple keys for fp %s: %s" % (fingerprint, keys) key = keys[fingerprint] uidlist = key.uidslist for secret_key in secret_keys: secret_fpr = secret_key.fpr self.log.info('Setting up to sign with %s', secret_fpr) # We need to --always-trust, because GnuPG would print # warning about the trustdb. I think this is because # we have a newly signed key whose trust GnuPG wants to # incorporate into the trust decision. tmpkeyring.context.set_option('always-trust') tmpkeyring.context.set_option('local-user', secret_fpr) # FIXME: For now, we sign all UIDs. This is bad. ret = tmpkeyring.sign_key(uidlist[0].uid, signall=True) self.log.info("Result of signing %s on key %s: %s", uidlist[0].uid, fingerprint, ret) for uid in uidlist: uid_str = uid.uid self.log.info("Processing uid %s %s", uid, uid_str) # 3.2. export and encrypt the signature # 3.3. mail the key to the user signed_key = UIDExport(uid_str, tmpkeyring.export_data(uid_str)) self.log.info("Exported %d bytes of signed key", len(signed_key)) # self.signui.tmpkeyring.context.set_option('armor') tmpkeyring.context.set_option('always-trust') encrypted_key = tmpkeyring.encrypt_data(data=signed_key, recipient=uid_str) keyid = str(key.keyid()) ctx = { 'uid' : uid_str, 'fingerprint': fingerprint, 'keyid': keyid, } # We could try to dir=tmpkeyring.dir # We do not use the with ... as construct as the # tempfile might be deleted before the MUA had the chance # to get hold of it. # Hence we reference the tmpfile and hope that it will be properly # cleaned up when this object will be destroyed... tmpfile = NamedTemporaryFile(prefix='gnome-keysign-', suffix='.asc') self.tmpfiles.append(tmpfile) filename = tmpfile.name self.log.info('Writing keydata to %s', filename) tmpfile.write(encrypted_key) # Interesting, sometimes it would not write the whole thing out, # so we better flush here tmpfile.flush() # As we're done with the file, we close it. #tmpfile.close() subject = Template(SUBJECT).safe_substitute(ctx) body = Template(BODY).safe_substitute(ctx) self.email_file (to=uid_str, subject=subject, body=body, files=[filename]) # FIXME: Can we get rid of self.tmpfiles here already? Even if the MUA is still running? # 3.4. optionnally (-l), create a local signature and import in # local keyring # 4. trash the temporary keyring else: self.log.error('data found in barcode does not match a OpenPGP fingerprint pattern: %s', fingerprint) if error_cb: GLib.idle_add(error_cb, data) return False
def sign_key_async(self, fingerprint=None, callback=None, data=None, error_cb=None): self.log.debug("I will sign key with fpr {}".format(fingerprint)) keyring = Keyring() keyring.context.set_option('export-options', 'export-minimal') tmpkeyring = TempSigningKeyring(keyring) # Eventually, we want to let the user select their keys to sign with # For now, we just take whatever is there. secret_keys = get_usable_secret_keys(tmpkeyring) self.log.info('Signing with these keys: %s', secret_keys) keydata = data or self.received_key_data if keydata: stripped_key = MinimalExport(keydata) fpr = fingerprint_for_key(stripped_key) if fingerprint is None: # The user hasn't provided any data to operate on fingerprint = fpr if not fingerprint == fpr: self.log.warning('Something strange is going on. ' 'We wanted to sign fingerprint "%s", received ' 'keydata to operate on, but the key has fpr "%s".', fingerprint, fpr) else: # Do we need this branch at all? if fingerprint is None: raise ValueError('You need to provide either keydata or a fpr') self.log.debug("looking for key %s in your keyring", fingerprint) keyring.context.set_option('export-options', 'export-minimal') stripped_key = keyring.export_data(fingerprint) self.log.debug('Trying to import key\n%s', stripped_key) if tmpkeyring.import_data(stripped_key): # 3. for every user id (or all, if -a is specified) # 3.1. sign the uid, using gpg-agent keys = tmpkeyring.get_keys(fingerprint) self.log.info("Found keys %s for fp %s", keys, fingerprint) assert len(keys) == 1, "We received multiple keys for fp %s: %s" % (fingerprint, keys) key = keys[fingerprint] uidlist = key.uidslist for secret_key in secret_keys: secret_fpr = secret_key.fpr self.log.info('Setting up to sign with %s', secret_fpr) # We need to --always-trust, because GnuPG would print # warning about the trustdb. I think this is because # we have a newly signed key whose trust GnuPG wants to # incorporate into the trust decision. tmpkeyring.context.set_option('always-trust') tmpkeyring.context.set_option('local-user', secret_fpr) # FIXME: For now, we sign all UIDs. This is bad. ret = tmpkeyring.sign_key(uidlist[0].uid, signall=True) self.log.info("Result of signing %s on key %s: %s", uidlist[0].uid, fingerprint, ret) for uid in uidlist: uid_str = uid.uid self.log.info("Processing uid %s %s", uid, uid_str) # 3.2. export and encrypt the signature # 3.3. mail the key to the user signed_key = UIDExport(uid_str, tmpkeyring.export_data(uid_str)) self.log.info("Exported %d bytes of signed key", len(signed_key)) # self.signui.tmpkeyring.context.set_option('armor') tmpkeyring.context.set_option('always-trust') encrypted_key = tmpkeyring.encrypt_data(data=signed_key, recipient=uid_str) keyid = str(key.keyid()) ctx = { 'uid' : uid_str, 'fingerprint': fingerprint, 'keyid': keyid, } # We could try to dir=tmpkeyring.dir # We do not use the with ... as construct as the # tempfile might be deleted before the MUA had the chance # to get hold of it. # Hence we reference the tmpfile and hope that it will be properly # cleaned up when this object will be destroyed... tmpfile = NamedTemporaryFile(prefix='gnome-keysign-', suffix='.asc') self.tmpfiles.append(tmpfile) filename = tmpfile.name self.log.info('Writing keydata to %s', filename) tmpfile.write(encrypted_key) # Interesting, sometimes it would not write the whole thing out, # so we better flush here tmpfile.flush() # As we're done with the file, we close it. #tmpfile.close() subject = Template(SUBJECT).safe_substitute(ctx) body = Template(BODY).safe_substitute(ctx) self.email_file (to=uid_str, subject=subject, body=body, files=[filename]) # FIXME: Can we get rid of self.tmpfiles here already? Even if the MUA is still running? # 3.4. optionnally (-l), create a local signature and import in # local keyring # 4. trash the temporary keyring else: self.log.error('data found in barcode does not match a OpenPGP fingerprint pattern: %s', fingerprint) if error_cb: GLib.idle_add(error_cb, data) return False