def _prepare_uid_for_export( self, key: PGPKey, uid: PGPUID) -> Optional[Tuple[str, bytes, str]]: # ultimately we should separate uids. self-signatures and certifications and store them in individual files # uids and self-signatures can likely be stored together # for now we might have to store keys with one uid and associated self-signatures and certifications together # for compatibility with libraries and gpg itself # filter for the pubkey only and copy the key object so we don't affect other instances key = copy(key.pubkey) # abort if presented with the pseudo-uid to export if uid_equals(uid, get_pseudo_uid()): # the pseudo-uid is exported together with the primary key material and does not need to be exported again return None # filter the key to only requested information key = self._filter_uids_on_key(key, uid) if len(key.userids) != 1: raise AssertionError("Only one UID should remain!") # export the key serialized_key: bytes = bytes(key) key_folder = self._folder_for_fingerprint(key.fingerprint) uid_folder = os.path.join(key_folder, "uid-packets") os.makedirs(uid_folder, exist_ok=True) serialization_hash: str = sha256(serialized_key).hex() filename = os.path.join(uid_folder, serialization_hash) return filename, serialized_key, serialization_hash
def _auto_reveal_uids(self, key: PGPKey) -> None: for uid in key.userids: for identity in self.git_anon_config.identities: if uid_equals(uid, identity.pgp_uid): if identity.auto_reveal: self.shared_keystore.add_userid( key, uid, identity.auto_reveal_encrypted)
def strip_pseudo_uid(uids: List[PGPUID]) -> List[PGPUID]: filtered: List[PGPUID] = [] for uid in uids: if not uid_equals(get_pseudo_uid(), uid): filtered.append(uid) return filtered
def _filter_uids_on_key(key: PGPKey, desired_uid: PGPUID) -> PGPKey: key = copy(key) # remove all user ids except the pseudo uid for uid in key.userids: if not uid_equals(uid, desired_uid): key.del_uid(uid.name) # assert that no unwanted information is left if len(key.userids) != 1 or not uid_equals(key.userids[0], desired_uid): raise AssertionError("Unwanted information left on the key!") for _ in key.revocation_signatures: raise AssertionError("Keys should not have revocation signatures!") if len(key.signers) != 0: raise AssertionError("Keys should not be signed directly!") return key
def _verify_expected_uid(key: PGPKey, expected_uid: Optional[PGPUID]) -> bool: if expected_uid is not None: imported_uid: PGPUID = key.userids[0] if not uid_equals(imported_uid, expected_uid): # The pseudo uid was not included. # A different one might have been used instead. return False if len(imported_uid.signers) > 1: # more than one self-signature or a certification included return False return True
def test_uid_equals(self): self.assertTrue( uid_equals(PGPUID.new("a", "b", "c"), PGPUID.new("a", "b", "c"))) self.assertFalse( uid_equals(PGPUID.new("a", "b", "c"), PGPUID.new("A", "b", "c"))) self.assertFalse( uid_equals(PGPUID.new("a", "b", "c"), PGPUID.new("a", "B", "c"))) self.assertFalse( uid_equals(PGPUID.new("a", "b", "c"), PGPUID.new("a", "b", "C"))) self.assertFalse( uid_equals(PGPUID.new("a", "b", "c"), PGPUID.new("a", "b"))) uid = PGPUID.new("a") self.assertTrue(uid_equals(uid, uid))
def uid_not_contained(uids: List[PGPUID], new: PGPUID) -> bool: for uid in uids: if uid_equals(uid, new): return False return True