update the common library to the master branch

This commit is contained in:
eyedeekay
2024-10-03 21:31:54 -04:00
parent 16961abc96
commit 09c7d32797
19 changed files with 520 additions and 522 deletions

View File

@ -75,7 +75,10 @@ func (c *Certificate) RawBytes() []byte {
// ExcessBytes returns the excess bytes in a certificate found after the specified payload length. // ExcessBytes returns the excess bytes in a certificate found after the specified payload length.
func (c *Certificate) ExcessBytes() []byte { func (c *Certificate) ExcessBytes() []byte {
return c.payload[c.len.Int():] if len(c.payload) >= c.len.Int() {
return c.payload[c.len.Int():]
}
return nil
} }
// Bytes returns the entire certificate in []byte form, trims payload to specified length. // Bytes returns the entire certificate in []byte form, trims payload to specified length.
@ -116,8 +119,8 @@ func (c *Certificate) Data() (data []byte) {
// NewCertificate creates a new Certficiate from []byte // NewCertificate creates a new Certficiate from []byte
// returns err if the certificate is too short or if the payload doesn't match specified length. // returns err if the certificate is too short or if the payload doesn't match specified length.
func NewCertificate(data []byte) (certificate *Certificate, err error) { func NewCertificate(data []byte) (certificate Certificate, err error) {
certificate = &Certificate{} certificate = Certificate{}
switch len(data) { switch len(data) {
case 0: case 0:
certificate.kind = Integer([]byte{0}) certificate.kind = Integer([]byte{0})
@ -126,29 +129,19 @@ func NewCertificate(data []byte) (certificate *Certificate, err error) {
"at": "(Certificate) NewCertificate", "at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data), "certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()), "reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate") }).Error("invalid certificate, empty")
err = fmt.Errorf("error parsing certificate: certificate is too short") err = fmt.Errorf("error parsing certificate: certificate is empty")
return return
case 1: case 1, 2:
certificate.kind = Integer(data[0:0]) certificate.kind = Integer(data[0 : len(data)-1])
certificate.len = Integer([]byte{0}) certificate.len = Integer([]byte{0})
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate", "at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data), "certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()), "reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate") }).Error("invalid certificate, too short")
err = fmt.Errorf("error parsing certificate: certificate is too short") err = fmt.Errorf("error parsing certificate: certificate is too short")
return return
case 2:
certificate.kind = Integer(data[0:1])
certificate.len = Integer([]byte{0})
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate")
err = fmt.Errorf("error parsing certificate length: certificate is too short")
return
default: default:
certificate.kind = Integer(data[0:1]) certificate.kind = Integer(data[0:1])
certificate.len = Integer(data[1:3]) certificate.len = Integer(data[1:3])
@ -160,17 +153,11 @@ func NewCertificate(data []byte) (certificate *Certificate, err error) {
"at": "(Certificate) NewCertificate", "at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(), "certificate_bytes_length": certificate.len.Int(),
"certificate_payload_length": payleng, "certificate_payload_length": payleng,
"data_bytes:": string(data),
"kind_bytes": data[0:1],
"len_bytes": data[1:3],
"reason": err.Error(), "reason": err.Error(),
}).Error("invalid certificate") }).Error("invalid certificate, shorter than specified by length")
return
} else if certificate.len.Int() < len(data)-CERT_MIN_SIZE {
err = fmt.Errorf("certificate parsing warning: certificate data is longer than specified by length")
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(),
"certificate_payload_length": payleng,
"reason": err.Error(),
}).Error("invalid certificate")
return return
} }
return return
@ -179,11 +166,11 @@ func NewCertificate(data []byte) (certificate *Certificate, err error) {
// ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at the end of the input. // ReadCertificate creates a Certificate from []byte and returns any ExcessBytes at the end of the input.
// returns err if the certificate could not be read. // returns err if the certificate could not be read.
func ReadCertificate(data []byte) (certificate *Certificate, remainder []byte, err error) { func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
certificate, err = NewCertificate(data) certificate, err = NewCertificate(data)
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" { if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
remainder = certificate.ExcessBytes()
err = nil err = nil
} }
remainder = certificate.ExcessBytes()
return return
} }

View File

@ -32,12 +32,12 @@ func TestCertificateLengthErrWhenTooShort(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x01} bytes := []byte{0x03, 0x01}
certificate, err := NewCertificate(bytes) certificate, _, err := ReadCertificate(bytes)
cert_len := certificate.Length() cert_len := certificate.Length()
assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data") assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data")
if assert.NotNil(err) { if assert.NotNil(err) {
assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned") assert.Equal("error parsing certificate: certificate is too short", err.Error(), "correct error message should be returned")
} }
} }
@ -71,13 +71,10 @@ func TestCertificateDataWhenTooLong(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa} bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
certificate, err := NewCertificate(bytes) certificate, _, _ := ReadCertificate(bytes)
cert_data := certificate.Data() cert_data := certificate.Data()
if assert.NotNil(err) { cert_len := certificate.Length() // len(cert_data)
assert.Equal("certificate parsing warning: certificate data is longer than specified by length", err.Error(), "correct error message should be returned")
}
cert_len := certificate.Length() //len(cert_data)
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was too long") assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was too long")
if cert_data[0] != 0xff || cert_data[1] != 0xff { if cert_data[0] != 0xff || cert_data[1] != 0xff {
t.Fatal("certificate.Data() returned incorrect data when data was too long") t.Fatal("certificate.Data() returned incorrect data when data was too long")
@ -144,6 +141,6 @@ func TestReadCertificateWithInvalidLength(t *testing.T) {
assert.Equal(cert.length(), 2, "ReadCertificate() should populate the certificate with the provided data even when invalid") assert.Equal(cert.length(), 2, "ReadCertificate() should populate the certificate with the provided data even when invalid")
assert.Equal(len(remainder), 0, "ReadCertificate() returned non-zero length remainder on invalid certificate") assert.Equal(len(remainder), 0, "ReadCertificate() returned non-zero length remainder on invalid certificate")
if assert.NotNil(err) { if assert.NotNil(err) {
assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned") assert.Equal("error parsing certificate: certificate is too short", err.Error(), "correct error message should be returned")
} }
} }

View File

@ -23,8 +23,13 @@ Contents
// https://geti2p.net/spec/common-structures#hash // https://geti2p.net/spec/common-structures#hash
type Hash [32]byte type Hash [32]byte
func (h Hash) Bytes() [32]byte {
return h
}
// HashData returns the SHA256 sum of a []byte input as Hash. // HashData returns the SHA256 sum of a []byte input as Hash.
func HashData(data []byte) (h Hash) { func HashData(data []byte) (h Hash) {
// log.Println("Hashing Data:", data)
h = sha256.Sum256(data) h = sha256.Sum256(data)
return return
} }

View File

@ -50,7 +50,9 @@ func NewInteger(bytes []byte, size int) (integer *Integer, remainder []byte, err
if size < MAX_INTEGER_SIZE { if size < MAX_INTEGER_SIZE {
integerSize = size integerSize = size
} }
i, remainder := ReadInteger(bytes, integerSize) intBytes := bytes[:integerSize]
remainder = bytes[integerSize:]
i, _ := ReadInteger(intBytes, integerSize)
integer = &i integer = &i
return return
} }

View File

@ -126,28 +126,25 @@ func beginsWith(bytes []byte, chr byte) bool {
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error) { func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error) {
if len(bytes) == 0 { if len(bytes) < 3 {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "ReadMapping", "at": "ReadMapping",
"reason": "zero length", "reason": "zero length",
}).Warn("mapping format violation") }).Warn("mapping format violation")
e := errors.New("zero length") e := errors.New("zero length")
err = append(err, e) err = append(err, e)
return
} }
size, remainder, e := NewInteger(bytes, 2) size, remainder, e := NewInteger(bytes, 2)
if e != nil { if e != nil {
err = append(err, e) err = append(err, e)
} }
if size.Int() == 0 {
mapping.size = size return
if e != nil {
log.WithFields(log.Fields{
"at": "ReadMapping",
"reason": "error parsing integer",
}).Warn("mapping format violation")
e := errors.New("error parsing integer")
err = append(err, e)
} }
mapping.size = size
map_bytes := remainder[:mapping.size.Int()]
remainder = remainder[mapping.size.Int():]
if len(remainder) == 0 { if len(remainder) == 0 {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "ReadMapping", "at": "ReadMapping",
@ -156,7 +153,10 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
e := errors.New("zero length") e := errors.New("zero length")
err = append(err, e) err = append(err, e)
} }
vals, remainder, mappingValueErrs := ReadMappingValues(bytes) // TODO: this should take the remainder and the length we already parsed above, as a parameter.
// Like tomorrow morning.
// ReadMappingValues should not attempt to figure out the length of the bytes it's reading over.
vals, _, mappingValueErrs := ReadMappingValues(map_bytes, *mapping.size)
err = append(err, mappingValueErrs...) err = append(err, mappingValueErrs...)
mapping.vals = vals mapping.vals = vals

