예제 #1
0
 def cert_request(self, key_id: str, uid: str) -> PGPKey:
     key = self.personal_keystore.get_key(key_id)
     if key is None:
         raise CustomException("No key with requested key_id found.")
     key = self._extract_matching_uid(key, uid)
     if key is None:
         raise CustomException(
             "Requested key does not have the requested uid.")
     return key
예제 #2
0
 def cert_import_single(self, key: PGPKey) -> None:
     if len(key.userids) != 1:
         raise CustomException(
             "Certification contained more than one UserID.")
     uid: PGPUID = key.userids[0]
     if len(uid.__sig__) > 2:  # self-signature plus one certification
         logging.error(uid.__sig__)
         raise CustomException("More than one certification included")
     if not key.verify(uid):
         raise CustomException(
             "UserID was not self-signed. This UID does not belong on this key."
         )
     self.personal_keystore.add_userid(key, uid)
예제 #3
0
 def use_identity(self, key_id: str, reuse: bool = False) -> None:
     key = self.personal_keystore.get_key(key_id)
     if key is None:
         raise CustomException("Public Key with this ID not available")
     key = self.personal_keystore.get_private_key(key.fingerprint)
     if key is None:
         raise CustomException("Private Key with this ID not available")
     if self.personal_keystore.is_expended(key.fingerprint) and not reuse:
         raise CustomException(
             "Identity is marked as expended/previously used and reuse was not allowed. "
             "Use --reuse to explicitly allow it.")
     identity_name, identity_mail = identity_from_keyid(key_id)
     self.git_config.set_user_identity(identity_name, identity_mail, key_id)
예제 #4
0
    def _combine_key_parts(key_parts: List[PGPKey]) -> PGPKey:
        # pylint: disable=protected-access
        final_key = None

        for part in key_parts:
            if part is None:
                continue
            if final_key is None:
                # first key part
                final_key = copy(part)
                continue
            if not part.fingerprint == final_key.fingerprint:
                raise CustomException(
                    "Fingerprints don't match for key parts to be combined.")
            if final_key.is_public and not part.is_public:
                old_final_key = copy(final_key)
                # noinspection PyProtectedMember
                final_key._key = copy(part._key)
                final_key.pubkey = old_final_key
            for uid in part.userids:
                final_key |= uid
            for sig in part.__sig__:
                final_key |= sig
            for subkey in part.subkeys:
                final_key |= subkey

        return final_key
예제 #5
0
def extract_keyid_from_identity(
        identity: str) -> Tuple[str, Optional[pgpy.pgp.Fingerprint]]:
    regex = "^(ANON )?(?P<keyid>[1234567890abcdefABCDEF]+) ?.*$"
    match = re.match(regex, identity)
    if match is None:
        raise CustomException(
            "Not a git-anon identity. Format does not match.")
    keyid: str = match.groupdict()["keyid"]
    keyid_len = len(keyid)
    if keyid_len not in (16, 40):
        # keyid is invalid
        raise CustomException("Not a git-anon identity. Invalid length: ",
                              keyid_len)

    if keyid_len == 40:
        return keyid[-16:], pgpy.pgp.Fingerprint(keyid)
    return keyid[-16:], None
예제 #6
0
def cert_trust(input_file: TextIOWrapper) -> None:
    # todo require user to provide all acceptable uids as parameters
    for key in _parse_keys_from_list_of_lines(input_file.readlines()):
        if not key.is_public and key.is_protected:
            raise CustomException(
                "Encrypted/Protected keys are not supported. Remove protection before importing."
            )
        API.cert_import_certification_key(key)
예제 #7
0
 def reveal_identity(self, key_id: str, encrypted: bool) -> List[str]:
     key = self.personal_keystore.get_key(key_id)
     if key is None:
         raise CustomException("No identity with given id could be found.")
     revealed_uids = []
     for uid in key.userids:
         self.shared_keystore.add_userid(key, uid, encrypted)
         revealed_uids.append(uid_as_str(uid))
     return revealed_uids
예제 #8
0
    def get_private_key(self, fingerprint: str) -> Optional[PGPKey]:
        expected_fingerprint = Fingerprint(fingerprint)
        key_file = self._get_private_key_location(expected_fingerprint)

        try:
            key, _ = PGPKey.from_file(key_file)
        except FileNotFoundError:
            return None

        if not key.fingerprint == expected_fingerprint:
            raise CustomException("Actual fingerprint for stored private key does not match expected one. ({})".format(
                expected_fingerprint))
        self._strip_signatures_uids_subkeys(key)

        pubkey = self.get_key(key.fingerprint.keyid, key.fingerprint)
        if pubkey is None:
            raise CustomException(
                "Missing public key for fingerprint {}, while private is available".format(expected_fingerprint))
        return self._combine_key_parts([pubkey, key])
