Esempio n. 1
0
 def read_signing_key(self, signing_key_path):
     signing_keys = self.read_file(signing_key_path, "signing_key")
     try:
         return read_signing_keys(signing_keys.splitlines(True))
     except Exception:
         raise ConfigError("Error reading signing_key."
                           " Try running again with --generate-config")
Esempio n. 2
0
 def read_signing_key(self, signing_key_path):
     signing_keys = self.read_file(signing_key_path, "signing_key")
     try:
         return read_signing_keys(signing_keys.splitlines(True))
     except Exception as e:
         raise ConfigError(
             "Error reading signing_key: %s" % (str(e))
         )
Esempio n. 3
0
 def read_signing_key(self, signing_key_path):
     signing_keys = self.read_file(signing_key_path, "signing_key")
     try:
         return read_signing_keys(signing_keys.splitlines(True))
     except Exception:
         raise ConfigError(
             "Error reading signing_key."
             " Try running again with --generate-config"
         )
Esempio n. 4
0
    def read_config(self, config, config_dir_path, **kwargs):
        # the signing key can be specified inline or in a separate file
        if "signing_key" in config:
            self.signing_key = read_signing_keys([config["signing_key"]])
        else:
            signing_key_path = config.get("signing_key_path")
            if signing_key_path is None:
                signing_key_path = os.path.join(
                    config_dir_path, config["server_name"] + ".signing.key")

            self.signing_key = self.read_signing_key(signing_key_path)

        self.old_signing_keys = self.read_old_signing_keys(
            config.get("old_signing_keys", {}))
        self.key_refresh_interval = self.parse_duration(
            config.get("key_refresh_interval", "1d"))

        # if neither trusted_key_servers nor perspectives are given, use the default.
        if "perspectives" not in config and "trusted_key_servers" not in config:
            key_servers = [{"server_name": "matrix.org"}]
        else:
            key_servers = config.get("trusted_key_servers", [])

            if not isinstance(key_servers, list):
                raise ConfigError(
                    "trusted_key_servers, if given, must be a list, not a %s" %
                    (type(key_servers).__name__, ))

            # merge the 'perspectives' config into the 'trusted_key_servers' config.
            key_servers.extend(_perspectives_to_key_servers(config))

        # list of TrustedKeyServer objects
        self.key_servers = list(
            _parse_key_servers(key_servers,
                               self.federation_verify_certificates))

        self.macaroon_secret_key = config.get("macaroon_secret_key",
                                              self.registration_shared_secret)

        if not self.macaroon_secret_key:
            # Unfortunately, there are people out there that don't have this
            # set. Lets just be "nice" and derive one from their secret key.
            logger.warn("Config is missing macaroon_secret_key")
            seed = bytes(self.signing_key[0])
            self.macaroon_secret_key = hashlib.sha256(seed).digest()

        self.expire_access_token = config.get("expire_access_token", False)

        # a secret which is used to calculate HMACs for form values, to stop
        # falsification of values
        self.form_secret = config.get("form_secret", None)
Esempio n. 5
0
    def read_signing_keys(self, signing_key_path, name):
        """Read the signing keys in the given path.

        Args:
            signing_key_path (str)
            name (str): Associated config key name

        Returns:
            list[SigningKey]
        """

        signing_keys = self.read_file(signing_key_path, name)
        try:
            return read_signing_keys(signing_keys.splitlines(True))
        except Exception as e:
            raise ConfigError("Error reading %s: %s" % (name, str(e)))
Esempio n. 6
0
def main() -> None:
    parser = argparse.ArgumentParser()

    parser.add_argument(
        "key_file",
        nargs="+",
        type=argparse.FileType("r"),
        help="The key file to read",
    )

    parser.add_argument(
        "-x",
        action="store_true",
        dest="for_config",
        help=
        "format the output for inclusion in the old_signing_keys config setting",
    )

    parser.add_argument(
        "--expiry-ts",
        type=int,
        default=int(time.time() * 1000) + 6 * 3600000,
        help=
        ("The expiry time to use for -x, in milliseconds since 1970. The default "
         "is (now+6h)."),
    )

    args = parser.parse_args()

    formatter = ((lambda k: format_for_config(k, args.expiry_ts))
                 if args.for_config else format_plain)

    for file in args.key_file:
        try:
            res = read_signing_keys(file)
        except Exception as e:
            exit(
                status=1,
                message="Error reading key from file %s: %s %s" %
                (file.name, type(e), e),
            )
        for key in res:
            formatter(get_verify_key(key))
