Improvements to Yggdrasil demo (#1114)
* Improvements to Yggdrasil demo * Fix missing copyright * Fix tie-break
This commit is contained in:
parent
90a0aa9b3e
commit
3b4be90000
6 changed files with 217 additions and 17 deletions
53
cmd/dendrite-demo-yggdrasil/convert/25519.go
Normal file
53
cmd/dendrite-demo-yggdrasil/convert/25519.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright 2019 Google LLC
|
||||
//
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
//
|
||||
// Original code from https://github.com/FiloSottile/age/blob/bbab440e198a4d67ba78591176c7853e62d29e04/internal/age/ssh.go
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha512"
|
||||
"math/big"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
var curve25519P, _ = new(big.Int).SetString("57896044618658097711785492504343953926634992332820282019728792003956564819949", 10)
|
||||
|
||||
func Ed25519PrivateKeyToCurve25519(pk ed25519.PrivateKey) []byte {
|
||||
h := sha512.New()
|
||||
_, _ = h.Write(pk.Seed())
|
||||
out := h.Sum(nil)
|
||||
return out[:curve25519.ScalarSize]
|
||||
}
|
||||
|
||||
func Ed25519PublicKeyToCurve25519(pk ed25519.PublicKey) []byte {
|
||||
// ed25519.PublicKey is a little endian representation of the y-coordinate,
|
||||
// with the most significant bit set based on the sign of the x-coordinate.
|
||||
bigEndianY := make([]byte, ed25519.PublicKeySize)
|
||||
for i, b := range pk {
|
||||
bigEndianY[ed25519.PublicKeySize-i-1] = b
|
||||
}
|
||||
bigEndianY[0] &= 0b0111_1111
|
||||
|
||||
// The Montgomery u-coordinate is derived through the bilinear map
|
||||
// u = (1 + y) / (1 - y)
|
||||
// See https://blog.filippo.io/using-ed25519-keys-for-encryption.
|
||||
y := new(big.Int).SetBytes(bigEndianY)
|
||||
denom := big.NewInt(1)
|
||||
denom.ModInverse(denom.Sub(denom, y), curve25519P) // 1 / (1 - y)
|
||||
u := y.Mul(y.Add(y, big.NewInt(1)), denom)
|
||||
u.Mod(u, curve25519P)
|
||||
|
||||
out := make([]byte, curve25519.PointSize)
|
||||
uBytes := u.Bytes()
|
||||
for i, b := range uBytes {
|
||||
out[len(uBytes)-i-1] = b
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
51
cmd/dendrite-demo-yggdrasil/convert/25519_test.go
Normal file
51
cmd/dendrite-demo-yggdrasil/convert/25519_test.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2020 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.
|
||||
|
||||
package convert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ed25519"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/curve25519"
|
||||
)
|
||||
|
||||
func TestKeyConversion(t *testing.T) {
|
||||
edPub, edPriv, err := ed25519.GenerateKey(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("Signing public:", hex.EncodeToString(edPub))
|
||||
t.Log("Signing private:", hex.EncodeToString(edPriv))
|
||||
|
||||
cuPriv := Ed25519PrivateKeyToCurve25519(edPriv)
|
||||
t.Log("Encryption private:", hex.EncodeToString(cuPriv))
|
||||
|
||||
cuPub := Ed25519PublicKeyToCurve25519(edPub)
|
||||
t.Log("Converted encryption public:", hex.EncodeToString(cuPub))
|
||||
|
||||
var realPub, realPriv [32]byte
|
||||
copy(realPriv[:32], cuPriv[:32])
|
||||
curve25519.ScalarBaseMult(&realPub, &realPriv)
|
||||
t.Log("Scalar-multed encryption public:", hex.EncodeToString(realPub[:]))
|
||||
|
||||
if !bytes.Equal(realPriv[:], cuPriv[:]) {
|
||||
t.Fatal("Private keys should be equal (this means the test is broken)")
|
||||
}
|
||||
if !bytes.Equal(realPub[:], cuPub[:]) {
|
||||
t.Fatal("Public keys should be equal")
|
||||
}
|
||||
}
|
|
@ -16,7 +16,9 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ed25519"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
|
@ -25,6 +27,8 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/matrix-org/dendrite/appservice"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/convert"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing"
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggconn"
|
||||
"github.com/matrix-org/dendrite/eduserver"
|
||||
"github.com/matrix-org/dendrite/eduserver/cache"
|
||||
|
@ -35,7 +39,6 @@ import (
|
|||
"github.com/matrix-org/dendrite/internal/setup"
|
||||
"github.com/matrix-org/dendrite/publicroomsapi/storage"
|
||||
"github.com/matrix-org/dendrite/roomserver"
|
||||
"github.com/matrix-org/dendrite/serverkeyapi"
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
|
@ -61,7 +64,13 @@ func createFederationClient(
|
|||
) *gomatrixserverlib.FederationClient {
|
||||
yggdialer := func(_, address string) (net.Conn, error) {
|
||||
tokens := strings.Split(address, ":")
|
||||
return n.Dial("curve25519", tokens[0])
|
||||
raw, err := hex.DecodeString(tokens[0])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("hex.DecodeString: %w", err)
|
||||
}
|
||||
converted := convert.Ed25519PublicKeyToCurve25519(ed25519.PublicKey(raw))
|
||||
convhex := hex.EncodeToString(converted)
|
||||
return n.Dial("curve25519", convhex)
|
||||
}
|
||||
yggdialerctx := func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
return yggdialer(network, address)
|
||||
|
@ -102,9 +111,9 @@ func main() {
|
|||
|
||||
cfg := &config.Dendrite{}
|
||||
cfg.SetDefaults()
|
||||
cfg.Matrix.ServerName = gomatrixserverlib.ServerName(ygg.EncryptionPublicKey())
|
||||
cfg.Matrix.ServerName = gomatrixserverlib.ServerName(ygg.DerivedServerName())
|
||||
cfg.Matrix.PrivateKey = ygg.SigningPrivateKey()
|
||||
cfg.Matrix.KeyID = gomatrixserverlib.KeyID("ed25519:auto")
|
||||
cfg.Matrix.KeyID = gomatrixserverlib.KeyID(signing.KeyID)
|
||||
cfg.Kafka.UseNaffka = true
|
||||
cfg.Kafka.Topics.OutputRoomEvent = "roomserverOutput"
|
||||
cfg.Kafka.Topics.OutputClientData = "clientapiOutput"
|
||||
|
@ -130,9 +139,7 @@ func main() {
|
|||
deviceDB := base.CreateDeviceDB()
|
||||
federation := createFederationClient(base, ygg)
|
||||
|
||||
serverKeyAPI := serverkeyapi.NewInternalAPI(
|
||||
base.Cfg, federation, base.Caches,
|
||||
)
|
||||
serverKeyAPI := &signing.YggdrasilKeys{}
|
||||
keyRing := serverKeyAPI.KeyRing()
|
||||
|
||||
rsComponent := roomserver.NewInternalAPI(
|
||||
|
@ -170,7 +177,7 @@ func main() {
|
|||
EDUInternalAPI: eduInputAPI,
|
||||
FederationSenderAPI: fsAPI,
|
||||
RoomserverAPI: rsAPI,
|
||||
ServerKeyAPI: serverKeyAPI,
|
||||
//ServerKeyAPI: serverKeyAPI,
|
||||
|
||||
PublicRoomsDB: publicRoomsDB,
|
||||
}
|
||||
|
@ -185,7 +192,7 @@ func main() {
|
|||
)
|
||||
|
||||
go func() {
|
||||
logrus.Info("Listening on ", ygg.EncryptionPublicKey())
|
||||
logrus.Info("Listening on ", ygg.DerivedServerName())
|
||||
logrus.Fatal(httpServer.Serve(ygg))
|
||||
}()
|
||||
go func() {
|
||||
|
|
69
cmd/dendrite-demo-yggdrasil/signing/fetcher.go
Normal file
69
cmd/dendrite-demo-yggdrasil/signing/fetcher.go
Normal file
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2020 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.
|
||||
|
||||
package signing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/matrix-org/gomatrixserverlib"
|
||||
)
|
||||
|
||||
const KeyID = "ed25519:dendrite-demo-yggdrasil"
|
||||
|
||||
type YggdrasilKeys struct {
|
||||
}
|
||||
|
||||
func (f *YggdrasilKeys) KeyRing() *gomatrixserverlib.KeyRing {
|
||||
return &gomatrixserverlib.KeyRing{
|
||||
KeyDatabase: f,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *YggdrasilKeys) FetchKeys(
|
||||
ctx context.Context,
|
||||
requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp,
|
||||
) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) {
|
||||
res := make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult)
|
||||
for req := range requests {
|
||||
if req.KeyID != KeyID {
|
||||
return nil, fmt.Errorf("FetchKeys: cannot fetch key with ID %s, should be %s", req.KeyID, KeyID)
|
||||
}
|
||||
|
||||
hexkey, err := hex.DecodeString(string(req.ServerName))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("FetchKeys: can't decode server name %q: %w", req.ServerName, err)
|
||||
}
|
||||
|
||||
res[req] = gomatrixserverlib.PublicKeyLookupResult{
|
||||
VerifyKey: gomatrixserverlib.VerifyKey{
|
||||
Key: hexkey,
|
||||
},
|
||||
ExpiredTS: gomatrixserverlib.PublicKeyNotExpired,
|
||||
ValidUntilTS: gomatrixserverlib.AsTimestamp(time.Now().Add(24 * time.Hour * 365)),
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (f *YggdrasilKeys) FetcherName() string {
|
||||
return "YggdrasilKeys"
|
||||
}
|
||||
|
||||
func (f *YggdrasilKeys) StoreKeys(ctx context.Context, results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult) error {
|
||||
return nil
|
||||
}
|
|
@ -24,6 +24,8 @@ import (
|
|||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/convert"
|
||||
|
||||
"github.com/libp2p/go-yamux"
|
||||
yggdrasiladmin "github.com/yggdrasil-network/yggdrasil-go/src/admin"
|
||||
yggdrasilconfig "github.com/yggdrasil-network/yggdrasil-go/src/config"
|
||||
|
@ -56,8 +58,6 @@ func Setup(instanceName, instancePeer string) (*Node, error) {
|
|||
log: gologme.New(os.Stdout, "YGG ", log.Flags()),
|
||||
incoming: make(chan *yamux.Stream),
|
||||
}
|
||||
n.config.AdminListen = fmt.Sprintf("unix://./%s-yggdrasil.sock", instanceName)
|
||||
n.config.MulticastInterfaces = []string{".*"}
|
||||
|
||||
yggfile := fmt.Sprintf("%s-yggdrasil.conf", instanceName)
|
||||
if _, err := os.Stat(yggfile); !os.IsNotExist(err) {
|
||||
|
@ -69,6 +69,11 @@ func Setup(instanceName, instancePeer string) (*Node, error) {
|
|||
panic(err)
|
||||
}
|
||||
} else {
|
||||
n.config.AdminListen = fmt.Sprintf("unix://./%s-yggdrasil.sock", instanceName)
|
||||
n.config.MulticastInterfaces = []string{".*"}
|
||||
n.config.EncryptionPrivateKey = hex.EncodeToString(n.EncryptionPrivateKey())
|
||||
n.config.EncryptionPublicKey = hex.EncodeToString(n.EncryptionPublicKey())
|
||||
|
||||
j, err := json.MarshalIndent(n.config, "", " ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -119,8 +124,23 @@ func Setup(instanceName, instancePeer string) (*Node, error) {
|
|||
return n, nil
|
||||
}
|
||||
|
||||
func (n *Node) EncryptionPublicKey() string {
|
||||
return n.core.EncryptionPublicKey()
|
||||
func (n *Node) DerivedServerName() string {
|
||||
return hex.EncodeToString(n.SigningPublicKey())
|
||||
}
|
||||
|
||||
func (n *Node) EncryptionPublicKey() []byte {
|
||||
edkey := n.SigningPublicKey()
|
||||
return convert.Ed25519PublicKeyToCurve25519(edkey)
|
||||
}
|
||||
|
||||
func (n *Node) EncryptionPrivateKey() []byte {
|
||||
edkey := n.SigningPrivateKey()
|
||||
return convert.Ed25519PrivateKeyToCurve25519(edkey)
|
||||
}
|
||||
|
||||
func (n *Node) SigningPublicKey() ed25519.PublicKey {
|
||||
pubBytes, _ := hex.DecodeString(n.config.SigningPublicKey)
|
||||
return ed25519.PublicKey(pubBytes)
|
||||
}
|
||||
|
||||
func (n *Node) SigningPrivateKey() ed25519.PrivateKey {
|
||||
|
|
|
@ -40,10 +40,10 @@ func (n *Node) listenFromYgg() {
|
|||
return
|
||||
}
|
||||
var session *yamux.Session
|
||||
if strings.Compare(n.EncryptionPublicKey(), conn.RemoteAddr().String()) < 0 {
|
||||
session, err = yamux.Client(conn, n.yamuxConfig())
|
||||
} else {
|
||||
if strings.Compare(conn.RemoteAddr().String(), n.DerivedServerName()) < 0 {
|
||||
session, err = yamux.Server(conn, n.yamuxConfig())
|
||||
} else {
|
||||
session, err = yamux.Client(conn, n.yamuxConfig())
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -96,7 +96,7 @@ func (n *Node) DialContext(ctx context.Context, network, address string) (net.Co
|
|||
n.log.Println("n.dialer.DialContext:", err)
|
||||
return nil, err
|
||||
}
|
||||
if strings.Compare(n.EncryptionPublicKey(), address) < 0 {
|
||||
if strings.Compare(address, n.DerivedServerName()) > 0 {
|
||||
session, err = yamux.Client(conn, n.yamuxConfig())
|
||||
} else {
|
||||
session, err = yamux.Server(conn, n.yamuxConfig())
|
||||
|
|
Loading…
Reference in a new issue