View File

@ -27,7 +27,6 @@ func TestValuesExclusesPairWithBadData(t *testing.T) {
assert.Equal(key, "a", "Values() returned by data with invalid key contains incorrect present key") assert.Equal(key, "a", "Values() returned by data with invalid key contains incorrect present key")
assert.Equal(val, "b", "Values() returned by data with invalid key contains incorrect present key") assert.Equal(val, "b", "Values() returned by data with invalid key contains incorrect present key")
} }
} }
func TestValuesWarnsMissingData(t *testing.T) { func TestValuesWarnsMissingData(t *testing.T) {

View File

@ -10,6 +10,17 @@ import (
// MappingValues represents the parsed key value pairs inside of an I2P Mapping. // MappingValues represents the parsed key value pairs inside of an I2P Mapping.
type MappingValues [][2]I2PString type MappingValues [][2]I2PString
func (m MappingValues) Get(key I2PString) I2PString {
keyBytes, _ := key.Data()
for _, pair := range m {
kb, _ := pair[0][0:].Data()
if kb == keyBytes {
return pair[1][1:]
}
}
return nil
}
// ValuesToMapping creates a *Mapping using MappingValues. // ValuesToMapping creates a *Mapping using MappingValues.
// The values are sorted in the order defined in mappingOrder. // The values are sorted in the order defined in mappingOrder.
func ValuesToMapping(values MappingValues) *Mapping { func ValuesToMapping(values MappingValues) *Mapping {
@ -46,11 +57,11 @@ func mappingOrder(values MappingValues) {
// ReadMappingValues returns *MappingValues from a []byte. // ReadMappingValues returns *MappingValues from a []byte.
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes []byte, errs []error) { func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingValues, remainder_bytes []byte, errs []error) {
mapping := remainder // mapping := remainder
//var remainder = mapping // var remainder = mapping
//var err error // var err error
if remainder == nil || len(remainder) < 0 { if remainder == nil || len(remainder) < 1 {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Mapping) Values", "at": "(Mapping) Values",
"reason": "data shorter than expected", "reason": "data shorter than expected",
@ -59,31 +70,21 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
return return
} }
map_values := make(MappingValues, 0) map_values := make(MappingValues, 0)
if len(remainder) < 1 { int_map_length := map_length.Int()
log.WithFields(log.Fields{ mapping_len := len(remainder)
"at": "(Mapping) Values", if mapping_len > int_map_length {
"reason": "data shorter than expected",
}).Error("mapping contained no data")
errs = []error{errors.New("mapping contained no data")}
return
}
l := Integer(remainder[:2])
length := l.Int()
// - 2 bytes for map length bits
mapping_len := len(mapping) - 2
if mapping_len > length {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Mapping) Values", "at": "(Mapping) Values",
"mapping_bytes_length": mapping_len, "mapping_bytes_length": mapping_len,
"mapping_length_field": length, "mapping_length_field": int_map_length,
"reason": "data longer than expected", "reason": "data longer than expected",
}).Warn("mapping format warning") }).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: data exists beyond length of mapping")) errs = append(errs, errors.New("warning parsing mapping: data exists beyond length of mapping"))
} else if length > mapping_len { } else if int_map_length > mapping_len {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Mapping) Values", "at": "(Mapping) Values",
"mapping_bytes_length": mapping_len, "mapping_bytes_length": mapping_len,
"mapping_length_field": length, "mapping_length_field": int_map_length,
"reason": "data shorter than expected", "reason": "data shorter than expected",
}).Warn("mapping format warning") }).Warn("mapping format warning")
errs = append(errs, errors.New("warning parsing mapping: mapping length exceeds provided data")) errs = append(errs, errors.New("warning parsing mapping: mapping length exceeds provided data"))
@ -91,7 +92,7 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
encounteredKeysMap := map[string]bool{} encounteredKeysMap := map[string]bool{}
// pop off length bytes before parsing kv pairs // pop off length bytes before parsing kv pairs
remainder = remainder[2:] // remainder = remainder[2:]
for { for {
// Read a key, breaking on fatal errors // Read a key, breaking on fatal errors
@ -111,16 +112,16 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
break break
} }
str, more, err := ReadI2PString(remainder) key_str, more, err := ReadI2PString(remainder)
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
key_str := str
if err != nil { if err != nil {
if stopValueRead(err) { if stopValueRead(err) {
errs = append(errs, err) errs = append(errs, err)
//return // return
} }
} }
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
// log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
// Check if key has already been encountered in this mapping // Check if key has already been encountered in this mapping
keyBytes, _ := key_str.Data() keyBytes, _ := key_str.Data()
@ -130,7 +131,9 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Mapping) Values", "at": "(Mapping) Values",
"reason": "duplicate key in mapping", "reason": "duplicate key in mapping",
"key": string(key_str),
}).Error("mapping format violation") }).Error("mapping format violation")
log.Printf("DUPE: %s", key_str)
errs = append(errs, errors.New("mapping format violation, duplicate key in mapping")) errs = append(errs, errors.New("mapping format violation, duplicate key in mapping"))
// Based on other implementations this does not seem to happen often? // Based on other implementations this does not seem to happen often?
// Java throws an exception in this case, the base object is a Hashmap so the value is overwritten and an exception is thrown. // Java throws an exception in this case, the base object is a Hashmap so the value is overwritten and an exception is thrown.
@ -142,33 +145,39 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Mapping) Values", "at": "(Mapping) Values",
"reason": "expected =", "reason": "expected =",
"value:": string(remainder),
}).Warn("mapping format violation") }).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected =")) errs = append(errs, errors.New("mapping format violation, expected ="))
log.Printf("ERRVAL: %s", remainder)
break break
} else {
remainder = remainder[1:]
} }
remainder = remainder[1:]
// Read a value, breaking on fatal errors // Read a value, breaking on fatal errors
// and appending warnings // and appending warnings
str, more, err = ReadI2PString(remainder) val_str, more, err := ReadI2PString(remainder)
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
val_str := str
if err != nil { if err != nil {
if stopValueRead(err) { if stopValueRead(err) {
errs = append(errs, err) errs = append(errs, err)
//return // return
} }
} }
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
// log.Printf("(MAPPING VALUES DEBUG) Remainder: %s\n", remainder)
// log.Printf("(MAPPING VALUES DEBUG) String: value: %s", val_str)
if !beginsWith(remainder, 0x3b) { if !beginsWith(remainder, 0x3b) {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Mapping) Values", "at": "(Mapping) Values",
"reason": "expected ;", "reason": "expected ;",
"value:": string(remainder),
}).Warn("mapping format violation") }).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected ;")) errs = append(errs, errors.New("mapping format violation, expected ;"))
break break
} else {
remainder = remainder[1:]
} }
remainder = remainder[1:]
// Append the key-value pair and break if there is no more data to read // Append the key-value pair and break if there is no more data to read
map_values = append(map_values, [2]I2PString{key_str, val_str}) map_values = append(map_values, [2]I2PString{key_str, val_str})
@ -181,5 +190,4 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
} }
values = &map_values values = &map_values
return return
} }

View File