Esempio n. 7
0
def main():
    config = yaml.load(open(sys.argv[1]))
    valid_until = int(time.time() / (3600 * 24)) * 1000 * 3600 * 24

    server_name = config["server_name"]
    signing_key = read_signing_keys(open(config["signing_key_path"]))[0]

    database = config["database"]
    assert database["name"] == "psycopg2", "Can only convert for postgresql"
    args = database["args"]
    args.pop("cp_max")
    args.pop("cp_min")
    connection = psycopg2.connect(**args)
    keys = select_v1_keys(connection)
    certificates = select_v1_certs(connection)
    json = select_v2_json(connection)

    result = {}
    for server in keys:
        if not server in json:
            v2_json = convert_v1_to_v2(
                server, valid_until, keys[server], certificates[server]
            )
            v2_json = sign_json(v2_json, server_name, signing_key)
            result[server] = v2_json

    yaml.safe_dump(result, sys.stdout, default_flow_style=False)

    rows = list(
        row for server, json in result.items()
        for row in rows_v2(server, json)
    )

    cursor = connection.cursor()
    cursor.executemany(
        "INSERT INTO server_keys_json ("
        " server_name, key_id, from_server,"
        " ts_added_ms, ts_valid_until_ms, key_json"
        ") VALUES (%s, %s, %s, %s, %s, %s)",
        rows
    )
    connection.commit()
def main():
    config = yaml.safe_load(open(sys.argv[1]))
    valid_until = int(time.time() / (3600 * 24)) * 1000 * 3600 * 24

    server_name = config["server_name"]
    signing_key = read_signing_keys(open(config["signing_key_path"]))[0]

    database = config["database"]
    assert database["name"] == "psycopg2", "Can only convert for postgresql"
    args = database["args"]
    args.pop("cp_max")
    args.pop("cp_min")
    connection = psycopg2.connect(**args)
    keys = select_v1_keys(connection)
    certificates = select_v1_certs(connection)
    json = select_v2_json(connection)

    result = {}
    for server in keys:
        if server not in json:
            v2_json = convert_v1_to_v2(server, valid_until, keys[server],
                                       certificates[server])
            v2_json = sign_json(v2_json, server_name, signing_key)
            result[server] = v2_json

    yaml.safe_dump(result, sys.stdout, default_flow_style=False)

    rows = [
        row for server, json in result.items()
        for row in rows_v2(server, json)
    ]

    cursor = connection.cursor()
    cursor.executemany(
        "INSERT INTO server_keys_json ("
        " server_name, key_id, from_server,"
        " ts_added_ms, ts_valid_until_ms, key_json"
        ") VALUES (%s, %s, %s, %s, %s, %s)",
        rows,
    )
    connection.commit()
Esempio n. 9
0
    def read_config(self, config):
        # the signing key can be specified inline or in a separate file
        if "signing_key" in config:
            self.signing_key = read_signing_keys([config["signing_key"]])
        else:
            self.signing_key_path = config["signing_key_path"]
            self.signing_key = self.read_signing_key(self.signing_key_path)

        self.old_signing_keys = self.read_old_signing_keys(
            config.get("old_signing_keys", {})
        )
        self.key_refresh_interval = self.parse_duration(
            config.get("key_refresh_interval", "1d"),
        )
        self.perspectives = self.read_perspectives(
            config.get("perspectives", {}).get("servers", {
                "matrix.org": {"verify_keys": {
                    "ed25519:auto": {
                        "key": "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw",
                    }
                }}
            })
        )

        self.macaroon_secret_key = config.get(
            "macaroon_secret_key", self.registration_shared_secret
        )

        if not self.macaroon_secret_key:
            # Unfortunately, there are people out there that don't have this
            # set. Lets just be "nice" and derive one from their secret key.
            logger.warn("Config is missing macaroon_secret_key")
            seed = bytes(self.signing_key[0])
            self.macaroon_secret_key = hashlib.sha256(seed).digest()

        self.expire_access_token = config.get("expire_access_token", False)

        # a secret which is used to calculate HMACs for form values, to stop
        # falsification of values
        self.form_secret = config.get("form_secret", None)
