safing-jess/letter-wire.go

189 lines
3.7 KiB
Go

package jess
import (
"errors"
"github.com/safing/structures/container"
)
/*
### Wire Format Version 1
- Wire Format Version: varint
- Flags: varint
- 1: Setup Msg (includes Version and Tools)
- 2: Sending Keys
- 4: Apply Keys
- Version: varint (if Setup Msg)
- SuiteID: byte block (if Setup Msg)
- Keys:
- Amount: varint
- IDs/Values: byte blocks
- Nonce: byte block
- Data: byte block
- MAC: byte block
*/
// ErrIncompatibleWireFormatVersion is returned when an incompatible wire format is encountered.
var ErrIncompatibleWireFormatVersion = errors.New("incompatible wire format version")
// ToWire serializes to letter for sending it over a network connection.
func (letter *Letter) ToWire() (*container.Container, error) {
c := container.New()
// Wire Format Version: varint
c.AppendNumber(1)
// Flags: varint
// - 1: Setup Msg (includes Version and Tools)
// - 2: Sending Keys
// - 4: Apply Keys
var flags uint64
if letter.Version > 0 {
flags |= 1
}
if len(letter.Keys) > 0 {
flags |= 2
}
if letter.ApplyKeys {
flags |= 4
}
c.AppendNumber(flags)
if letter.Version > 0 {
// Version: varint (if Setup Msg)
c.AppendNumber(uint64(letter.Version))
// SuiteID: byte block (if Setup Msg)
c.AppendAsBlock([]byte(letter.SuiteID))
}
if len(letter.Keys) > 0 {
// Keys:
// - Amount: varint
// - IDs/Values: byte blocks
c.AppendInt(len(letter.Keys))
for _, seal := range letter.Keys {
c.AppendAsBlock([]byte(seal.ID))
c.AppendAsBlock(seal.Value)
}
}
// Nonce: byte block
c.AppendAsBlock(letter.Nonce)
// Data: byte block
c.AppendAsBlock(letter.Data)
// MAC: byte block
c.AppendAsBlock(letter.Mac)
// debugging:
// fmt.Printf("%+v\n", c.CompileData())
return c, nil
}
// LetterFromWireData is a relay to LetterFromWire to quickly fix import issues of godep.
//
// Deprecated: Please use LetterFromWire with a fresh container directly.
func LetterFromWireData(data []byte) (*Letter, error) {
return LetterFromWire(container.New(data))
}
// LetterFromWire parses a letter sent over a network connection.
func LetterFromWire(c *container.Container) (*Letter, error) {
letter := &Letter{}
// Wire Format Version: varint
wireFormatVersion, err := c.GetNextN8()
if err != nil {
return nil, err
}
if wireFormatVersion != 1 {
return nil, ErrIncompatibleWireFormatVersion
}
// Flags: varint
// - 1: Setup Msg (includes Version and Tools)
// - 2: Sending Keys
// - 4: Apply Keys
var (
setupMsg bool
sendingKeys bool
)
flags, err := c.GetNextN64()
if err != nil {
return nil, err
}
if flags&1 > 0 {
setupMsg = true
}
if flags&2 > 0 {
sendingKeys = true
}
if flags&4 > 0 {
letter.ApplyKeys = true
}
if setupMsg {
// Version: varint (if Setup Msg)
n, err := c.GetNextN8()
if err != nil {
return nil, err
}
letter.Version = n
// SuiteID: byte block (if Setup Msg)
suiteID, err := c.GetNextBlock()
if err != nil {
return nil, err
}
letter.SuiteID = string(suiteID)
}
if sendingKeys {
// Keys:
// - Amount: varint
// - IDs/Values: byte blocks
n, err := c.GetNextN8()
if err != nil {
return nil, err
}
letter.Keys = make([]*Seal, n)
for i := 0; i < len(letter.Keys); i++ {
signetID, err := c.GetNextBlock()
if err != nil {
return nil, err
}
sealValue, err := c.GetNextBlock()
if err != nil {
return nil, err
}
letter.Keys[i] = &Seal{
ID: string(signetID),
Value: sealValue,
}
}
}
// Nonce: byte block
letter.Nonce, err = c.GetNextBlock()
if err != nil {
return nil, err
}
// Data: byte block
letter.Data, err = c.GetNextBlock()
if err != nil {
return nil, err
}
// MAC: byte block
letter.Mac, err = c.GetNextBlock()
if err != nil {
return nil, err
}
return letter, nil
}