@ -2,6 +2,7 @@ package data
import ( import (
"errors" "errors"
"fmt"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -38,28 +39,21 @@ func (str I2PString) Length() (length int, err error) {
err = errors.New("error parsing string: zero length") err = errors.New("error parsing string: zero length")
return return
} }
l := Integer([]byte{byte(str[0])}) l, _, err := NewInteger(str[:], 1)
if err != nil {
return l.Int(), err
}
length = l.Int() length = l.Int()
inferred_len := length + 1
str_len := len(str) str_len := len(str)
if inferred_len > str_len { if length > str_len {
log.WithFields(log.Fields{ /*log.WithFields(log.Fields{
"at": "(I2PString) Length", "at": "(I2PString) Length",
"string_bytes_length": str_len, "string_bytes_length": str_len,
"string_length_field": length, "string_length_field": length,
"expected_bytes_length": inferred_len, "data": string(str),
"reason": "data shorter than specified", "reason": "data less than specified by length",
}).Warn("string format warning") }).Error("string format warning")*/
err = errors.New("string parsing warning: string data is shorter than specified by length") err = errors.New("string parsing warning: string data is shorter than specified by length")
} else if str_len > inferred_len {
log.WithFields(log.Fields{
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
"reason": "data longer than specified",
}).Warn("string format warning")
err = errors.New("string parsing warning: string contains data beyond length")
} }
return return
} }
@ -73,14 +67,20 @@ func (str I2PString) Data() (data string, err error) {
case "error parsing string: zero length": case "error parsing string: zero length":
return return
case "string parsing warning: string data is shorter than specified by length": case "string parsing warning: string data is shorter than specified by length":
data = string(str[1:]) if is, e := ToI2PString(string(str[:])); e != nil {
return return "", e
} else {
return is.Data()
}
case "string parsing warning: string contains data beyond length": case "string parsing warning: string contains data beyond length":
data = string(str[1 : length+1]) data = string(str[1:])
return return
} }
} }
data = string(str[1:]) if length == 0 {
return
}
data = string(str[1 : length+1])
return return
} }
@ -113,20 +113,25 @@ func ToI2PString(data string) (str I2PString, err error) {
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) { func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
str = I2PString(data) length, _, err := NewInteger(data, 1)
length, err := I2PString(data).Length() if err != nil {
if err != nil && err.Error() == "string parsing warning: string contains data beyond length" { return
str = I2PString(data[:length+1]) }
remainder = data[length+1:] data_len := length.Int() + 1
err = nil str = data[:data_len]
remainder = data[data_len:]
l, err := str.Length()
if l != data_len-1 {
err = fmt.Errorf("error reading I2P string, length does not match data")
return
} }
return return
} }
// NewI2PString creates a new *I2PString from []byte using ReadI2PString. // NewI2PString creates a new *I2PString from []byte using ReadI2PString.
// Returns a pointer to I2PString unlike ReadI2PString. // Returns a pointer to I2PString unlike ReadI2PString.
func NewI2PString(data []byte) (str *I2PString, remainder []byte, err error) { /*func NewI2PString(data []byte) (str *I2PString, remainder []byte, err error) {
objstr, remainder, err := ReadI2PString(data) objstr, remainder, err := ReadI2PString(data)
str = &objstr str = &objstr
return return
} }*/

View File

@ -26,7 +26,7 @@ Identical to KeysAndCert.
// //
// https://geti2p.net/spec/common-structures#destination // https://geti2p.net/spec/common-structures#destination
type Destination struct { type Destination struct {
*KeysAndCert KeysAndCert
} }
// Base32Address returns the I2P base32 address for this Destination. // Base32Address returns the I2P base32 address for this Destination.
@ -48,17 +48,9 @@ func (destination Destination) Base64() string {
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) { func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
keys_and_cert, remainder, err := NewKeysAndCert(data) keys_and_cert, remainder, err := ReadKeysAndCert(data)
destination = Destination{ destination = Destination{
keys_and_cert, keys_and_cert,
} }
return return
} }
// NewDestination creates a new *Destination from []byte using ReadDestination.
// Returns a pointer to Destination unlike ReadDestination.
func NewDestination(data []byte) (destination *Destination, remainder []byte, err error) {
objdestination, remainder, err := ReadDestination(data)
destination = &objdestination
return destination, remainder, err
}

View File

@ -52,6 +52,10 @@ const (
// Key Certificate Public Key Types // Key Certificate Public Key Types
const ( const (
KEYCERT_CRYPTO_ELG = iota KEYCERT_CRYPTO_ELG = iota
KEYCERT_CRYPTO_P256
KEYCERT_CRYPTO_P384
KEYCERT_CRYPTO_P521
KEYCERT_CRYPTO_X25519
) )
const ( const (
@ -73,7 +77,11 @@ const (
// PublicKey sizes for Public Key Types // PublicKey sizes for Public Key Types
const ( const (
KEYCERT_CRYPTO_ELG_SIZE = 256 KEYCERT_CRYPTO_ELG_SIZE = 256
KEYCERT_CRYPTO_P256_SIZE = 64
KEYCERT_CRYPTO_P384_SIZE = 96
KEYCERT_CRYPTO_P521_SIZE = 132
KEYCERT_CRYPTO_X25519_SIZE = 32
) )
// Sizes of structures in KeyCertificates // Sizes of structures in KeyCertificates
@ -82,9 +90,9 @@ const (
KEYCERT_SPK_SIZE = 128 KEYCERT_SPK_SIZE = 128
) )
//type KeyCertificate []byte // type KeyCertificate []byte
type KeyCertificate struct { type KeyCertificate struct {
*Certificate Certificate
spkType Integer spkType Integer
cpkType Integer cpkType Integer
} }
@ -112,7 +120,7 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
return return
} }
data_len := len(data) data_len := len(data)
if data_len < KEYCERT_PUBKEY_SIZE { if data_len < key_certificate.CryptoSize() {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(KeyCertificate) ConstructPublicKey", "at": "(KeyCertificate) ConstructPublicKey",
"data_len": data_len, "data_len": data_len,
@ -127,6 +135,10 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
var elg_key crypto.ElgPublicKey var elg_key crypto.ElgPublicKey
copy(elg_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE]) copy(elg_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
public_key = elg_key public_key = elg_key
case KEYCERT_CRYPTO_X25519:
var ed25519_key crypto.Ed25519PublicKey
copy(ed25519_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
public_key = ed25519_key
} }
return return
} }
@ -139,7 +151,7 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
return return
} }
data_len := len(data) data_len := len(data)
if data_len < KEYCERT_SPK_SIZE { if data_len < key_certificate.SignatureSize() {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(KeyCertificate) ConstructSigningPublicKey", "at": "(KeyCertificate) ConstructSigningPublicKey",
"data_len": data_len, "data_len": data_len,
@ -169,11 +181,11 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate.Certificate.RawBytes()[4:4+extra]) copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate.Certificate.RawBytes()[4:4+extra])
signing_public_key = ec_key signing_public_key = ec_key
case KEYCERT_SIGN_RSA2048: case KEYCERT_SIGN_RSA2048:
//var rsa_key crypto.RSA2048PublicKey // var rsa_key crypto.RSA2048PublicKey
//extra := KEYCERT_SIGN_RSA2048_SIZE - 128 // extra := KEYCERT_SIGN_RSA2048_SIZE - 128
//copy(rsa_key[:], data) // copy(rsa_key[:], data)
//copy(rsa_key[128:], key_certificate[4:4+extra]) // copy(rsa_key[128:], key_certificate[4:4+extra])
//signing_public_key = rsa_key // signing_public_key = rsa_key
case KEYCERT_SIGN_RSA3072: case KEYCERT_SIGN_RSA3072:
case KEYCERT_SIGN_RSA4096: case KEYCERT_SIGN_RSA4096:
case KEYCERT_SIGN_ED25519: case KEYCERT_SIGN_ED25519:
@ -185,65 +197,60 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
// SignatureSize return the size of a Signature corresponding to the Key Certificate's SigningPublicKey type. // SignatureSize return the size of a Signature corresponding to the Key Certificate's SigningPublicKey type.
func (key_certificate KeyCertificate) SignatureSize() (size int) { func (key_certificate KeyCertificate) SignatureSize() (size int) {
sizes := map[int]int{ sizes := map[int]int{
KEYCERT_SIGN_DSA_SHA1: 40, KEYCERT_SIGN_DSA_SHA1: KEYCERT_SIGN_DSA_SHA1_SIZE,
KEYCERT_SIGN_P256: 64, KEYCERT_SIGN_P256: KEYCERT_SIGN_P256_SIZE,
KEYCERT_SIGN_P384: 96, KEYCERT_SIGN_P384: KEYCERT_SIGN_P384_SIZE,
KEYCERT_SIGN_P521: 132, KEYCERT_SIGN_P521: KEYCERT_SIGN_P521_SIZE,
KEYCERT_SIGN_RSA2048: 256, KEYCERT_SIGN_RSA2048: KEYCERT_SIGN_RSA2048_SIZE,
KEYCERT_SIGN_RSA3072: 384, KEYCERT_SIGN_RSA3072: KEYCERT_SIGN_RSA3072_SIZE,
KEYCERT_SIGN_RSA4096: 512, KEYCERT_SIGN_RSA4096: KEYCERT_SIGN_RSA4096_SIZE,
KEYCERT_SIGN_ED25519: 64, KEYCERT_SIGN_ED25519: KEYCERT_SIGN_ED25519_SIZE,
KEYCERT_SIGN_ED25519PH: 64, KEYCERT_SIGN_ED25519PH: KEYCERT_SIGN_ED25519PH_SIZE,
} }
key_type := key_certificate.SigningPublicKeyType() key_type := key_certificate.SigningPublicKeyType()
return sizes[int(key_type)] return sizes[int(key_type)]
} }
// CryptoSize return the size of a Public Key corresponding to the Key Certificate's PublicKey type.
func (key_certificate KeyCertificate) CryptoSize() (size int) {
sizes := map[int]int{
KEYCERT_CRYPTO_ELG: KEYCERT_CRYPTO_ELG_SIZE,
KEYCERT_CRYPTO_P256: KEYCERT_CRYPTO_P256_SIZE,
KEYCERT_CRYPTO_P384: KEYCERT_CRYPTO_P384_SIZE,
KEYCERT_CRYPTO_P521: KEYCERT_CRYPTO_P521_SIZE,
KEYCERT_CRYPTO_X25519: KEYCERT_CRYPTO_X25519_SIZE,
}
key_type := key_certificate.PublicKeyType()
return sizes[int(key_type)]
}
// NewKeyCertificate creates a new *KeyCertificate from []byte using ReadCertificate. // NewKeyCertificate creates a new *KeyCertificate from []byte using ReadCertificate.
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder []byte, err error) { func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder []byte, err error) {
var certificate *Certificate var certificate Certificate
certificate, remainder, err = ReadCertificate(bytes) certificate, remainder, err = ReadCertificate(bytes)
//if err != nil { if err != nil {
// return nil, err return
//} }
if len(bytes) < KEYCERT_MIN_SIZE { if len(bytes) < KEYCERT_MIN_SIZE {
err = errors.New("error parsing key certificate: not enough data") err = errors.New("error parsing key certificate: not enough data")
remainder = bytes[KEYCERT_MIN_SIZE:]
} }
switch len(bytes) { key_certificate = &KeyCertificate{
case 4: Certificate: certificate,
key_certificate = &KeyCertificate{ }
Certificate: certificate, if len(bytes) >= 5 {
spkType: Integer(bytes[4:]), key_certificate.spkType = Integer(bytes[4:5])
cpkType: Integer([]byte{0}), }
} if len(bytes) >= 7 {
case 5: key_certificate.cpkType = Integer(bytes[6:7])
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer([]byte{0}),
}
case 6:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer(bytes[6:]),
}
default:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer(bytes[6:7]),
}
} }
remainder = bytes[7:]
//key_certificate.PublicKey = NewPublicKey(bytes)
return return
} }
// KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate. // KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate.
func KeyCertificateFromCertificate(certificate *Certificate) *KeyCertificate { func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate {
k, _, _ := NewKeyCertificate(certificate.RawBytes()) k, _, _ := NewKeyCertificate(certificate.RawBytes())
return k return k
} }

