Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Add an export_signing_key script #6546

Merged
merged 4 commits into from
Dec 19, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/6546.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add an export_signing_key script to extract the public part of signing keys when rotating them.
13 changes: 7 additions & 6 deletions docs/code_style.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ Some guidelines follow:
correctly handles the top-level option being set to `None` (as it
will be if no sub-options are enabled).
- Lines should be wrapped at 80 characters.
- Use two-space indents.

Example:

Expand All @@ -155,13 +156,13 @@ Example:
# Settings for the frobber
#
frobber:
# frobbing speed. Defaults to 1.
#
#speed: 10
# frobbing speed. Defaults to 1.
#
#speed: 10

# frobbing distance. Defaults to 1000.
#
#distance: 100
# frobbing distance. Defaults to 1000.
#
#distance: 100

Note that the sample configuration is generated from the synapse code
and is maintained by a script, `scripts-dev/generate_sample_config`.
Expand Down
21 changes: 13 additions & 8 deletions docs/sample_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1115,14 +1115,19 @@ metrics_flags:
signing_key_path: "CONFDIR/SERVERNAME.signing.key"

# The keys that the server used to sign messages with but won't use
# to sign new messages. E.g. it has lost its private key
#
#old_signing_keys:
# "ed25519:auto":
# # Base64 encoded public key
# key: "The public part of your old signing key."
# # Millisecond POSIX timestamp when the key expired.
# expired_ts: 123456789123
# to sign new messages.
#
old_signing_keys:
# For each key, `key` should be the base64-encoded public key, and
# `expired_ts`should be the time (in milliseconds since the unix epoch) that
# it was last used.
#
# It is possible to build an entry from an old signing.key file using the
# `export_signing_key` script which is provided with synapse.
#
# For example:
#
#"ed25519:id": { key: "base64string", expired_ts: 123456789123 }

# How long key response published by this server is valid for.
# Used to set the valid_until_ts in /key/v2 APIs.
Expand Down
95 changes: 95 additions & 0 deletions scripts/export_signing_key
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright 2019 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import sys
import time
from typing import Optional

import nacl.signing
from signedjson.key import encode_verify_key_base64, get_verify_key, read_signing_keys


def exit(status: int = 0, message: Optional[str] = None):
if message:
print(message, file=sys.stderr)
sys.exit(status)


def format_plain(public_key: nacl.signing.VerifyKey):
print(
"%s:%s %s"
% (public_key.alg, public_key.version, encode_verify_key_base64(public_key),)
)


def format_for_config(public_key: nacl.signing.VerifyKey, expiry_ts: int):
print(
' "%s:%s": { key: "%s", expired_ts: %i }'
% (
public_key.alg,
public_key.version,
encode_verify_key_base64(public_key),
expiry_ts,
)
)


if __name__ == "__main__":
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",
nargs=1,
type=int,
default=int(time.time() * 1000),
erikjohnston marked this conversation as resolved.
Show resolved Hide resolved
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
)

keys = []
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),
)
res = []
for key in res:
formatter(get_verify_key(key))
23 changes: 15 additions & 8 deletions synapse/config/key.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def read_config(self, config, config_dir_path, **kwargs):
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", {})
config.get("old_signing_keys")
)
self.key_refresh_interval = self.parse_duration(
config.get("key_refresh_interval", "1d")
Expand Down Expand Up @@ -199,14 +199,19 @@ def generate_config_section(
signing_key_path: "%(base_key_name)s.signing.key"

# The keys that the server used to sign messages with but won't use
# to sign new messages. E.g. it has lost its private key
# to sign new messages.
#
#old_signing_keys:
# "ed25519:auto":
# # Base64 encoded public key
# key: "The public part of your old signing key."
# # Millisecond POSIX timestamp when the key expired.
# expired_ts: 123456789123
old_signing_keys:
# For each key, `key` should be the base64-encoded public key, and
# `expired_ts`should be the time (in milliseconds since the unix epoch) that
# it was last used.
#
# It is possible to build an entry from an old signing.key file using the
# `export_signing_key` script which is provided with synapse.
#
# For example:
#
#"ed25519:id": { key: "base64string", expired_ts: 123456789123 }

# How long key response published by this server is valid for.
# Used to set the valid_until_ts in /key/v2 APIs.
Expand Down Expand Up @@ -290,6 +295,8 @@ def read_signing_keys(self, signing_key_path, name):
raise ConfigError("Error reading %s: %s" % (name, str(e)))

def read_old_signing_keys(self, old_signing_keys):
if old_signing_keys is None:
return {}
keys = {}
for key_id, key_data in old_signing_keys.items():
if is_signing_algorithm_supported(key_id):
Expand Down