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")
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)) )
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" )
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)
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)))
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))
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()
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)
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)
def test_read_keys(self): stream = ["ed25519 %s %s" % (self.version, self.key_base64)] keys = read_signing_keys(stream) self.assertEquals(len(keys), 1)
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")