View File

@ -79,103 +79,41 @@ type KeysAndCert struct {
} }
// Bytes returns the entire KeyCertificate in []byte form, trims payload to specified length. // Bytes returns the entire KeyCertificate in []byte form, trims payload to specified length.
func (keys_and_cert *KeysAndCert) Bytes() []byte { func (keys_and_cert KeysAndCert) Bytes() []byte {
return keys_and_cert.KeyCertificate.Bytes() return keys_and_cert.KeyCertificate.Bytes()
} }
// PublicKey returns the public key as a crypto.PublicKey. // PublicKey returns the public key as a crypto.PublicKey.
func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) { func (keys_and_cert *KeysAndCert) PublicKey() (key crypto.PublicKey) {
/*cert := keys_and_cert.Certificate()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
} else {
// A Certificate is present in this KeysAndCert
cert_type := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a PublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
key, err = KeyCertificateFromCertificate(cert).ConstructPublicKey(
keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey. No other Certificate
// types are currently in use.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
log.WithFields(log.Fields{
"at": "(KeysAndCert) PublicKey",
"cert_type": cert_type,
}).Warn("unused certificate type observed")
}
}
return*/
return keys_and_cert.publicKey return keys_and_cert.publicKey
} }
// SigningPublicKey returns the signing public key. // SigningPublicKey returns the signing public key.
func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey) { func (keys_and_cert *KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey) {
/*cert := keys_and_cert.Certificate()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
} else {
// A Certificate is present in this KeysAndCert
cert_type := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a SigningPublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
signing_public_key, err = KeyCertificateFromCertificate(cert).ConstructSigningPublicKey(
keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE : KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy SHA DSA1 SigningPublicKey.
// No other Certificate types are currently in use.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
}
}*/
return keys_and_cert.signingPublicKey return keys_and_cert.signingPublicKey
} }
// Certfificate returns the certificate. // Certfificate returns the certificate.
func (keys_and_cert *KeysAndCert) Certificate() (cert *Certificate) { func (keys_and_cert *KeysAndCert) Certificate() (cert Certificate) {
return keys_and_cert.KeyCertificate.Certificate return keys_and_cert.KeyCertificate.Certificate
} }
// // ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
// Read a KeysAndCert from a slice of bytes, retuning it and the remaining data as well as any errors // Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
// encoutered parsing the KeysAndCert.
//
// ReadKeysAndCert returns KeysAndCert from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) { func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) {
/*data_len := len(data) data_len := len(data)
if data_len < KEYS_AND_CERT_MIN_SIZE { // keys_and_cert = KeysAndCert{}
if data_len < KEYS_AND_CERT_MIN_SIZE && data_len > KEYS_AND_CERT_DATA_SIZE {
log.WithFields(log.Fields{
"at": "ReadKeysAndCert",
"data_len": data_len,
"required_len": KEYS_AND_CERT_MIN_SIZE,
"reason": "not enough data",
}).Error("error parsing keys and cert")
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
keys_and_cert.KeyCertificate, remainder, _ = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
return
} else if data_len < KEYS_AND_CERT_DATA_SIZE {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "ReadKeysAndCert", "at": "ReadKeysAndCert",
"data_len": data_len, "data_len": data_len,
@ -185,56 +123,22 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size") err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
return return
} }
keys_and_cert = KeysAndCert(data[:KEYS_AND_CERT_MIN_SIZE]) keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
cert, _ := keys_and_cert.Certificate() if err != nil {
cert_len := cert.Length()
if cert_len == 0 {
remainder = data[KEYS_AND_CERT_MIN_SIZE:]
return return
} }
if data_len < KEYS_AND_CERT_MIN_SIZE+cert_len { // TODO: this only supports one key type right now and it's the old key type, but the layout is the same.
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:]...) // a case-switch which sets the size of the SPK and the PK should be used to replace the referenced KEYS_AND_CERT_PUBKEY_SIZE
//err = cert_len_err // and KEYS_AND_CERT_SPK_SIZE constants in the future.
} else { keys_and_cert.publicKey, err = keys_and_cert.KeyCertificate.ConstructPublicKey(data[:keys_and_cert.KeyCertificate.CryptoSize()])
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:KEYS_AND_CERT_MIN_SIZE+cert_len]...) if err != nil {
remainder = data[KEYS_AND_CERT_MIN_SIZE+cert_len:] return
}*/ }
keys_and_cert_pointer, remainder, err := NewKeysAndCert(data) keys_and_cert.signingPublicKey, err = keys_and_cert.KeyCertificate.ConstructSigningPublicKey(data[KEYS_AND_CERT_DATA_SIZE-keys_and_cert.KeyCertificate.SignatureSize() : KEYS_AND_CERT_DATA_SIZE])
keys_and_cert = *keys_and_cert_pointer if err != nil {
return
}
padding := data[KEYS_AND_CERT_PUBKEY_SIZE : KEYS_AND_CERT_DATA_SIZE-KEYS_AND_CERT_SPK_SIZE]
keys_and_cert.padding = padding
return return
} }
// NewKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
// Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
func NewKeysAndCert(data []byte) (keys_and_cert *KeysAndCert, remainder []byte, err error) {
data_len := len(data)
keys_and_cert = &KeysAndCert{}
if data_len < KEYS_AND_CERT_MIN_SIZE {
log.WithFields(log.Fields{
"at": "ReadKeysAndCert",
"data_len": data_len,
"required_len": KEYS_AND_CERT_MIN_SIZE,
"reason": "not enough data",
}).Error("error parsing keys and cert")
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
return
}
cert, remainder, err := NewKeyCertificate(data)
keys_and_cert.KeyCertificate = cert
if err != nil {
return nil, nil, err
}
padding := data[KEYS_AND_CERT_MIN_SIZE+cert.Length():]
keys_and_cert.padding = padding
publicKey, err := cert.ConstructPublicKey(padding)
keys_and_cert.publicKey = publicKey
if err != nil {
return nil, nil, err
}
signingPublicKey, err := cert.ConstructSigningPublicKey(padding)
keys_and_cert.signingPublicKey = signingPublicKey
if err != nil {
return nil, nil, err
}
return keys_and_cert, remainder, err
}