Esempio n. 10
0
    def read_config(self, config: JsonDict, config_dir_path: str,
                    **kwargs: Any) -> None:
        # the signing key can be specified inline or in a separate file
        if "signing_key" in config:
            self.signing_key = read_signing_keys([config["signing_key"]])
        else:
            assert config_dir_path is not None
            signing_key_path = config.get("signing_key_path")
            if signing_key_path is None:
                signing_key_path = os.path.join(
                    config_dir_path, config["server_name"] + ".signing.key")

            self.signing_key = self.read_signing_keys(signing_key_path,
                                                      "signing_key")

        self.old_signing_keys = self.read_old_signing_keys(
            config.get("old_signing_keys"))
        self.key_refresh_interval = self.parse_duration(
            config.get("key_refresh_interval", "1d"))

        suppress_key_server_warning = config.get("suppress_key_server_warning",
                                                 False)
        key_server_signing_keys_path = config.get(
            "key_server_signing_keys_path")
        if key_server_signing_keys_path:
            self.key_server_signing_keys = self.read_signing_keys(
                key_server_signing_keys_path, "key_server_signing_keys_path")
        else:
            self.key_server_signing_keys = list(self.signing_key)

        # if neither trusted_key_servers nor perspectives are given, use the default.
        if "perspectives" not in config and "trusted_key_servers" not in config:
            logger.warning(TRUSTED_KEY_SERVER_NOT_CONFIGURED_WARN)
            key_servers = [{"server_name": "matrix.org"}]
        else:
            key_servers = config.get("trusted_key_servers", [])

            if not isinstance(key_servers, list):
                raise ConfigError(
                    "trusted_key_servers, if given, must be a list, not a %s" %
                    (type(key_servers).__name__, ))

            # merge the 'perspectives' config into the 'trusted_key_servers' config.
            key_servers.extend(_perspectives_to_key_servers(config))

            if not suppress_key_server_warning and "matrix.org" in (
                    s["server_name"] for s in key_servers):
                logger.warning(TRUSTED_KEY_SERVER_CONFIGURED_AS_M_ORG_WARN)

        # list of TrustedKeyServer objects
        self.key_servers = list(
            _parse_key_servers(key_servers,
                               self.root.tls.federation_verify_certificates))

        macaroon_secret_key: Optional[str] = config.get(
            "macaroon_secret_key",
            self.root.registration.registration_shared_secret)

        if not macaroon_secret_key:
            # Unfortunately, there are people out there that don't have this
            # set. Lets just be "nice" and derive one from their secret key.
            logger.warning("Config is missing macaroon_secret_key")
            seed = bytes(self.signing_key[0])
            self.macaroon_secret_key = hashlib.sha256(seed).digest()
        else:
            self.macaroon_secret_key = macaroon_secret_key.encode("utf-8")

        # a secret which is used to calculate HMACs for form values, to stop
        # falsification of values
        self.form_secret = config.get("form_secret", None)
Esempio n. 11
0
 def test_read_keys(self):
     stream = ["ed25519 %s %s" % (self.version, self.key_base64)]
     keys = read_signing_keys(stream)
     self.assertEquals(len(keys), 1)
Esempio n. 12
0
def main() -> None:
    parser = argparse.ArgumentParser(
        description="""Adds a signature to a JSON object.

Example usage:

    $ scripts-dev/sign_json.py -N test -k localhost.signing.key "{}"
    {"signatures":{"test":{"ed25519:a_ZnZh":"LmPnml6iM0iR..."}}}
""",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )

    parser.add_argument(
        "-N",
        "--server-name",
        help="Name to give as the local homeserver. If unspecified, will be "
        "read from the config file.",
    )

    parser.add_argument(
        "-k",
        "--signing-key-path",
        help="Path to the file containing the private ed25519 key to sign the "
        "request with.",
    )

    parser.add_argument(
        "-K",
        "--signing-key",
        help="The private ed25519 key to sign the request with.",
    )

    parser.add_argument(
        "-c",
        "--config",
        default="homeserver.yaml",
        help=
        ("Path to synapse config file, from which the server name and/or signing "
         "key path will be read. Ignored if --server-name and --signing-key(-path) "
         "are both given."),
    )

    parser.add_argument(
        "--sign-event-room-version",
        type=str,
        help=
        ("Sign the JSON as an event for the given room version, rather than raw JSON. "
         "This means that we will add a 'hashes' object, and redact the event before "
         "signing."),
    )

    input_args = parser.add_mutually_exclusive_group()

    input_args.add_argument("input_data",
                            nargs="?",
                            help="Raw JSON to be signed.")

    input_args.add_argument(
        "-i",
        "--input",
        type=argparse.FileType("r"),
        default=sys.stdin,
        help=
        ("A file from which to read the JSON to be signed. If neither --input nor "
         "input_data are given, JSON will be read from stdin."),
    )

    parser.add_argument(
        "-o",
        "--output",
        type=argparse.FileType("w"),
        default=sys.stdout,
        help="Where to write the signed JSON. Defaults to stdout.",
    )

    args = parser.parse_args()

    if not args.server_name or not (args.signing_key_path or args.signing_key):
        read_args_from_config(args)

    if args.signing_key:
        keys = read_signing_keys([args.signing_key])
    else:
        with open(args.signing_key_path) as f:
            keys = read_signing_keys(f)

    json_to_sign = args.input_data
    if json_to_sign is None:
        json_to_sign = args.input.read()

    try:
        obj = json.loads(json_to_sign)
    except JSONDecodeError as e:
        print("Unable to parse input as JSON: %s" % e, file=sys.stderr)
        sys.exit(1)

    if not isinstance(obj, dict):
        print("Input json was not an object", file=sys.stderr)
        sys.exit(1)

    if args.sign_event_room_version:
        room_version = KNOWN_ROOM_VERSIONS.get(args.sign_event_room_version)
        if not room_version:
            print(f"Unknown room version {args.sign_event_room_version}",
                  file=sys.stderr)
            sys.exit(1)
        add_hashes_and_signatures(room_version, obj, args.server_name, keys[0])
    else:
        sign_json(obj, args.server_name, keys[0])

    for c in json_encoder.iterencode(obj):
        args.output.write(c)
    args.output.write("\n")
Esempio n. 13
0
 def test_read_keys(self):
     stream = ["ed25519 %s %s" % (self.version, self.key_base64)]
     keys = read_signing_keys(stream)
     self.assertEquals(len(keys), 1)