예제 #9
0
    def unmask_identity(
            self, anonymous_identity: str) -> Tuple[List[str], List[str]]:
        keyid, fingerprint = extract_keyid_from_identity(anonymous_identity)

        key = self.shared_keystore.get_key(keyid, fingerprint)
        if key is None:
            raise CustomException("Unknown Identity: Public Key not found.")
        uids = key.userids
        if len(uids) == 0:
            # this would make the identity malformed as it has to have at least a pseudo uid.
            raise CustomException("Unknown Identity: Identity has no UserIDs")
        unverified_attributes = []
        verified_attributes = []
        for uid in uids:
            if verify_uid(uid, self.trusted_keystore):
                verified_attributes.append(uid_as_str(uid))
            else:
                unverified_attributes.append(uid_as_str(uid))
        return verified_attributes, unverified_attributes
예제 #10
0
 def reveal_attribute(self,
                      key_id: str,
                      attribute: str,
                      encrypted: bool = True) -> List[str]:
     key = self.personal_keystore.get_key(key_id)
     if key is None:
         raise CustomException("No identity with given id could be found.")
     revealed_uids = []
     for uid in key.userids:
         if uid_as_str(uid) == attribute:
             self.shared_keystore.add_userid(key, uid, encrypted)
             revealed_uids.append(uid_as_str(uid))
             # This also accepts previously revealed user ids and reveals them again.
             #   (which should not create a new file)
     if len(revealed_uids) == 0:
         raise CustomException(
             "This attribute has not been added for this identity. "
             "Please add it before attempting to reveal it.")
     return revealed_uids
예제 #11
0
 def _write_file(self, filename: str, data: bytes) -> None:
     if os.path.isfile(filename):
         # We already stored this exact serialized packet.
         with open(filename, "rb") as file:
             if not file.read() == data:
                 raise CustomException(
                     "Writing to {} failed. File already exists but contents are not as expected."
                     .format(filename))
         return
     with open(filename, "wb") as file:
         file.write(data)
예제 #12
0
 def cert_gen_key(self, uids: List[str]) -> Tuple[PGPKey, PGPKey]:
     pgpy_uids = []
     for uid in uids:
         pgpy_uid = parse_uid(uid)
         if pgpy_uid is None:
             raise CustomException(
                 "UID '{}' could not be parsed".format(uid))
         pgpy_uids.append(pgpy_uid)
     pub, sec = create_identity_internal(None, pgpy_uids)
     self.trusted_keystore.store_key(sec)
     return pub, sec
예제 #13
0
    def _get_primary_key(
            self, keyid: str,
            fingerprint: Optional[pgpy.pgp.Fingerprint]) -> Optional[PGPKey]:
        possible_location: str
        if fingerprint is not None:
            if fingerprint.keyid != keyid:
                raise CustomException(
                    "Keyid does not match with end of provided fingerprint.")
            possible_location = self._folder_for_fingerprint(fingerprint)
        else:
            potential_locations = self._folders_for_keyid(keyid)
            if len(potential_locations) == 0:
                return None
            if len(potential_locations) > 1:
                message = "Found more than one key with id " + keyid + ": keys:"
                for potential_location in potential_locations:
                    fpr = potential_location[:-40]
                    message += "\n  fpr:" + fpr
                message += "Consider yourself lucky. This might be a sensation and is so unlikely that no code was " \
                           "written to handle this situation."
                raise CustomException(message)
            possible_location = potential_locations[0]

        if not os.path.isdir(possible_location):
            # the requested key is not available
            return None

        primary_key_file = os.path.join(possible_location, "primary_key.pub")
        if not os.path.isfile(primary_key_file):
            # the folder exists but the primary key does not
            return None

        key, _ = pgpy.PGPKey.from_file(primary_key_file)

        if not possible_location == self._folder_for_fingerprint(
                key.fingerprint):
            # the fingerprint does not match the storage location
            return None

        return self._verify_primary_key(key, keyid, fingerprint,
                                        self._expected_pseudo_uid())