View File

@ -6,23 +6,17 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestCertificateWithMissingData(t *testing.T) { /*func TestCertificateWithMissingData(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01} cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01}
data := make([]byte, 128+256) data := make([]byte, 128+256)
data = append(data, cert_data...) data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data) _, _, err := NewKeysAndCert(data)
cert := keys_and_cert.Certificate()
if assert.NotNil(err) { if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error()) assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
} }
cert_bytes := cert.Bytes() }*/
if assert.Equal(len(cert_data), len(cert_bytes)) {
assert.Equal(cert_bytes, cert_data, "keys_and_cert.Certificate() did not return available data when cert was missing some data")
}
}
func TestCertificateWithValidData(t *testing.T) { func TestCertificateWithValidData(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
@ -31,9 +25,10 @@ func TestCertificateWithValidData(t *testing.T) {
data := make([]byte, 128+256) data := make([]byte, 128+256)
data = append(data, cert_data...) data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data) keys_and_cert, _, err := ReadKeysAndCert(data)
assert.Nil(err)
cert := keys_and_cert.Certificate() cert := keys_and_cert.Certificate()
assert.Nil(err)
cert_bytes := cert.Bytes() cert_bytes := cert.Bytes()
if assert.Equal(len(cert_data), len(cert_bytes)) { if assert.Equal(len(cert_data), len(cert_bytes)) {
assert.Equal(cert_bytes, cert_data, "keys_and_cert.Certificate() did not return correct data with valid cert") assert.Equal(cert_bytes, cert_data, "keys_and_cert.Certificate() did not return correct data with valid cert")
@ -168,7 +163,7 @@ func TestSigningPublicKeyWithKeyCertificate(t *testing.T) {
assert.Equal(len(signing_pub_key_data), signing_pub_key.Len()) assert.Equal(len(signing_pub_key_data), signing_pub_key.Len())
} }
func TestReadKeysAndCertWithMissingData(t *testing.T) { func TestNewKeysAndCertWithMissingData(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cert_data := make([]byte, 128) cert_data := make([]byte, 128)
@ -177,10 +172,9 @@ func TestReadKeysAndCertWithMissingData(t *testing.T) {
if assert.NotNil(err) { if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error()) assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
} }
} }
func TestReadKeysAndCertWithMissingCertData(t *testing.T) { func TestNewKeysAndCertWithMissingCertData(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cert_data := make([]byte, 128+256) cert_data := make([]byte, 128+256)
@ -192,7 +186,7 @@ func TestReadKeysAndCertWithMissingCertData(t *testing.T) {
} }
} }
func TestReadKeysAndCertWithValidDataWithCertificate(t *testing.T) { func TestNewKeysAndCertWithValidDataWithCertificate(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cert_data := make([]byte, 128+256) cert_data := make([]byte, 128+256)
@ -202,7 +196,7 @@ func TestReadKeysAndCertWithValidDataWithCertificate(t *testing.T) {
assert.Nil(err) assert.Nil(err)
} }
func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) { func TestNewKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cert_data := make([]byte, 128+256) cert_data := make([]byte, 128+256)
@ -212,7 +206,7 @@ func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
assert.Nil(err) assert.Nil(err)
} }
func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) { func TestNewKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cert_data := make([]byte, 128+256) cert_data := make([]byte, 128+256)
@ -224,7 +218,7 @@ func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
assert.Nil(err) assert.Nil(err)
} }
func TestReadKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T) { func TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
cert_data := make([]byte, 128+256) cert_data := make([]byte, 128+256)

View File

@ -133,6 +133,9 @@ type LeaseSet struct {
// Destination returns the Destination as []byte. // Destination returns the Destination as []byte.
func (lease_set LeaseSet) Destination() (destination Destination, err error) { func (lease_set LeaseSet) Destination() (destination Destination, err error) {
keys_and_cert, _, err := ReadKeysAndCert(lease_set) keys_and_cert, _, err := ReadKeysAndCert(lease_set)
if err != nil {
return
}
destination, _, err = ReadDestination(keys_and_cert.Bytes()) destination, _, err = ReadDestination(keys_and_cert.Bytes())
return return
} }

View File

@ -14,9 +14,9 @@ import (
func buildDestination() *router_identity.RouterIdentity { func buildDestination() *router_identity.RouterIdentity {
router_ident_data := make([]byte, 128+256) router_ident_data := make([]byte, 128+256)
router_ident_data = append(router_ident_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}...) router_ident_data = append(router_ident_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}...)
ident, _, err := router_identity.NewRouterIdentity(router_ident_data) ident, _, err := router_identity.ReadRouterIdentity(router_ident_data)
panic(err) panic(err)
return ident return &ident
} }
func buildPublicKey() []byte { func buildPublicKey() []byte {
@ -77,7 +77,7 @@ func TestDestinationIsCorrect(t *testing.T) {
dest, err := lease_set.Destination() dest, err := lease_set.Destination()
assert.Nil(err) assert.Nil(err)
dest_cert := dest.Certificate() dest_cert := dest.Certificate()
//assert.Nil(err) // assert.Nil(err)
cert_type := dest_cert.Type() cert_type := dest_cert.Type()
assert.Nil(err) assert.Nil(err)
assert.Equal(certificate.CERT_KEY, cert_type) assert.Equal(certificate.CERT_KEY, cert_type)

View File

@ -3,6 +3,10 @@ package router_address
import ( import (
"errors" "errors"
"fmt"
"net"
"strconv"
"strings"
. "github.com/go-i2p/go-i2p/lib/common/data" . "github.com/go-i2p/go-i2p/lib/common/data"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@ -63,71 +67,215 @@ options :: Mapping
// //
// https://geti2p.net/spec/common-structures#routeraddress // https://geti2p.net/spec/common-structures#routeraddress
type RouterAddress struct { type RouterAddress struct {
cost *Integer TransportCost *Integer
expiration *Date ExpirationDate *Date
Transport_Style *I2PString TransportType I2PString
options *Mapping TransportOptions *Mapping
parserErr error
} }
// Network implements net.Addr. It returns the transport type plus 4 or 6
func (router_address *RouterAddress) Network() string {
if router_address.TransportType == nil {
return ""
}
str, err := router_address.TransportType.Data()
if err != nil {
return ""
}
return string(str) + router_address.IPVersion()
}
// IPVersion returns a string "4" for IPv4 or 6 for IPv6
func (router_address *RouterAddress) IPVersion() string {
str, err := router_address.CapsString().Data()
if err != nil {
return ""
}
if strings.HasSuffix(str, "6") {
return "6"
}
return "4"
}
func (router_address *RouterAddress) UDP() bool {
return strings.HasPrefix(strings.ToLower(router_address.Network()), "ssu")
}
// String implements net.Addr. It returns the IP address, followed by the options
func (router_address *RouterAddress) String() string {
var rv []string
rv = append(rv, string(router_address.TransportStyle()))
rv = append(rv, string(router_address.HostString()))
rv = append(rv, string(router_address.PortString()))
rv = append(rv, string(router_address.StaticKeyString()))
rv = append(rv, string(router_address.InitializationVectorString()))
rv = append(rv, string(router_address.ProtocolVersionString()))
if router_address.UDP() {
rv = append(rv, string(router_address.IntroducerHashString(0)))
rv = append(rv, string(router_address.IntroducerExpirationString(0)))
rv = append(rv, string(router_address.IntroducerTagString(0)))
rv = append(rv, string(router_address.IntroducerHashString(1)))
rv = append(rv, string(router_address.IntroducerExpirationString(1)))
rv = append(rv, string(router_address.IntroducerTagString(1)))
rv = append(rv, string(router_address.IntroducerHashString(2)))
rv = append(rv, string(router_address.IntroducerExpirationString(2)))
rv = append(rv, string(router_address.IntroducerTagString(2)))
}
return strings.TrimSpace(strings.Join(rv, " "))
}
var ex_addr net.Addr = &RouterAddress{}
// Bytes returns the router address as a []byte. // Bytes returns the router address as a []byte.
func (router_address RouterAddress) Bytes() []byte { func (router_address RouterAddress) Bytes() []byte {
bytes := make([]byte, 0) bytes := make([]byte, 0)
bytes = append(bytes, router_address.cost.Bytes()...) bytes = append(bytes, router_address.TransportCost.Bytes()...)
bytes = append(bytes, router_address.expiration.Bytes()...) bytes = append(bytes, router_address.ExpirationDate.Bytes()...)
strData, err := router_address.Transport_Style.Data() strData, err := router_address.TransportType.Data()
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"error": err, "error": err,
}).Error("RouterAddress.Bytes: error getting Transport_Style bytes") }).Error("RouterAddress.Bytes: error getting transport_style bytes")
} else { } else {
bytes = append(bytes, strData...) bytes = append(bytes, strData...)
} }
//bytes = append(bytes, router_address.options.Bytes()...) bytes = append(bytes, router_address.TransportOptions.Data()...)
return bytes return bytes
} }
// Cost returns the cost for this RouterAddress as a Go integer. // Cost returns the cost for this RouterAddress as a Go integer.
func (router_address RouterAddress) Cost() int { func (router_address RouterAddress) Cost() int {
return router_address.cost.Int() return router_address.TransportCost.Int()
} }
// Expiration returns the expiration for this RouterAddress as an I2P Date. // Expiration returns the expiration for this RouterAddress as an I2P Date.
func (router_address RouterAddress) Expiration() Date { func (router_address RouterAddress) Expiration() Date {
return *router_address.expiration return *router_address.ExpirationDate
} }
// TransportStyle returns the transport style for this RouterAddress as an I2PString. // TransportStyle returns the transport style for this RouterAddress as an I2PString.
func (router_address RouterAddress) TransportStyle() I2PString { func (router_address RouterAddress) TransportStyle() I2PString {
return *router_address.Transport_Style return router_address.TransportType
}
// GetOption returns the value of the option specified by the key
func (router_address RouterAddress) GetOption(key I2PString) I2PString {
return router_address.Options().Values().Get(key)
}
func (router_address RouterAddress) HostString() I2PString {
host, _ := ToI2PString("host")
return router_address.GetOption(host)
}
func (router_address RouterAddress) PortString() I2PString {
port, _ := ToI2PString("port")
return router_address.GetOption(port)
}
func (router_address RouterAddress) CapsString() I2PString {
caps, _ := ToI2PString("caps")
return router_address.GetOption(caps)
}
func (router_address RouterAddress) StaticKeyString() I2PString {
sk, _ := ToI2PString("s")
return router_address.GetOption(sk)
}
func (router_address RouterAddress) InitializationVectorString() I2PString {
iv, _ := ToI2PString("i")
return router_address.GetOption(iv)
}
func (router_address RouterAddress) ProtocolVersionString() I2PString {
v, _ := ToI2PString("v")
return router_address.GetOption(v)
}
func (router_address RouterAddress) IntroducerHashString(num int) I2PString {
if num >= 0 && num <= 2 {
val := strconv.Itoa(num)
v, _ := ToI2PString("ih" + val)
return router_address.GetOption(v)
}
v, _ := ToI2PString("ih0")
return router_address.GetOption(v)
}
func (router_address RouterAddress) IntroducerExpirationString(num int) I2PString {
if num >= 0 && num <= 2 {
val := strconv.Itoa(num)
v, _ := ToI2PString("iexp" + val)
return router_address.GetOption(v)
}
v, _ := ToI2PString("iexp0")
return router_address.GetOption(v)
}
func (router_address RouterAddress) IntroducerTagString(num int) I2PString {
if num >= 0 && num <= 2 {
val := strconv.Itoa(num)
v, _ := ToI2PString("itag" + val)
return router_address.GetOption(v)
}
v, _ := ToI2PString("itag0")
return router_address.GetOption(v)
}
func (router_address RouterAddress) Host() (net.Addr, error) {
host := router_address.HostString()
hostBytes, err := host.Data()
if err != nil {
return nil, err
}
ip := net.ParseIP(hostBytes)
if ip == nil {
return nil, fmt.Errorf("null host error")
}
return net.ResolveIPAddr("", ip.String())
}
func (router_address RouterAddress) Port() (string, error) {
port := router_address.PortString()
portBytes, err := port.Data()
if err != nil {
return "", err
}
val, err := strconv.Atoi(portBytes)
if err != nil {
return "", err
}
return strconv.Itoa(val), nil
}
func (router_address RouterAddress) StaticKey() ([32]byte, error) {
sk := router_address.StaticKeyString()
if len([]byte(sk)) != 32 {
return [32]byte{}, fmt.Errorf("error: invalid static key")
}
return [32]byte(sk), nil
}
func (router_address RouterAddress) InitializationVector() ([32]byte, error) {
iv := router_address.InitializationVectorString()
if len([]byte(iv)) != 32 {
return [32]byte{}, fmt.Errorf("error: invalid static key")
}
return [32]byte(iv), nil
}
func (router_address RouterAddress) ProtocolVersion() (string, error) {
return router_address.ProtocolVersionString().Data()
} }
// Options returns the options for this RouterAddress as an I2P Mapping. // Options returns the options for this RouterAddress as an I2P Mapping.
func (router_address RouterAddress) Options() Mapping { func (router_address RouterAddress) Options() Mapping {
return *router_address.options return *router_address.TransportOptions
} }
// Check if the RouterAddress is empty or if it is too small to contain valid data. // Check if the RouterAddress is empty or if it is too small to contain valid data.
func (router_address RouterAddress) checkValid() (err error, exit bool) { func (router_address RouterAddress) checkValid() (err error, exit bool) {
/*addr_len := len(router_address)
exit = false
if addr_len == 0 {
log.WithFields(log.Fields{
"at": "(RouterAddress) checkValid",
"reason": "no data",
}).Error("invalid router address")
err = errors.New("error parsing RouterAddress: no data")
exit = true
} else if addr_len < ROUTER_ADDRESS_MIN_SIZE {
log.WithFields(log.Fields{
"at": "(RouterAddress) checkValid",
"reason": "data too small (len < ROUTER_ADDRESS_MIN_SIZE)",
}).Warn("router address format warning")
err = errors.New("warning parsing RouterAddress: data too small")
}*/
if router_address.parserErr != nil {
exit = true
}
return return
} }
@ -135,62 +283,40 @@ func (router_address RouterAddress) checkValid() (err error, exit bool) {
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) { func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) {
if data == nil || len(data) == 0 { if len(data) == 0 {
log.WithField("at", "(RouterAddress) ReadRouterAddress").Error("no data") log.WithField("at", "(RouterAddress) ReadRouterAddress").Error("error parsing RouterAddress: no data")
err = errors.New("error parsing RouterAddress: no data") err = errors.New("error parsing RouterAddress: no data")
router_address.parserErr = err
return return
} }
cost, remainder, err := NewInteger([]byte{data[0]}, 1) router_address.TransportCost, remainder, err = NewInteger(data, 1)
router_address.cost = cost
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress", "at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing cost", "reason": "error parsing cost",
}).Warn("error parsing RouterAddress") }).Warn("error parsing RouterAddress")
router_address.parserErr = err
} }
expiration, remainder, err := NewDate(remainder) router_address.ExpirationDate, remainder, err = NewDate(remainder)
router_address.expiration = expiration
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress", "at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing expiration", "reason": "error parsing expiration",
}).Error("error parsing RouterAddress") }).Error("error parsing RouterAddress")
router_address.parserErr = err
} }
Transport_Style, remainder, err := NewI2PString(remainder) router_address.TransportType, remainder, err = ReadI2PString(remainder)
router_address.Transport_Style = Transport_Style
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress", "at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing Transport_Style", "reason": "error parsing transport_style",
}).Error("error parsing RouterAddress") }).Error("error parsing RouterAddress")
router_address.parserErr = err
} }
options, remainder, errs := NewMapping(remainder) var errs []error
router_address.TransportOptions, remainder, errs = NewMapping(remainder)
for _, err := range errs { for _, err := range errs {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress", "at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing options", "reason": "error parsing options",
}).Error("error parsing RouterAddress") "error": err,
router_address.parserErr = err }).Error("error parsing RozuterAddress")
}
router_address.options = options
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing options",
}).Error("error parsing RouterAddress")
router_address.parserErr = err
} }
return return
} }
// NewRouterAddress creates a new *RouterAddress from []byte using ReadRouterAddress.
// Returns a pointer to RouterAddress unlike ReadRouterAddress.
func NewRouterAddress(data []byte) (router_address *RouterAddress, remainder []byte, err error) {
objrouteraddress, remainder, err := ReadRouterAddress(data)
router_address = &objrouteraddress
return
}

