5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2025-01-11 11:55:41 +00:00
yggdrasil-go/src/core/version.go

155 lines
4.1 KiB
Go
Raw Normal View History

2021-05-23 19:42:26 +00:00
package core
2018-06-09 23:44:59 +00:00
// This file contains the version metadata struct
2019-11-29 09:45:02 +00:00
// Used in the initial connection setup and key exchange
2018-06-09 23:44:59 +00:00
// Some of this could arguably go in wire.go instead
2023-03-18 12:14:32 +00:00
import (
"bytes"
"crypto/ed25519"
"encoding/binary"
"fmt"
2023-06-18 19:28:14 +00:00
"io"
"golang.org/x/crypto/blake2b"
2023-03-18 12:14:32 +00:00
)
// This is the version-specific metadata exchanged at the start of a connection.
2019-11-29 09:45:02 +00:00
// It must always begin with the 4 bytes "meta" and a wire formatted uint64 major version number.
// The current version also includes a minor version number, and the box/sig/link keys that need to be exchanged to open a connection.
2018-06-09 23:44:59 +00:00
type version_metadata struct {
2023-03-18 12:14:32 +00:00
majorVer uint16
minorVer uint16
publicKey ed25519.PublicKey
priority uint8
2018-06-09 23:44:59 +00:00
}
2023-03-18 12:14:32 +00:00
const (
ProtocolVersionMajor uint16 = 0
ProtocolVersionMinor uint16 = 5
)
// Once a major/minor version is released, it is not safe to change any of these
// (including their ordering), it is only safe to add new ones.
2023-03-18 12:14:32 +00:00
const (
metaVersionMajor uint16 = iota // uint16
metaVersionMinor // uint16
metaPublicKey // [32]byte
metaPriority // uint8
)
// Gets a base metadata with no keys set, but with the correct version numbers.
2018-06-09 23:44:59 +00:00
func version_getBaseMetadata() version_metadata {
return version_metadata{
2023-03-18 12:14:32 +00:00
majorVer: ProtocolVersionMajor,
minorVer: ProtocolVersionMinor,
2018-06-09 23:44:59 +00:00
}
}
// Encodes version metadata into its wire format.
func (m *version_metadata) encode(privateKey ed25519.PrivateKey, password []byte) ([]byte, error) {
2023-03-18 12:14:32 +00:00
bs := make([]byte, 0, 64)
bs = append(bs, 'm', 'e', 't', 'a')
2023-06-18 19:28:14 +00:00
bs = append(bs, 0, 0) // Remaining message length
2023-03-18 12:14:32 +00:00
bs = binary.BigEndian.AppendUint16(bs, metaVersionMajor)
bs = binary.BigEndian.AppendUint16(bs, 2)
bs = binary.BigEndian.AppendUint16(bs, m.majorVer)
bs = binary.BigEndian.AppendUint16(bs, metaVersionMinor)
bs = binary.BigEndian.AppendUint16(bs, 2)
bs = binary.BigEndian.AppendUint16(bs, m.minorVer)
bs = binary.BigEndian.AppendUint16(bs, metaPublicKey)
bs = binary.BigEndian.AppendUint16(bs, ed25519.PublicKeySize)
bs = append(bs, m.publicKey[:]...)
bs = binary.BigEndian.AppendUint16(bs, metaPriority)
bs = binary.BigEndian.AppendUint16(bs, 1)
bs = append(bs, m.priority)
hasher, err := blake2b.New512(password)
if err != nil {
return nil, err
}
n, err := hasher.Write(m.publicKey)
if err != nil {
return nil, err
}
if n != ed25519.PublicKeySize {
return nil, fmt.Errorf("hash writer only wrote %d bytes", n)
}
hash := hasher.Sum(nil)
bs = append(bs, ed25519.Sign(privateKey, hash)...)
2023-06-18 19:28:14 +00:00
binary.BigEndian.PutUint16(bs[4:6], uint16(len(bs)-6))
return bs, nil
2018-06-09 23:44:59 +00:00
}
// Decodes version metadata from its wire format into the struct.
func (m *version_metadata) decode(r io.Reader, password []byte) bool {
2023-06-18 19:28:14 +00:00
bh := [6]byte{}
if _, err := io.ReadFull(r, bh[:]); err != nil {
return false
}
2023-03-18 12:14:32 +00:00
meta := [4]byte{'m', 'e', 't', 'a'}
2023-06-18 19:28:14 +00:00
if !bytes.Equal(bh[:4], meta[:]) {
return false
}
bs := make([]byte, binary.BigEndian.Uint16(bh[4:6]))
if _, err := io.ReadFull(r, bs); err != nil {
2018-06-09 23:44:59 +00:00
return false
}
sig := bs[len(bs)-ed25519.SignatureSize:]
bs = bs[:len(bs)-ed25519.SignatureSize]
2023-06-18 19:28:14 +00:00
for len(bs) >= 4 {
2023-03-18 12:14:32 +00:00
op := binary.BigEndian.Uint16(bs[:2])
oplen := binary.BigEndian.Uint16(bs[2:4])
if bs = bs[4:]; len(bs) < int(oplen) {
break
}
switch op {
case metaVersionMajor:
m.majorVer = binary.BigEndian.Uint16(bs[:2])
case metaVersionMinor:
m.minorVer = binary.BigEndian.Uint16(bs[:2])
case metaPublicKey:
m.publicKey = make(ed25519.PublicKey, ed25519.PublicKeySize)
copy(m.publicKey, bs[:ed25519.PublicKeySize])
case metaPriority:
m.priority = bs[0]
}
bs = bs[oplen:]
}
hasher, err := blake2b.New512(password)
if err != nil {
return false
}
n, err := hasher.Write(m.publicKey)
if err != nil || n != ed25519.PublicKeySize {
return false
}
hash := hasher.Sum(nil)
return ed25519.Verify(m.publicKey, hash, sig)
2018-06-09 23:44:59 +00:00
}
// Checks that the "meta" bytes and the version numbers are the expected values.
2018-06-09 23:44:59 +00:00
func (m *version_metadata) check() bool {
2023-03-18 12:14:32 +00:00
switch {
case m.majorVer != ProtocolVersionMajor:
return false
case m.minorVer != ProtocolVersionMinor:
return false
case len(m.publicKey) != ed25519.PublicKeySize:
return false
default:
return true
}
2018-06-09 23:44:59 +00:00
}