예제 #14
0
    def store_key(self, key: PGPKey) -> None:
        key = copy(key)
        self.add_key_and_all_uids(key)
        key_file = self._get_private_key_location(key.fingerprint)

        self._strip_signatures_uids_subkeys(key)

        if key.is_protected:
            raise CustomException("Protected/Encrypted keys are currently not supported.")

        key_encoded: bytes = bytes(str(key), "utf-8")
        self._write_file(key_file, key_encoded)
예제 #15
0
    def derive_key(self, enc_params_file: str, encryption_key: str,
                   cache_dir_path) -> str:
        with open(enc_params_file, "r") as file:
            scrypt_n = self.scrypt_n
            scrypt_r = self.scrypt_r
            scrypt_p = self.scrypt_p
            salt: str = "default-salt"
            verification_hash: Optional[str] = None
            for _, line in enumerate(file):
                if line.startswith("salt: "):
                    salt = line.replace("salt: ", "").strip()
                if line.startswith("hash: "):
                    verification_hash = line.replace("hash: ", "").strip()
                if line.startswith("scrypt_n: "):
                    scrypt_n = int(line.replace("scrypt_n: ", "").strip())
                if line.startswith("scrypt_r: "):
                    scrypt_r = int(line.replace("scrypt_r: ", "").strip())
                if line.startswith("scrypt_p: "):
                    scrypt_p = int(line.replace("scrypt_p: ", "").strip())
        if verification_hash is None:
            raise CustomException(
                "No hash stored in enc_params file. Can not verify encryption key."
            )

        cached_derived_key = self._get_cached_derived_key(
            cache_dir_path, verification_hash)
        if cached_derived_key is not None and \
                KeyDerivationHelper.hash_encryption_key(cached_derived_key) == verification_hash:
            return cached_derived_key

        enc_key: str = KeyDerivationHelper._derive_key(salt, scrypt_n,
                                                       scrypt_r, scrypt_p,
                                                       encryption_key)
        enc_key_hashed = KeyDerivationHelper.hash_encryption_key(enc_key)
        if verification_hash != enc_key_hashed:
            raise CustomException("Invalid encryption key provided.")
        self._set_cached_derived_key(cache_dir_path, verification_hash,
                                     enc_key)
        return enc_key
예제 #16
0
 def reveal_name(self, key_id: str, encrypted: bool) -> str:
     """Reveals the primary name or attribute associated with the identity."""
     key = self.personal_keystore.get_key(key_id)
     if key is None:
         raise CustomException("No identity with given id could be found.")
     revealed_uids = []
     for uid in key.userids:
         if uid.is_primary:
             self.shared_keystore.add_userid(key, uid, encrypted)
             revealed_uids.append(uid_as_str(uid))
             # this also accepts previously revealed user ids and reveals them again
             #   (which should not create a new file)
     count = len(revealed_uids)
     if count == 0:
         raise CustomException(
             "No primary Attribute has been added for this identity. "
             "Please add it before attempting to reveal it.")
     if count >= 2:
         for uid in revealed_uids:
             logging.warning("Revealed: %s", uid)
         raise RuntimeWarning(
             "We just revealed more than one primary identity.")
     return revealed_uids[0]
예제 #17
0
 def _cert_sign_single(key: PGPKey, signature_key: PGPKey,
                       accepted_uids: List[str],
                       accept_any_uid: bool) -> Optional[PGPKey]:
     key = copy(key)
     if len(key.userids) > 1:
         logging.error(key)
         raise CustomException(
             "Key {} contained more than one UID. Not signing any of them.".
             format(key.fingerprint))
     key_uid = key.userids[0]
     if not key.verify(key_uid):
         raise CustomException(
             "Not signing UID '{}' on key {} due to missing self-signature."
             .format(key_uid, key.fingerprint))
     # The key might contain illegal components but these will simply be passed through for now.
     if uid_is_in(key_uid, accepted_uids) or accept_any_uid:
         if may_certify(key_uid, signature_key):
             certification = patched_pgpy_certify(
                 signature_key,
                 key_uid,
                 created=get_uniform_time_as_datetime())
             key_uid |= certification
             return key
     return None
예제 #18
0
def throw() -> None:
    raise CustomException("Test Exception", "Second")
예제 #19
0
def cert_request(uid: str, keyid: str, output_file: TextIOWrapper) -> None:
    key = API.cert_request(keyid, uid)
    if key is None:
        raise CustomException("No key with this key_id and uid found.")
    output_file.write(str(key))