View File

@ -31,7 +31,6 @@ func TestCheckRouterAddressValidReportsDataMissing(t *testing.T) {
err, exit := router_address.checkValid() err, exit := router_address.checkValid()
assert.Equal(exit, false, "checkValid indicates to stop parsing when some fields may be present") assert.Equal(exit, false, "checkValid indicates to stop parsing when some fields may be present")
} }
func TestCheckRouterAddressValidNoErrWithValidData(t *testing.T) { func TestCheckRouterAddressValidNoErrWithValidData(t *testing.T) {
@ -40,8 +39,8 @@ func TestCheckRouterAddressValidNoErrWithValidData(t *testing.T) {
router_address, _, _ := ReadRouterAddress([]byte{0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00}) router_address, _, _ := ReadRouterAddress([]byte{0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00})
mapping, err := GoMapToMapping(map[string]string{"host": "127.0.0.1", "port": "4567"}) mapping, err := GoMapToMapping(map[string]string{"host": "127.0.0.1", "port": "4567"})
assert.Nil(err, "GoMapToMapping() returned error with valid data") assert.Nil(err, "GoMapToMapping() returned error with valid data")
router_address.options = mapping router_address.TransportOptions = mapping
//router_address = append(router_address, mapping...) // router_address = append(router_address, mapping...)
err, exit := router_address.checkValid() err, exit := router_address.checkValid()
assert.Nil(err, "checkValid() reported error with valid data") assert.Nil(err, "checkValid() reported error with valid data")

View File

@ -20,24 +20,16 @@ Identical to KeysAndCert.
// //
// https://geti2p.net/spec/common-structures#routeridentity // https://geti2p.net/spec/common-structures#routeridentity
type RouterIdentity struct { type RouterIdentity struct {
*KeysAndCert KeysAndCert
} }
// ReadRouterIdentity returns RouterIdentity from a []byte. // ReadRouterIdentity returns RouterIdentity from a []byte.
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) { func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) {
keys_and_cert, remainder, err := NewKeysAndCert(data) keys_and_cert, remainder, err := ReadKeysAndCert(data)
router_identity = RouterIdentity{ router_identity = RouterIdentity{
keys_and_cert, keys_and_cert,
} }
return return
} }
// NewRouterIdentity creates a new *RouterIdentity from []byte using ReadRouterIdentity.
// Returns a pointer to RouterIdentity unlike ReadRouterIdentity.
func NewRouterIdentity(data []byte) (router_identity *RouterIdentity, remainder []byte, err error) {
objrouter_identity, remainder, err := ReadRouterIdentity(data)
router_identity = &objrouter_identity
return
}

View File

@ -3,7 +3,7 @@ package router_info
import ( import (
"errors" "errors"
"net" "strconv"
"strings" "strings"
. "github.com/go-i2p/go-i2p/lib/common/data" . "github.com/go-i2p/go-i2p/lib/common/data"
@ -15,6 +15,11 @@ import (
const ROUTER_INFO_MIN_SIZE = 439 const ROUTER_INFO_MIN_SIZE = 439
const (
MIN_GOOD_VERSION = 58
MAX_GOOD_VERSION = 99
)
/* /*
[RouterInfo] [RouterInfo]
Accurate for version 0.9.49 Accurate for version 0.9.49
@ -99,7 +104,7 @@ signature :: Signature
// //
// https://geti2p.net/spec/common-structures#routerinfo // https://geti2p.net/spec/common-structures#routerinfo
type RouterInfo struct { type RouterInfo struct {
router_identity *RouterIdentity router_identity RouterIdentity
published *Date published *Date
size *Integer size *Integer
addresses []*RouterAddress addresses []*RouterAddress
@ -108,13 +113,8 @@ type RouterInfo struct {
signature *Signature signature *Signature
} }
var routerInfoTest net.Addr = &RouterInfo{}
// Bytes returns the RouterInfo as a []byte suitable for writing to a stream. // Bytes returns the RouterInfo as a []byte suitable for writing to a stream.
func (router_info RouterInfo) Bytes() ([]byte, error) { func (router_info RouterInfo) Bytes() (bytes []byte, err error) {
var err error
var bytes []byte
bytes = append(bytes, router_info.router_identity.KeysAndCert.Bytes()...) bytes = append(bytes, router_info.router_identity.KeysAndCert.Bytes()...)
bytes = append(bytes, router_info.published.Bytes()...) bytes = append(bytes, router_info.published.Bytes()...)
bytes = append(bytes, router_info.size.Bytes()...) bytes = append(bytes, router_info.size.Bytes()...)
@ -122,45 +122,34 @@ func (router_info RouterInfo) Bytes() ([]byte, error) {
bytes = append(bytes, router_address.Bytes()...) bytes = append(bytes, router_address.Bytes()...)
} }
bytes = append(bytes, router_info.peer_size.Bytes()...) bytes = append(bytes, router_info.peer_size.Bytes()...)
//bytes = append(bytes, router_info.options.Bytes()...) bytes = append(bytes, router_info.options.Data()...)
bytes = append(bytes, []byte(*router_info.signature)...) bytes = append(bytes, []byte(*router_info.signature)...)
return bytes, err return bytes, err
} }
// Network Implements net.Addr, returns comma-separated list of transport types func (router_info RouterInfo) String() string {
func (router_info *RouterInfo) Network() string { str := "Certificate: " + string(router_info.router_identity.KeysAndCert.Bytes())
var str []string str += "Published: " + string(router_info.published.Bytes())
for _, addr := range router_info.addresses { str += "Addresses:" + string(router_info.size.Bytes())
t, err := addr.Transport_Style.Data() for index, router_address := range router_info.addresses {
if err != nil { str += "Address " + strconv.Itoa(index) + ": " + router_address.String()
return strings.Join(str, ",")
}
str = append(str, t)
} }
return strings.Join(str, ",") str += "Peer Size: " + string(router_info.peer_size.Bytes())
} str += "Options: " + string(router_info.options.Data())
str += "Signature: " + string([]byte(*router_info.signature))
// String Implements net.Addr, returns router-info `Bytes` converted to a string return str
func (router_info *RouterInfo) String() string {
bytes, err := router_info.Bytes()
if err != nil {
// TODO handle this issue
return ""
}
return string(bytes)
} }
// RouterIdentity returns the router identity as *RouterIdentity. // RouterIdentity returns the router identity as *RouterIdentity.
func (router_info *RouterInfo) RouterIdentity() *RouterIdentity { func (router_info *RouterInfo) RouterIdentity() *RouterIdentity {
return router_info.router_identity return &router_info.router_identity
} }
// IndentHash returns the identity hash (sha256 sum) for this RouterInfo. // IndentHash returns the identity hash (sha256 sum) for this RouterInfo.
func (router_info *RouterInfo) IdentHash() Hash { func (router_info *RouterInfo) IdentHash() Hash {
ri := router_info.RouterIdentity() data, _ := router_info.RouterIdentity().KeyCertificate.Data()
h := HashData(ri.KeysAndCert.Certificate().Data()) return HashData(data)
return h
} }
// Published returns the date this RouterInfo was published as an I2P Date. // Published returns the date this RouterInfo was published as an I2P Date.
@ -190,73 +179,21 @@ func (router_info RouterInfo) Options() (mapping Mapping) {
return *router_info.options return *router_info.options
} }
//
// Return the signature of this router info
//
// Signature returns the signature for this RouterInfo as an I2P Signature. // Signature returns the signature for this RouterInfo as an I2P Signature.
func (router_info RouterInfo) Signature() (signature Signature) { func (router_info RouterInfo) Signature() (signature Signature) {
return *router_info.signature return *router_info.signature
} }
// // Network implements net.Addr
// Used during parsing to determine where in the RouterInfo the Mapping data begins. func (router_info RouterInfo) Network() string {
// return "i2p"
/*func (router_info RouterInfo) optionsLocation() (location int) { }
data, remainder, err := ReadRouterIdentity(router_info)
if err != nil {
return
}
location += len(data)
remainder_len := len(remainder)
if remainder_len < 9 {
log.WithFields(log.Fields{
"at": "(RouterInfo) optionsLocation",
"data_len": remainder_len,
"required_len": 9,
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router addresses: not enough data")
return
}
location += 9
remaining := remainder[9:]
var router_address RouterAddress
var router_addresses []RouterAddress
addr_count, cerr := router_info.RouterAddressCount()
if cerr != nil {
err = cerr
return
}
for i := 0; i < addr_count; i++ {
router_address, remaining, err = ReadRouterAddress(remaining)
if err == nil {
location += len(router_address)
router_addresses = append(router_addresses, router_address)
}
}
location += 1
return
}*/
//
// Used during parsing to determine the size of the options in the RouterInfo.
//
/*func (router_info RouterInfo) optionsSize() (size int) {
head := router_info.optionsLocation()
s := Integer(router_info[head : head+2])
size = s.Int() + 2
return
}*/
// ReadRouterInfo returns RouterInfo from a []byte. // ReadRouterInfo returns RouterInfo from a []byte.
// The remaining bytes after the specified length are also returned. // The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing. // Returns a list of errors that occurred during parsing.
func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error) { func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error) {
identity, remainder, err := NewRouterIdentity(bytes) info.router_identity, remainder, err = ReadRouterIdentity(bytes)
info.router_identity = identity
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo", "at": "(RouterInfo) ReadRouterInfo",
@ -265,9 +202,9 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
"reason": "not enough data", "reason": "not enough data",
}).Error("error parsing router info") }).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data") err = errors.New("error parsing router info: not enough data")
return
} }
date, remainder, err := NewDate(remainder) info.published, remainder, err = NewDate(remainder)
info.published = date
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo", "at": "(RouterInfo) ReadRouterInfo",
@ -277,36 +214,32 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
}).Error("error parsing router info") }).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data") err = errors.New("error parsing router info: not enough data")
} }
size, remainder, err := NewInteger(remainder, 1) info.size, remainder, err = NewInteger(remainder, 1)
info.size = size
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo", "at": "(RouterInfo) ReadRouterInfo",
"data_len": len(remainder), "data_len": len(remainder),
"required_len": size.Int(), "required_len": info.size.Int(),
"reason": "not enough data", "reason": "read error",
}).Error("error parsing router info") }).Error("error parsing router info size")
err = errors.New("error parsing router info: not enough data")
} }
addresses := make([]*RouterAddress, size.Int()) for i := 0; i < info.size.Int(); i++ {
for i := 0; i < size.Int(); i++ { address, more, err := ReadRouterAddress(remainder)
address, remainder, err := NewRouterAddress(remainder) remainder = more
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo", "at": "(RouterInfo) ReadRouterInfo",
"data_len": len(remainder), "data_len": len(remainder),
//"required_len": ROUTER_ADDRESS_SIZE, //"required_len": ROUTER_ADDRESS_SIZE,
"reason": "not enough data", "reason": "not enough data",
}).Error("error parsing router info") }).Error("error parsing router address")
err = errors.New("error parsing router info: not enough data") err = errors.New("error parsing router info: not enough data")
} }
addresses = append(addresses, address) info.addresses = append(info.addresses, &address)
} }
info.addresses = addresses info.peer_size, remainder, err = NewInteger(remainder, 1)
peer_size := Integer(remainder[:1]) var errs []error
info.peer_size = &peer_size info.options, remainder, errs = NewMapping(remainder)
remainder = remainder[1:]
options, remainder, errs := NewMapping(remainder)
if len(errs) != 0 { if len(errs) != 0 {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo", "at": "(RouterInfo) ReadRouterInfo",
@ -320,7 +253,7 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
} }
err = errors.New("error parsing router info: " + estring) err = errors.New("error parsing router info: " + estring)
} }
info.options = options info.signature, remainder, err = NewSignature(remainder)
if err != nil { if err != nil {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo", "at": "(RouterInfo) ReadRouterInfo",
@ -333,10 +266,57 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
return return
} }
// NewRouterInfo creates a new *RouterInfo from []byte using ReadRouterInfo. func (router_info *RouterInfo) RouterCapabilities() string {
// Returns a pointer to RouterInfo unlike ReadRouterInfo. str, err := ToI2PString("caps")
func NewRouterInfo(data []byte) (router_info *RouterInfo, remainder []byte, err error) { if err != nil {
routerInfo, remainder, err := ReadRouterInfo(data) return ""
router_info = &routerInfo }
return return string(router_info.options.Values().Get(str))
}
func (router_info *RouterInfo) RouterVersion() string {
str, err := ToI2PString("router.version")
if err != nil {
return ""
}
return string(router_info.options.Values().Get(str))
}
func (router_info *RouterInfo) GoodVersion() bool {
version := router_info.RouterVersion()
v := strings.Split(version, ".")
if len(v) != 3 {
return false
}
if v[0] == "0" {
if v[1] == "9" {
val, _ := strconv.Atoi(v[2])
if val >= MIN_GOOD_VERSION && val <= MAX_GOOD_VERSION {
return true
}
}
}
return false
}
func (router_info *RouterInfo) UnCongested() bool {
caps := router_info.RouterCapabilities()
if strings.Contains(caps, "K") {
return false
}
if strings.Contains(caps, "G") {
return false
}
if strings.Contains(caps, "E") {
return false
}
return true
}
func (router_info *RouterInfo) Reachable() bool {
caps := router_info.RouterCapabilities()
if strings.Contains(caps, "U") {
return false
}
return strings.Contains(caps, "R")
} }

View File

@ -131,7 +131,6 @@ func TestRouterAddressesReturnsAddresses(t *testing.T) {
), ),
) )
} }
} }
func TestRouterAddressesReturnsAddressesWithMultiple(t *testing.T) { func TestRouterAddressesReturnsAddressesWithMultiple(t *testing.T) {
@ -162,7 +161,6 @@ func TestRouterAddressesReturnsAddressesWithMultiple(t *testing.T) {
) )
} }
} }
} }
func TestPeerSizeIsZero(t *testing.T) { func TestPeerSizeIsZero(t *testing.T) {
@ -200,7 +198,7 @@ func TestRouterIdentityIsCorrect(t *testing.T) {
router_info, _ := buildFullRouterInfo() router_info, _ := buildFullRouterInfo()
router_identity := router_info.RouterIdentity() router_identity := router_info.RouterIdentity()
//assert.Nil(err) // assert.Nil(err)
assert.Equal( assert.Equal(
0, 0,
bytes.Compare( bytes.Compare(