aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dendrite-config.yaml8
-rw-r--r--federationapi/routing/keys.go12
-rw-r--r--internal/config/config.go26
-rw-r--r--internal/config/config_global.go20
-rw-r--r--internal/config/config_test.go2
5 files changed, 62 insertions, 6 deletions
diff --git a/dendrite-config.yaml b/dendrite-config.yaml
index 8c737692..b71fb509 100644
--- a/dendrite-config.yaml
+++ b/dendrite-config.yaml
@@ -38,6 +38,14 @@ global:
# The path to the signing private key file, used to sign requests and events.
private_key: matrix_key.pem
+ # The paths and expiry timestamps (as a UNIX timestamp in millisecond precision)
+ # to old signing private keys that were formerly in use on this domain. These
+ # keys will not be used for federation request or event signing, but will be
+ # provided to any other homeserver that asks when trying to verify old events.
+ # old_private_keys:
+ # - private_key: old_matrix_key.pem
+ # expired_at: 1601024554498
+
# How long a remote server can cache our server signing key before requesting it
# again. Increasing this number will reduce the number of requests made by other
# servers for our key but increases the period that a compromised key will be
diff --git a/federationapi/routing/keys.go b/federationapi/routing/keys.go
index 785be090..17762b03 100644
--- a/federationapi/routing/keys.go
+++ b/federationapi/routing/keys.go
@@ -136,6 +136,8 @@ func localKeys(cfg *config.FederationAPI, validUntil time.Time) (*gomatrixserver
var keys gomatrixserverlib.ServerKeys
keys.ServerName = cfg.Matrix.ServerName
+ keys.TLSFingerprints = cfg.TLSFingerPrints
+ keys.ValidUntilTS = gomatrixserverlib.AsTimestamp(validUntil)
publicKey := cfg.Matrix.PrivateKey.Public().(ed25519.PublicKey)
@@ -145,9 +147,15 @@ func localKeys(cfg *config.FederationAPI, validUntil time.Time) (*gomatrixserver
},
}
- keys.TLSFingerprints = cfg.TLSFingerPrints
keys.OldVerifyKeys = map[gomatrixserverlib.KeyID]gomatrixserverlib.OldVerifyKey{}
- keys.ValidUntilTS = gomatrixserverlib.AsTimestamp(validUntil)
+ for _, oldVerifyKey := range cfg.Matrix.OldVerifyKeys {
+ keys.OldVerifyKeys[oldVerifyKey.KeyID] = gomatrixserverlib.OldVerifyKey{
+ VerifyKey: gomatrixserverlib.VerifyKey{
+ Key: gomatrixserverlib.Base64Bytes(oldVerifyKey.PrivateKey),
+ },
+ ExpiredTS: oldVerifyKey.ExpiredAt,
+ }
+ }
toSign, err := json.Marshal(keys.ServerKeyFields)
if err != nil {
diff --git a/internal/config/config.go b/internal/config/config.go
index d75500db..7528aa23 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -228,10 +228,30 @@ func loadConfig(
return nil, err
}
- if c.Global.KeyID, c.Global.PrivateKey, err = readKeyPEM(privateKeyPath, privateKeyData); err != nil {
+ if c.Global.KeyID, c.Global.PrivateKey, err = readKeyPEM(privateKeyPath, privateKeyData, true); err != nil {
return nil, err
}
+ for i, oldPrivateKey := range c.Global.OldVerifyKeys {
+ var oldPrivateKeyData []byte
+
+ oldPrivateKeyPath := absPath(basePath, oldPrivateKey.PrivateKeyPath)
+ oldPrivateKeyData, err = readFile(oldPrivateKeyPath)
+ if err != nil {
+ return nil, err
+ }
+
+ // NOTSPEC: Ordinarily we should enforce key ID formatting, but since there are
+ // a number of private keys out there with non-compatible symbols in them due
+ // to lack of validation in Synapse, we won't enforce that for old verify keys.
+ keyID, privateKey, perr := readKeyPEM(oldPrivateKeyPath, oldPrivateKeyData, false)
+ if perr != nil {
+ return nil, perr
+ }
+
+ c.Global.OldVerifyKeys[i].KeyID, c.Global.OldVerifyKeys[i].PrivateKey = keyID, privateKey
+ }
+
for _, certPath := range c.FederationAPI.FederationCertificatePaths {
absCertPath := absPath(basePath, certPath)
var pemData []byte
@@ -444,7 +464,7 @@ func absPath(dir string, path Path) string {
return filepath.Join(dir, string(path))
}
-func readKeyPEM(path string, data []byte) (gomatrixserverlib.KeyID, ed25519.PrivateKey, error) {
+func readKeyPEM(path string, data []byte, enforceKeyIDFormat bool) (gomatrixserverlib.KeyID, ed25519.PrivateKey, error) {
for {
var keyBlock *pem.Block
keyBlock, data = pem.Decode(data)
@@ -462,7 +482,7 @@ func readKeyPEM(path string, data []byte) (gomatrixserverlib.KeyID, ed25519.Priv
if !strings.HasPrefix(keyID, "ed25519:") {
return "", nil, fmt.Errorf("key ID %q doesn't start with \"ed25519:\" in %q", keyID, path)
}
- if !keyIDRegexp.MatchString(keyID) {
+ if enforceKeyIDFormat && !keyIDRegexp.MatchString(keyID) {
return "", nil, fmt.Errorf("key ID %q in %q contains illegal characters (use a-z, A-Z, 0-9 and _ only)", keyID, path)
}
_, privKey, err := ed25519.GenerateKey(bytes.NewReader(keyBlock.Bytes))
diff --git a/internal/config/config_global.go b/internal/config/config_global.go
index 03f522be..d210a3ac 100644
--- a/internal/config/config_global.go
+++ b/internal/config/config_global.go
@@ -22,6 +22,11 @@ type Global struct {
// prefix "ed25519:".
KeyID gomatrixserverlib.KeyID `yaml:"-"`
+ // Information about old private keys that used to be used to sign requests and
+ // events on this domain. They will not be used but will be advertised to other
+ // servers that ask for them to help verify old events.
+ OldVerifyKeys []OldVerifyKeys `yaml:"old_private_keys"`
+
// How long a remote server can cache our server key for before requesting it again.
// Increasing this number will reduce the number of requests made by remote servers
// for our key, but increases the period a compromised key will be considered valid
@@ -60,6 +65,21 @@ func (c *Global) Verify(configErrs *ConfigErrors, isMonolith bool) {
c.Metrics.Verify(configErrs, isMonolith)
}
+type OldVerifyKeys struct {
+ // Path to the private key.
+ PrivateKeyPath Path `yaml:"private_key"`
+
+ // The private key itself.
+ PrivateKey ed25519.PrivateKey `yaml:"-"`
+
+ // The key ID of the private key.
+ KeyID gomatrixserverlib.KeyID `yaml:"-"`
+
+ // When the private key was designed as "expired", as a UNIX timestamp
+ // in millisecond precision.
+ ExpiredAt gomatrixserverlib.Timestamp `yaml:"expired_at"`
+}
+
// The configuration to use for Prometheus metrics
type Metrics struct {
// Whether or not the metrics are enabled
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 39b3ee47..7549fa02 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -234,7 +234,7 @@ func (m mockReadFile) readFile(path string) ([]byte, error) {
}
func TestReadKey(t *testing.T) {
- keyID, _, err := readKeyPEM("path/to/key", []byte(testKey))
+ keyID, _, err := readKeyPEM("path/to/key", []byte(testKey), true)
if err != nil {
t.Error("failed to load private key:", err)
}