Skip to content

Commit

Permalink
sec: sugget keys + in dv
Browse files Browse the repository at this point in the history
  • Loading branch information
pulsejet committed Jan 21, 2025
1 parent 8e8634f commit c143f81
Show file tree
Hide file tree
Showing 16 changed files with 141 additions and 35 deletions.
10 changes: 10 additions & 0 deletions dv/config/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
_ "embed"
"errors"
"time"

Expand All @@ -17,6 +18,9 @@ var MulticastStrategy = enc.LOCALHOST.Append(
enc.NewStringComponent(enc.TypeGenericNameComponent, "multicast"),
)

//go:embed schema.tlv
var SchemaBytes []byte

type Config struct {
// Network should be the same for all routers in the network.
Network string `json:"network"`
Expand All @@ -26,6 +30,8 @@ type Config struct {
AdvertisementSyncInterval_ms uint64 `json:"advertise_interval"`
// Time after which a neighbor is considered dead.
RouterDeadInterval_ms uint64 `json:"router_dead_interval"`
// URI specifying KeyChain location.
KeyChainUri string `json:"keychain"`

// Parsed Global Prefix
networkNameN enc.Name
Expand Down Expand Up @@ -168,3 +174,7 @@ func (c *Config) AdvertisementSyncInterval() time.Duration {
func (c *Config) RouterDeadInterval() time.Duration {
return time.Duration(c.RouterDeadInterval_ms) * time.Millisecond
}

func (c *Config) SchemaBytes() []byte {
return SchemaBytes
}
Binary file added dv/config/schema.tlv
Binary file not shown.
16 changes: 16 additions & 0 deletions dv/config/schema.trust
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Network name from config
#network: network
// Router name from config
#router: #network/router

// Prefix table data
#prefix: #router/"32=DV"/"32=PFX"/_/_ <= #router_cert
// Advertisement data
#advert: /"localhop"/#router/"32=DV"/"32=ADV"/_ <= #router_cert

// Certificate definitions
#root_cert: #network/#KEY
#router_cert: #router/#KEY <= #root_cert

// Standard NDN conventions
#KEY: "KEY"/_/_/_
7 changes: 6 additions & 1 deletion dv/dv.sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ dv:
# [required] Global prefix for all DV routers in the network
network: /ndn
# [required] Unique name for each router in the network
router: /sample
router: /ndn/sample

# [optional] Period of Advertisement Sync Interests (ms)
advertise_interval: 5000
# [optional] Time after which a neighbor is considered dead (ms)
router_dead_interval: 30000

# [optional] Keychain URI for security
# - If "insecure" is specified, security is disabled
# - Example: dir:///absolute/path/to/keychain
keychain: "insecure"
29 changes: 28 additions & 1 deletion dv/dv/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/named-data/ndnd/std/ndn"
mgmt "github.com/named-data/ndnd/std/ndn/mgmt_2022"
"github.com/named-data/ndnd/std/object"
"github.com/named-data/ndnd/std/security/keychain"
"github.com/named-data/ndnd/std/security/schema"
ndn_sync "github.com/named-data/ndnd/std/sync"
"github.com/named-data/ndnd/std/utils"
)
Expand All @@ -21,6 +23,8 @@ type Router struct {
engine ndn.Engine
// config for this router
config *config.Config
// trust configuration
trust *ndn.TrustConfig
// object client
client *object.Client
// nfd management thread
Expand Down Expand Up @@ -58,11 +62,34 @@ func NewRouter(config *config.Config, engine ndn.Engine) (*Router, error) {
return nil, err
}

// Create packet store
store := object.NewMemoryStore()

// Create security configuration
var trust *ndn.TrustConfig = nil
if config.KeyChainUri == "insecure" {
log.Warn(nil, "Security is disabled - insecure mode")
} else {
kc, err := keychain.NewKeyChain(config.KeyChainUri, store)
if err != nil {
return nil, err
}
schema, err := schema.NewLvsSchema(config.SchemaBytes())
if err != nil {
return nil, err
}
trust = &ndn.TrustConfig{
KeyChain: kc,
Schema: schema,
}
}

// Create the DV router
dv := &Router{
engine: engine,
config: config,
client: object.NewClient(engine, object.NewMemoryStore()),
trust: trust,
client: object.NewClient(engine, store, trust),
nfdc: nfdc.NewNfdMgmtThread(engine),
mutex: sync.Mutex{},
}
Expand Down
10 changes: 10 additions & 0 deletions std/ndn/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ type SigChecker func(name enc.Name, sigCovered enc.Wire, sig Signature) bool
type KeyChain interface {
// String provides the log identifier of the keychain.
String() string
// Store provides the public storage of the keychain.
Store() Store
// GetIdentities returns all identities in the keychain.
GetIdentities() []KeyChainIdentity
// GetIdentity returns the identity by full name.
Expand Down Expand Up @@ -73,3 +75,11 @@ type KeyChainKey interface {
// The version number is always set to zero.
UniqueCerts() []enc.Name
}

// TrustSchema is the interface for a trust schema.
type TrustSchema interface {
// Check checks if a packet can be signed with the provided certificate.
Check(pkt enc.Name, cert enc.Name) bool
// Suggest suggests a signer for a packet.
Suggest(enc.Name, KeyChain) Signer
}
18 changes: 18 additions & 0 deletions std/ndn/security_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ndn

import enc "github.com/named-data/ndnd/std/encoding"

// TrustConfig is the configuration of the trust module.
type TrustConfig struct {
// KeyChain is the keychain.
KeyChain KeyChain
// Schema is the trust schema.
Schema TrustSchema
// Roots are the full names of the trust anchors.
Roots []enc.Name
}

// Suggest suggests a signer for a given name.
func (tc *TrustConfig) Suggest(name enc.Name) Signer {
return tc.Schema.Suggest(name, tc.KeyChain)
}
5 changes: 4 additions & 1 deletion std/object/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type Client struct {
engine ndn.Engine
// data storage
store ndn.Store
// trust configuration
trust *ndn.TrustConfig
// segment fetcher
fetcher rrSegFetcher

Expand All @@ -28,10 +30,11 @@ type Client struct {
}

// Create a new client with given engine and store
func NewClient(engine ndn.Engine, store ndn.Store) *Client {
func NewClient(engine ndn.Engine, store ndn.Store, trust *ndn.TrustConfig) *Client {
client := new(Client)
client.engine = engine
client.store = store
client.trust = trust
client.fetcher = newRrSegFetcher(client)

client.stop = make(chan bool)
Expand Down
8 changes: 7 additions & 1 deletion std/object/client_produce.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package object

import (
"errors"
"fmt"
"runtime"
"time"

Expand Down Expand Up @@ -133,8 +134,13 @@ func Produce(args ProduceArgs, store ndn.Store, signer ndn.Signer) (enc.Name, er
// Produce and sign data, and insert into the client's store.
// The input data will be freed as the object is segmented.
func (c *Client) Produce(args ProduceArgs) (enc.Name, error) {
// TODO: sign the data
signer := sig.NewSha256Signer()
if c.trust != nil {
signer = c.trust.Suggest(args.Name)
if signer == nil {
return nil, fmt.Errorf("no valid signer found for %s", args.Name)
}
}

return Produce(args, c.store, signer)
}
Expand Down
4 changes: 4 additions & 0 deletions std/security/keychain/keychain_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ func (kc *KeyChainDir) String() string {
return fmt.Sprintf("keychain-dir (%s)", kc.path)
}

func (kc *KeyChainDir) Store() ndn.Store {
return kc.mem.Store()
}

func (kc *KeyChainDir) GetIdentities() []ndn.KeyChainIdentity {
return kc.mem.GetIdentities()
}
Expand Down
4 changes: 4 additions & 0 deletions std/security/keychain/keychain_mem.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ func (kc *KeyChainMem) String() string {
return "keychain-mem"
}

func (kc *KeyChainMem) Store() ndn.Store {
return kc.pubStore
}

func (kc *KeyChainMem) GetIdentities() []ndn.KeyChainIdentity {
return kc.identities
}
Expand Down
37 changes: 30 additions & 7 deletions std/security/schema/lvs.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"errors"

enc "github.com/named-data/ndnd/std/encoding"
"github.com/named-data/ndnd/std/ndn"
sig "github.com/named-data/ndnd/std/security/signer"
)

const LVS_VERSION uint64 = 0x00011000
Expand Down Expand Up @@ -189,18 +191,26 @@ func (s *LvsSchema) Match(name enc.Name) []*LvsNode {
}

func (s *LvsSchema) Check(pkt enc.Name, key enc.Name) bool {
return s.checkSigner(s.Match(pkt), s.Match(key))
}

func (s *LvsSchema) Suggest(pkt enc.Name, keychain ndn.KeyChain) ndn.Signer {
pktNodes := s.Match(pkt)
keyNodes := s.Match(key)
for _, pktNode := range pktNodes {
for _, sc := range pktNode.SignCons {
for _, keyNode := range keyNodes {
if keyNode.Id == sc {
return true
for _, id := range keychain.GetIdentities() {
for _, key := range id.Keys() {
for _, cert := range key.UniqueCerts() {
certNodes := s.Match(cert)
if s.checkSigner(pktNodes, certNodes) {
// Valid signer found, remove version number
return &sig.ContextSigner{
Signer: key.Signer(),
KeyLocatorName: cert[:len(cert)-1],
}
}
}
}
}
return false
return nil
}

func (s *LvsSchema) checkCons(
Expand Down Expand Up @@ -234,3 +244,16 @@ func (s *LvsSchema) checkCons(
}
return true
}

func (s *LvsSchema) checkSigner(pktNodes []*LvsNode, keyNodes []*LvsNode) bool {
for _, pktNode := range pktNodes {
for _, sc := range pktNode.SignCons {
for _, keyNode := range keyNodes {
if keyNode.Id == sc {
return true
}
}
}
}
return false
}
22 changes: 1 addition & 21 deletions std/security/signer/context_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,10 @@ import (

// ContextSigner is a wrapper around a signer to provide extra context.
type ContextSigner struct {
Signer ndn.Signer
ndn.Signer
KeyLocatorName enc.Name
}

func (s *ContextSigner) Type() ndn.SigType {
return s.Signer.Type()
}

func (s *ContextSigner) KeyName() enc.Name {
return s.Signer.KeyName()
}

func (s *ContextSigner) KeyLocator() enc.Name {
return s.KeyLocatorName
}

func (s *ContextSigner) EstimateSize() uint {
return s.Signer.EstimateSize()
}

func (s *ContextSigner) Sign(covered enc.Wire) ([]byte, error) {
return s.Signer.Sign(covered)
}

func (s *ContextSigner) Public() ([]byte, error) {
return s.Signer.Public()
}
2 changes: 1 addition & 1 deletion tools/catchunks.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (cc *CatChunks) run() {
defer app.Stop()

// start object client
cli := object.NewClient(app, object.NewMemoryStore())
cli := object.NewClient(app, object.NewMemoryStore(), nil)
err = cli.Start()
if err != nil {
log.Error(cc, "Unable to start object client", "err", err)
Expand Down
2 changes: 1 addition & 1 deletion tools/nfdc/nfdc_dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (

func (n *Nfdc) fetchStatusDataset(suffix enc.Name) ([]byte, error) {
// consume-only client, no need for a store
client := object.NewClient(n.engine, nil)
client := object.NewClient(n.engine, nil, nil)
client.Start()
defer client.Stop()

Expand Down
2 changes: 1 addition & 1 deletion tools/putchunks.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (pc *PutChunks) run() {
defer app.Stop()

// start object client
cli := object.NewClient(app, object.NewMemoryStore())
cli := object.NewClient(app, object.NewMemoryStore(), nil)
err = cli.Start()
if err != nil {
log.Fatal(pc, "Unable to start object client", "err", err)
Expand Down

0 comments on commit c143f81

Please sign in to comment.