graphvent/user.go

240 lines
5.5 KiB
Go

2023-07-20 22:08:28 -06:00
package graphvent
import (
"fmt"
"time"
2023-07-20 22:08:28 -06:00
"encoding/json"
"crypto/ecdsa"
"crypto/x509"
"crypto/ecdh"
2023-07-20 22:08:28 -06:00
)
type ECDHState struct {
ECKey *ecdh.PrivateKey
SharedSecret []byte
}
type ECDHStateJSON struct {
ECKey []byte `json:"ec_key"`
SharedSecret []byte `json:"shared_secret"`
}
func (state *ECDHState) MarshalJSON() ([]byte, error) {
var key_bytes []byte
var err error
if state.ECKey != nil {
key_bytes, err = x509.MarshalPKCS8PrivateKey(state.ECKey)
if err != nil {
return nil, err
}
}
return json.Marshal(&ECDHStateJSON{
ECKey: key_bytes,
SharedSecret: state.SharedSecret,
})
}
func (state *ECDHState) UnmarshalJSON(data []byte) error {
var j ECDHStateJSON
err := json.Unmarshal(data, &j)
if err != nil {
return err
}
state.SharedSecret = j.SharedSecret
if len(j.ECKey) == 0 {
state.ECKey = nil
} else {
tmp_key, err := x509.ParsePKCS8PrivateKey(j.ECKey)
if err != nil {
return err
}
ecdsa_key, ok := tmp_key.(*ecdsa.PrivateKey)
if ok == false {
return fmt.Errorf("Parsed wrong key type from DB for ECDHState")
}
state.ECKey, err = ecdsa_key.ECDH()
if err != nil {
return err
}
}
return nil
}
type ECDHMap map[NodeID]ECDHState
func (m ECDHMap) MarshalJSON() ([]byte, error) {
tmp := map[string]ECDHState{}
for id, state := range(m) {
tmp[id.String()] = state
}
return json.Marshal(tmp)
}
2023-07-26 00:18:11 -06:00
type ECDHExt struct {
ECDHStates ECDHMap
}
func NewECDHExt() *ECDHExt {
return &ECDHExt{
ECDHStates: ECDHMap{},
}
2023-07-20 22:08:28 -06:00
}
func ResolveFields[T Extension](t T, name string, field_funcs map[string]func(T)interface{})interface{} {
var zero T
field_func, ok := field_funcs[name]
if ok == false {
return fmt.Errorf("%s is not a field of %s", name, zero.Type())
}
return field_func(t)
}
func (ext *ECDHExt) Field(name string) interface{} {
return ResolveFields(ext, name, map[string]func(*ECDHExt)interface{}{
"ecdh_states": func(ext *ECDHExt) interface{} {
return ext.ECDHStates
},
})
}
func (ext *ECDHExt) HandleECDHSignal(ctx *Context, source NodeID, node *Node, signal ECDHSignal) {
ctx.Log.Logf("ecdh", "ECDH_SIGNAL: %s->%s - %+v", source, node, signal)
switch signal.State {
case "req":
state, exists := ext.ECDHStates[source]
if exists == false {
state = ECDHState{nil, nil}
}
resp, shared_secret, err := NewECDHRespSignal(ctx, node, signal)
if err == nil {
state.SharedSecret = shared_secret
ext.ECDHStates[source] = state
ctx.Log.Logf("ecdh", "New shared secret for %s<->%s - %+v", node.ID, source, ext.ECDHStates[source].SharedSecret)
ctx.Send(node.ID, source, resp)
} else {
ctx.Log.Logf("ecdh", "ECDH_REQ_ERR: %s", err)
// TODO: send error response
}
case "resp":
state, exists := ext.ECDHStates[source]
if exists == false || state.ECKey == nil {
ctx.Send(node.ID, source, StateSignal{NewDirectSignal(ECDHSignalType), "no_req"})
} else {
err := VerifyECDHSignal(time.Now(), signal, DEFAULT_ECDH_WINDOW)
if err == nil {
shared_secret, err := state.ECKey.ECDH(signal.ECDH)
if err == nil {
state.SharedSecret = shared_secret
state.ECKey = nil
ext.ECDHStates[source] = state
ctx.Log.Logf("ecdh", "New shared secret for %s<->%s - %+v", node.ID, source, ext.ECDHStates[source].SharedSecret)
}
}
}
default:
ctx.Log.Logf("ecdh", "unknown echd state %s", signal.State)
}
2023-07-20 22:08:28 -06:00
}
func (ext *ECDHExt) HandleStateSignal(ctx *Context, source NodeID, node *Node, signal StateSignal) {
}
func (ext *ECDHExt) Process(ctx *Context, source NodeID, node *Node, signal Signal) {
switch signal.Direction() {
case Direct:
switch signal.Type() {
case ECDHSignalType:
switch ecdh_signal := signal.(type) {
case ECDHSignal:
ext.HandleECDHSignal(ctx, source, node, ecdh_signal)
case StateSignal:
ext.HandleStateSignal(ctx, source, node, ecdh_signal)
default:
ctx.Log.Logf("ecdh", "BAD_SIGNAL_CAST: %+v", signal)
}
default:
}
default:
}
2023-07-20 22:08:28 -06:00
}
2023-07-26 00:18:11 -06:00
func (ext *ECDHExt) Type() ExtType {
return ECDHExtType
}
func (ext *ECDHExt) Serialize() ([]byte, error) {
return json.MarshalIndent(ext, "", " ")
2023-07-20 22:08:28 -06:00
}
2023-07-26 00:18:11 -06:00
func LoadECDHExt(ctx *Context, data []byte) (Extension, error) {
var ext ECDHExt
err := json.Unmarshal(data, &ext)
2023-07-20 22:08:28 -06:00
if err != nil {
return nil, err
}
return &ext, nil
2023-07-25 09:51:55 -06:00
}
2023-07-26 00:18:11 -06:00
type GroupExt struct {
Members map[NodeID]string
}
type GroupExtJSON struct {
Members map[string]string `json:"members"`
2023-07-25 09:51:55 -06:00
}
2023-07-26 00:18:11 -06:00
func (ext *GroupExt) Type() ExtType {
return GroupExtType
2023-07-25 09:51:55 -06:00
}
2023-07-26 00:18:11 -06:00
func (ext *GroupExt) Serialize() ([]byte, error) {
return json.MarshalIndent(&GroupExtJSON{
Members: IDMap(ext.Members),
2023-07-26 00:18:11 -06:00
}, "", " ")
2023-07-25 09:51:55 -06:00
}
func (ext *GroupExt) Field(name string) interface{} {
return ResolveFields(ext, name, map[string]func(*GroupExt)interface{}{
"members": func(ext *GroupExt) interface{} {
return ext.Members
},
})
}
func NewGroupExt(members map[NodeID]string) *GroupExt {
2023-07-26 11:56:10 -06:00
if members == nil {
members = map[NodeID]string{}
2023-07-26 11:56:10 -06:00
}
2023-07-26 11:56:10 -06:00
return &GroupExt{
Members: members,
}
}
2023-07-26 00:18:11 -06:00
func LoadGroupExt(ctx *Context, data []byte) (Extension, error) {
var j GroupExtJSON
2023-07-26 00:18:11 -06:00
err := json.Unmarshal(data, &j)
2023-07-25 09:51:55 -06:00
members, err := LoadIDMap(j.Members)
2023-07-26 00:18:11 -06:00
if err != nil {
return nil, err
}
return &GroupExt{
Members: members,
}, nil
2023-07-26 00:18:11 -06:00
}
2023-07-25 09:51:55 -06:00
func (ext *GroupExt) Process(ctx *Context, princ_id NodeID, node *Node, signal Signal) {
return
2023-07-26 00:18:11 -06:00
}