Skip to content

Commit 02753f1

Browse files
committed
add config-level support for protecting storage buckets and creating authoritarian relationship between peers
1 parent 79ef50d commit 02753f1

File tree

9 files changed

+148
-44
lines changed

9 files changed

+148
-44
lines changed

cmd/util.go

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ limitations under the License.
1414
package cmd
1515

1616
import (
17+
"encoding/base64"
1718
"encoding/json"
1819
"fmt"
1920
"os"
@@ -321,6 +322,11 @@ var CommonFlags []cli.Flag = []cli.Flag{
321322
Usage: "Enable peerguard. (Experimental)",
322323
EnvVars: []string{"PEERGUARD"},
323324
},
325+
&cli.StringFlag{
326+
Name: "privkey",
327+
Usage: "Use fixed base64 <- protobuf encoded privkey. (Experimental)",
328+
EnvVars: []string{"EDGEVPNPRIVKEY"},
329+
},
324330
&cli.BoolFlag{
325331
Name: "privkey-cache",
326332
Usage: "Enable privkey caching. (Experimental)",
@@ -495,31 +501,39 @@ func cliToOpts(c *cli.Context) ([]node.Option, []vpn.Option, *logger.Logger) {
495501
}
496502
}
497503

498-
// Check if we have any privkey identity cached already
499-
if c.Bool("privkey-cache") {
500-
keyFile := filepath.Join(c.String("privkey-cache-dir"), "privkey")
501-
dat, err := os.ReadFile(keyFile)
502-
if err == nil && len(dat) > 0 {
503-
llger.Info("Reading key from", keyFile)
504-
505-
nc.Privkey = dat
504+
if c.String("privkey") != "" {
505+
raw, err := base64.StdEncoding.DecodeString(c.String("privkey"))
506+
if err != nil {
507+
checkErr(fmt.Errorf("failed to decode privkey: %v", err))
506508
} else {
507-
// generate, write
508-
llger.Info("Generating private key and saving it locally for later use in", keyFile)
509+
nc.Privkey = raw
510+
}
511+
} else {
512+
// Check if we have any privkey identity cached already
513+
if c.Bool("privkey-cache") {
514+
keyFile := filepath.Join(c.String("privkey-cache-dir"), "privkey")
515+
dat, err := os.ReadFile(keyFile)
516+
if err == nil && len(dat) > 0 {
517+
llger.Info("Reading key from", keyFile)
518+
nc.Privkey = dat
519+
} else {
520+
// generate, write
521+
llger.Info("Generating private key and saving it locally for later use in", keyFile)
509522

510-
privkey, err := node.GenPrivKey(0)
511-
checkErr(err)
523+
privkey, err := node.GenPrivKey(0)
524+
checkErr(err)
512525

513-
r, err := crypto.MarshalPrivateKey(privkey)
514-
checkErr(err)
526+
r, err := crypto.MarshalPrivateKey(privkey)
527+
checkErr(err)
515528

516-
err = os.MkdirAll(c.String("privkey-cache-dir"), 0600)
517-
checkErr(err)
529+
err = os.MkdirAll(c.String("privkey-cache-dir"), 0600)
530+
checkErr(err)
518531

519-
err = os.WriteFile(keyFile, r, 0600)
520-
checkErr(err)
532+
err = os.WriteFile(keyFile, r, 0600)
533+
checkErr(err)
521534

522-
nc.Privkey = r
535+
nc.Privkey = r
536+
}
523537
}
524538
}
525539

config.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
otp:
2+
dht:
3+
interval: 360
4+
key: YVMwYeeoIJ9yGQeuRNHY3wigEhDEisAPcbt0L30vQ3q
5+
length: 43
6+
crypto:
7+
interval: 360
8+
key: 0Yu91JT1WPmWtmmrFD5tWrSzeyhLUVFWyiEXzIezcyz
9+
length: 43
10+
room: k9xRlX6brHxKMAWhGgvsuoiwq4fcNyNtA7JQivZBYm7
11+
rendezvous: tFMpGqtqtFHckVt62FCklh9xqjTi9upKWCmXNrNBCpL
12+
mdns: NG8LRHaJTRnR0tbOGgr73oQTZqvKEn0kllXQr5SfKDs
13+
max_message_size: 20971520
14+
15+
trusted_peer_ids:
16+
- 12D3KooWQi1XDFy1Ntv5WXLYJWbuFy1zbXM3F6jc4DUJKtaoZPpC
17+
protected_store_key:
18+
- trustzone
19+
- trustzoneAuth
20+
- initialOwner

pkg/blockchain/ledger.go

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ import (
2121
"io"
2222
"io/ioutil"
2323
"log"
24+
"maps"
25+
"slices"
2426
"sync"
2527
"time"
2628

@@ -35,6 +37,10 @@ type Ledger struct {
3537
blockchain Store
3638

3739
channel io.Writer
40+
41+
skipVerify bool
42+
trustedPeerIDS []string
43+
protectedStoreKeys []string
3844
}
3945

4046
type Store interface {
@@ -59,6 +65,16 @@ func (l *Ledger) newGenesis() {
5965
l.blockchain.Add(genesisBlock)
6066
}
6167

68+
func (l *Ledger) SkipVerify() {
69+
l.skipVerify = true
70+
}
71+
func (l *Ledger) SetTrustedPeerIDS(ids []string) {
72+
l.trustedPeerIDS = ids
73+
}
74+
func (l *Ledger) SetProtectedStoreKeys(keys []string) {
75+
l.protectedStoreKeys = keys
76+
}
77+
6278
// Syncronizer starts a goroutine which
6379
// writes the blockchain to the periodically
6480
func (l *Ledger) Syncronizer(ctx context.Context, t time.Duration) {
@@ -123,8 +139,17 @@ func (l *Ledger) Update(f *Ledger, h *hub.Message, c chan *hub.Message) (err err
123139
return
124140
}
125141

142+
if len(l.protectedStoreKeys) > 0 && !slices.Contains(l.trustedPeerIDS, h.SenderID) {
143+
for _, key := range l.protectedStoreKeys {
144+
if !maps.Equal(l.blockchain.Last().Storage[key], block.Storage[key]) {
145+
err = errors.Wrapf(err, "unauthorized attempt to write to protected bucket: %s", key)
146+
return
147+
}
148+
}
149+
}
150+
126151
l.Lock()
127-
if block.Index > l.blockchain.Len() {
152+
if l.skipVerify || block.Index > l.blockchain.Len() {
128153
l.blockchain.Add(*block)
129154
}
130155
l.Unlock()
@@ -350,12 +375,14 @@ func (l *Ledger) Index() int {
350375
func (l *Ledger) writeData(s map[string]map[string]Data) {
351376
newBlock := l.blockchain.Last().NewBlock(s)
352377

353-
if newBlock.IsValid(l.blockchain.Last()) {
354-
l.Lock()
355-
l.blockchain.Add(newBlock)
356-
l.Unlock()
378+
if !l.skipVerify && !newBlock.IsValid(l.blockchain.Last()) {
379+
return
357380
}
358381

382+
l.Lock()
383+
l.blockchain.Add(newBlock)
384+
l.Unlock()
385+
359386
bytes, err := json.Marshal(l.blockchain.Last())
360387
if err != nil {
361388
log.Println(err)

pkg/node/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ type Config struct {
7676

7777
Sealer Sealer
7878
PeerGater Gater
79+
80+
TrustedPeerIDS []string
81+
ProtectedStoreKeys []string
7982
}
8083

8184
type Gater interface {

pkg/node/connection.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"io"
2121
mrand "math/rand"
2222
"net"
23+
"slices"
2324

2425
internalCrypto "github.com/mudler/edgevpn/pkg/crypto"
2526

@@ -253,6 +254,21 @@ func (e *Node) handleEvents(ctx context.Context, inputChannel chan *hub.Message,
253254
continue
254255
}
255256

257+
// If we have enabled trusted arbiter peers
258+
if len(e.config.TrustedPeerIDS) > 0 && e.host.ID().String() != m.SenderID {
259+
// If we are not the trusted one
260+
if !slices.Contains(e.config.TrustedPeerIDS, e.host.ID().String()) {
261+
// If incoming message is not from trusted one
262+
if !slices.Contains(e.config.TrustedPeerIDS, m.SenderID) {
263+
e.config.Logger.Warnf("%s gated room message from %s - not present in trusted peer IDS", e.host.ID(), m.SenderID)
264+
continue
265+
} else {
266+
// If we a non-trusted peer, and we receive a meesage from the trusted one - disable peerGater
267+
peerGater = false
268+
}
269+
}
270+
}
271+
256272
if peerGater {
257273
if e.config.PeerGater != nil && e.config.PeerGater.Gate(e, peer.ID(m.SenderID)) {
258274
e.config.Logger.Warnf("gated message from %s", m.SenderID)

pkg/node/node.go

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"encoding/json"
1919
"fmt"
2020
"os"
21+
"slices"
2122
"sync"
2223
"time"
2324

@@ -112,6 +113,25 @@ func (e *Node) Start(ctx context.Context) error {
112113
if err != nil {
113114
return err
114115
}
116+
117+
// Set the handler when we receive messages
118+
// The ledger needs to read them and update the internal blockchain
119+
e.config.Handlers = append(e.config.Handlers, ledger.Update)
120+
121+
e.config.Logger.Info("Starting EdgeVPN network")
122+
123+
// Startup libp2p network
124+
err = e.startNetwork(ctx)
125+
if err != nil {
126+
return err
127+
}
128+
129+
if len(e.config.TrustedPeerIDS) > 0 && !slices.Contains(e.config.TrustedPeerIDS, e.host.ID().String()) {
130+
ledger.SkipVerify()
131+
}
132+
ledger.SetTrustedPeerIDS(e.config.TrustedPeerIDS)
133+
ledger.SetProtectedStoreKeys(e.config.ProtectedStoreKeys)
134+
115135
// For testing purposes, can be included into the config opts routine as init known public key
116136
if os.Getenv("PEERGATE_PUBLIC") != "" {
117137
publicStr := os.Getenv("PEERGATE_PUBLIC")
@@ -123,20 +143,9 @@ func (e *Node) Start(ctx context.Context) error {
123143
}
124144

125145
for k, v := range publicMap {
126-
ledger.Persist(ctx, 5*time.Second, 20*time.Second, "trustzoneAuth", k, v)
146+
ledger.Persist(ctx, 5*time.Second, 20*time.Second, protocol.TrustZoneAuthKey, k, v)
127147
}
128-
}
129-
130-
// Set the handler when we receive messages
131-
// The ledger needs to read them and update the internal blockchain
132-
e.config.Handlers = append(e.config.Handlers, ledger.Update)
133-
134-
e.config.Logger.Info("Starting EdgeVPN network")
135-
136-
// Startup libp2p network
137-
err = e.startNetwork(ctx)
138-
if err != nil {
139-
return err
148+
ledger.Persist(ctx, 5*time.Second, 20*time.Second, "initialOwner", e.host.ID().String(), "")
140149
}
141150

142151
// Send periodically messages to the channel with our blockchain content

pkg/node/options.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,9 @@ type YAMLConnectionConfig struct {
259259
Rendezvous string `yaml:"rendezvous"`
260260
MDNS string `yaml:"mdns"`
261261
MaxMessageSize int `yaml:"max_message_size"`
262+
263+
TrustedPeerIDS []string `yaml:"trusted_peer_ids"`
264+
ProtectedStoreKeys []string `yaml:"protected_store_keys"`
262265
}
263266

264267
// Base64 returns the base64 string representation of the connection
@@ -301,6 +304,8 @@ func (y YAMLConnectionConfig) copy(mdns, dht bool, cfg *Config, d *discovery.DHT
301304
}
302305
cfg.SealKeyLength = y.OTP.Crypto.Length
303306
cfg.MaxMessageSize = y.MaxMessageSize
307+
cfg.TrustedPeerIDS = y.TrustedPeerIDS
308+
cfg.ProtectedStoreKeys = y.ProtectedStoreKeys
304309
}
305310

306311
const defaultKeyLength = 43

pkg/trustzone/authprovider/ecdsa/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ func (e *ECDSA521) Challenger(inTrustZone bool, c node.Config, n *node.Node, b *
9393
msg := hub.NewMessage("challenge")
9494
msg.Annotations = make(map[string]interface{})
9595
msg.Annotations["sigs"] = string(signature)
96+
msg.SenderID = n.Host().ID().String()
9697
n.PublishMessage(msg)
9798
return
9899
}

test.sh

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
#!/bin/bash
22

3-
keys=($(go run main.go peergater ecdsa-genkey | cut -d: -f2- ))
4-
PRIVKEY=${keys[0]}
5-
PUBKEY=${keys[1]}
3+
main_keys=($(go run main.go peergater ecdsa-genkey | cut -d: -f2- ))
4+
client_keys=($(go run main.go peergater ecdsa-genkey | cut -d: -f2- ))
5+
MAIN_PRIVKEY=${main_keys[0]}
6+
MAIN_PUBKEY=${main_keys[1]}
7+
CLIENT_PRIVKEY=${client_keys[0]}
8+
CLIENT_PUBKEY=${client_keys[1]}
69

710
# export EDGEVPNDHTANNOUNCEMADDRS=/ip4/.../tcp/.../p2p/...
8-
export EDGEVPNCONFIG=~/config.yml
11+
export EDGEVPNCONFIG=config.yml
912
export EDGEVPNPEERGATEINTERVAL=10
13+
export EDGEVPNPRIVKEY='CAESQOV82ydHYcTFqyjf6fE6Zrdr9aH97GwGODEWm9HmELv73T55KPBrW5n3D29Df7b+DjH1zVzqUa1cgpTBHiEBdgk='
1014
export PEERGATE=true
1115
export PEERGUARD=true
1216
export PEERGATE_AUTOCLEAN=true
13-
export PEERGATE_AUTH='{ "ecdsa" : { "private_key": "'$PRIVKEY'" } }'
14-
export PEERGATE_PUBLIC='{ "ecdsa_1": "'$PUBKEY'" }'
17+
export PEERGATE_AUTH='{ "ecdsa" : { "private_key": "'$MAIN_PRIVKEY'" } }'
18+
export PEERGATE_PUBLIC='{ "ecdsa_main": "'$MAIN_PUBKEY'", "ecdsa_client": "'$CLIENT_PUBKEY'" }'
1519

1620
# killall main is a bad idea, but that worked on my machine
1721
sudo -E bash -c "
18-
IFACE=\"utun10\" go run main.go api &
22+
IFACE=\"utun10\" go run main.go &
23+
sleep 3
24+
25+
export -n EDGEVPNPRIVKEY
26+
export PEERGATE_AUTH='{ \"ecdsa\" : { \"private_key\": \""$CLIENT_PRIVKEY"\" } }'
27+
1928
IFACE=\"utun11\" go run main.go
2029
killall main
2130
"

0 commit comments

Comments
 (0)