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.
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.
@@ -116,8 +119,8 @@ func (c *Certificate) Data() (data []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.
func NewCertificate(data []byte) (certificate *Certificate, err error) {
certificate = &Certificate{}
func NewCertificate(data []byte) (certificate Certificate, err error) {
certificate = Certificate{}
switch len(data) {
case 0:
certificate.kind = Integer([]byte{0})
@@ -126,29 +129,19 @@ func NewCertificate(data []byte) (certificate *Certificate, err error) {
"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: certificate is too short")
}).Error("invalid certificate, empty")
err = fmt.Errorf("error parsing certificate: certificate is empty")
return
case 1:
certificate.kind = Integer(data[0:0])
case 1, 2:
certificate.kind = Integer(data[0 : len(data)-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")
}).Error("invalid certificate, too short")
err = fmt.Errorf("error parsing certificate: certificate is too short")
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:
certificate.kind = Integer(data[0:1])
certificate.len = Integer(data[1:3])
@@ -160,17 +153,11 @@ func NewCertificate(data []byte) (certificate *Certificate, err error) {
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.len.Int(),
"certificate_payload_length": payleng,
"data_bytes:": string(data),
"kind_bytes": data[0:1],
"len_bytes": data[1:3],
"reason": err.Error(),
}).Error("invalid certificate")
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")
}).Error("invalid certificate, shorter than specified by length")
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.
// 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)
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
remainder = certificate.ExcessBytes()
err = nil
}
remainder = certificate.ExcessBytes()
return
}

View File

@@ -32,12 +32,12 @@ func TestCertificateLengthErrWhenTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x01}
certificate, err := NewCertificate(bytes)
certificate, _, err := ReadCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data")
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)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
certificate, err := NewCertificate(bytes)
certificate, _, _ := ReadCertificate(bytes)
cert_data := certificate.Data()
if assert.NotNil(err) {
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)
cert_len := certificate.Length() // len(cert_data)
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 {
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(len(remainder), 0, "ReadCertificate() returned non-zero length remainder on invalid certificate")
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
type Hash [32]byte
func (h Hash) Bytes() [32]byte {
return h
}
// HashData returns the SHA256 sum of a []byte input as Hash.
func HashData(data []byte) (h Hash) {
// log.Println("Hashing Data:", data)
h = sha256.Sum256(data)
return
}

View File

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

View File

@@ -126,28 +126,25 @@ func beginsWith(bytes []byte, chr byte) bool {
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error) {
if len(bytes) == 0 {
if len(bytes) < 3 {
log.WithFields(log.Fields{
"at": "ReadMapping",
"reason": "zero length",
}).Warn("mapping format violation")
e := errors.New("zero length")
err = append(err, e)
return
}
size, remainder, e := NewInteger(bytes, 2)
if e != nil {
err = append(err, e)
}
mapping.size = size
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)
if size.Int() == 0 {
return
}
mapping.size = size
map_bytes := remainder[:mapping.size.Int()]
remainder = remainder[mapping.size.Int():]
if len(remainder) == 0 {
log.WithFields(log.Fields{
"at": "ReadMapping",
@@ -156,7 +153,10 @@ func ReadMapping(bytes []byte) (mapping Mapping, remainder []byte, err []error)
e := errors.New("zero length")
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...)
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(val, "b", "Values() returned by data with invalid key contains incorrect present key")
}
}
func TestValuesWarnsMissingData(t *testing.T) {

View File

@@ -10,6 +10,17 @@ import (
// MappingValues represents the parsed key value pairs inside of an I2P Mapping.
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.
// The values are sorted in the order defined in mappingOrder.
func ValuesToMapping(values MappingValues) *Mapping {
@@ -46,11 +57,11 @@ func mappingOrder(values MappingValues) {
// ReadMappingValues returns *MappingValues from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes []byte, errs []error) {
mapping := remainder
//var remainder = mapping
//var err error
if remainder == nil || len(remainder) < 0 {
func ReadMappingValues(remainder []byte, map_length Integer) (values *MappingValues, remainder_bytes []byte, errs []error) {
// mapping := remainder
// var remainder = mapping
// var err error
if remainder == nil || len(remainder) < 1 {
log.WithFields(log.Fields{
"at": "(Mapping) Values",
"reason": "data shorter than expected",
@@ -59,31 +70,21 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
return
}
map_values := make(MappingValues, 0)
if len(remainder) < 1 {
log.WithFields(log.Fields{
"at": "(Mapping) Values",
"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 {
int_map_length := map_length.Int()
mapping_len := len(remainder)
if mapping_len > int_map_length {
log.WithFields(log.Fields{
"at": "(Mapping) Values",
"mapping_bytes_length": mapping_len,
"mapping_length_field": length,
"mapping_length_field": int_map_length,
"reason": "data longer than expected",
}).Warn("mapping format warning")
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{
"at": "(Mapping) Values",
"mapping_bytes_length": mapping_len,
"mapping_length_field": length,
"mapping_length_field": int_map_length,
"reason": "data shorter than expected",
}).Warn("mapping format warning")
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{}
// pop off length bytes before parsing kv pairs
remainder = remainder[2:]
// remainder = remainder[2:]
for {
// Read a key, breaking on fatal errors
@@ -111,16 +112,16 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
break
}
str, more, err := ReadI2PString(remainder)
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
key_str := str
key_str, more, err := ReadI2PString(remainder)
if err != nil {
if stopValueRead(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
keyBytes, _ := key_str.Data()
@@ -130,7 +131,9 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
log.WithFields(log.Fields{
"at": "(Mapping) Values",
"reason": "duplicate key in mapping",
"key": string(key_str),
}).Error("mapping format violation")
log.Printf("DUPE: %s", key_str)
errs = append(errs, errors.New("mapping format violation, duplicate key in mapping"))
// 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.
@@ -142,33 +145,39 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
log.WithFields(log.Fields{
"at": "(Mapping) Values",
"reason": "expected =",
"value:": string(remainder),
}).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected ="))
log.Printf("ERRVAL: %s", remainder)
break
} else {
remainder = remainder[1:]
}
remainder = remainder[1:]
// Read a value, breaking on fatal errors
// and appending warnings
str, more, err = ReadI2PString(remainder)
// overwriting remainder with more as another var to prevent memory weirdness in loops
remainder = more
val_str := str
val_str, more, err := ReadI2PString(remainder)
if err != nil {
if stopValueRead(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) {
log.WithFields(log.Fields{
"at": "(Mapping) Values",
"reason": "expected ;",
"value:": string(remainder),
}).Warn("mapping format violation")
errs = append(errs, errors.New("mapping format violation, expected ;"))
break
} else {
remainder = remainder[1:]
}
remainder = remainder[1:]
// 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})
@@ -181,5 +190,4 @@ func ReadMappingValues(remainder []byte) (values *MappingValues, remainder_bytes
}
values = &map_values
return
}

View File

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

View File

@@ -26,7 +26,7 @@ Identical to KeysAndCert.
//
// https://geti2p.net/spec/common-structures#destination
type Destination struct {
*KeysAndCert
KeysAndCert
}
// 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.
// Returns a list of errors that occurred during parsing.
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{
keys_and_cert,
}
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
const (
KEYCERT_CRYPTO_ELG = iota
KEYCERT_CRYPTO_P256
KEYCERT_CRYPTO_P384
KEYCERT_CRYPTO_P521
KEYCERT_CRYPTO_X25519
)
const (
@@ -73,7 +77,11 @@ const (
// PublicKey sizes for Public Key Types
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
@@ -82,9 +90,9 @@ const (
KEYCERT_SPK_SIZE = 128
)
//type KeyCertificate []byte
// type KeyCertificate []byte
type KeyCertificate struct {
*Certificate
Certificate
spkType Integer
cpkType Integer
}
@@ -112,7 +120,7 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
return
}
data_len := len(data)
if data_len < KEYCERT_PUBKEY_SIZE {
if data_len < key_certificate.CryptoSize() {
log.WithFields(log.Fields{
"at": "(KeyCertificate) ConstructPublicKey",
"data_len": data_len,
@@ -127,6 +135,10 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
var elg_key crypto.ElgPublicKey
copy(elg_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE])
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
}
@@ -139,7 +151,7 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
return
}
data_len := len(data)
if data_len < KEYCERT_SPK_SIZE {
if data_len < key_certificate.SignatureSize() {
log.WithFields(log.Fields{
"at": "(KeyCertificate) ConstructSigningPublicKey",
"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])
signing_public_key = ec_key
case KEYCERT_SIGN_RSA2048:
//var rsa_key crypto.RSA2048PublicKey
//extra := KEYCERT_SIGN_RSA2048_SIZE - 128
//copy(rsa_key[:], data)
//copy(rsa_key[128:], key_certificate[4:4+extra])
//signing_public_key = rsa_key
// var rsa_key crypto.RSA2048PublicKey
// extra := KEYCERT_SIGN_RSA2048_SIZE - 128
// copy(rsa_key[:], data)
// copy(rsa_key[128:], key_certificate[4:4+extra])
// signing_public_key = rsa_key
case KEYCERT_SIGN_RSA3072:
case KEYCERT_SIGN_RSA4096:
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.
func (key_certificate KeyCertificate) SignatureSize() (size int) {
sizes := map[int]int{
KEYCERT_SIGN_DSA_SHA1: 40,
KEYCERT_SIGN_P256: 64,
KEYCERT_SIGN_P384: 96,
KEYCERT_SIGN_P521: 132,
KEYCERT_SIGN_RSA2048: 256,
KEYCERT_SIGN_RSA3072: 384,
KEYCERT_SIGN_RSA4096: 512,
KEYCERT_SIGN_ED25519: 64,
KEYCERT_SIGN_ED25519PH: 64,
KEYCERT_SIGN_DSA_SHA1: KEYCERT_SIGN_DSA_SHA1_SIZE,
KEYCERT_SIGN_P256: KEYCERT_SIGN_P256_SIZE,
KEYCERT_SIGN_P384: KEYCERT_SIGN_P384_SIZE,
KEYCERT_SIGN_P521: KEYCERT_SIGN_P521_SIZE,
KEYCERT_SIGN_RSA2048: KEYCERT_SIGN_RSA2048_SIZE,
KEYCERT_SIGN_RSA3072: KEYCERT_SIGN_RSA3072_SIZE,
KEYCERT_SIGN_RSA4096: KEYCERT_SIGN_RSA4096_SIZE,
KEYCERT_SIGN_ED25519: KEYCERT_SIGN_ED25519_SIZE,
KEYCERT_SIGN_ED25519PH: KEYCERT_SIGN_ED25519PH_SIZE,
}
key_type := key_certificate.SigningPublicKeyType()
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.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, remainder []byte, err error) {
var certificate *Certificate
var certificate Certificate
certificate, remainder, err = ReadCertificate(bytes)
//if err != nil {
// return nil, err
//}
if err != nil {
return
}
if len(bytes) < KEYCERT_MIN_SIZE {
err = errors.New("error parsing key certificate: not enough data")
remainder = bytes[KEYCERT_MIN_SIZE:]
}
switch len(bytes) {
case 4:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:]),
cpkType: Integer([]byte{0}),
}
case 5:
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]),
}
key_certificate = &KeyCertificate{
Certificate: certificate,
}
if len(bytes) >= 5 {
key_certificate.spkType = Integer(bytes[4:5])
}
if len(bytes) >= 7 {
key_certificate.cpkType = Integer(bytes[6:7])
}
remainder = bytes[7:]
//key_certificate.PublicKey = NewPublicKey(bytes)
return
}
// KeyCertificateFromCertificate returns a *KeyCertificate from a *Certificate.
func KeyCertificateFromCertificate(certificate *Certificate) *KeyCertificate {
func KeyCertificateFromCertificate(certificate Certificate) *KeyCertificate {
k, _, _ := NewKeyCertificate(certificate.RawBytes())
return k
}

View File

@@ -79,103 +79,41 @@ type KeysAndCert struct {
}
// 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()
}
// PublicKey returns the public key as a 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
}
// SigningPublicKey returns the signing public key.
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
}
// 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
}
//
// Read a KeysAndCert from a slice of bytes, retuning it and the remaining data as well as any errors
// 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.
// ReadKeysAndCert creates a new *KeysAndCert from []byte using ReadKeysAndCert.
// Returns a pointer to KeysAndCert unlike ReadKeysAndCert.
func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) {
/*data_len := len(data)
if data_len < KEYS_AND_CERT_MIN_SIZE {
data_len := len(data)
// 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{
"at": "ReadKeysAndCert",
"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")
return
}
keys_and_cert = KeysAndCert(data[:KEYS_AND_CERT_MIN_SIZE])
cert, _ := keys_and_cert.Certificate()
cert_len := cert.Length()
if cert_len == 0 {
remainder = data[KEYS_AND_CERT_MIN_SIZE:]
keys_and_cert.KeyCertificate, remainder, err = NewKeyCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
if err != nil {
return
}
if data_len < KEYS_AND_CERT_MIN_SIZE+cert_len {
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:]...)
//err = cert_len_err
} else {
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:KEYS_AND_CERT_MIN_SIZE+cert_len]...)
remainder = data[KEYS_AND_CERT_MIN_SIZE+cert_len:]
}*/
keys_and_cert_pointer, remainder, err := NewKeysAndCert(data)
keys_and_cert = *keys_and_cert_pointer
// TODO: this only supports one key type right now and it's the old key type, but the layout is the same.
// 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
// and KEYS_AND_CERT_SPK_SIZE constants in the future.
keys_and_cert.publicKey, err = keys_and_cert.KeyCertificate.ConstructPublicKey(data[:keys_and_cert.KeyCertificate.CryptoSize()])
if err != nil {
return
}
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])
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
}
// 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"
)
func TestCertificateWithMissingData(t *testing.T) {
/*func TestCertificateWithMissingData(t *testing.T) {
assert := assert.New(t)
cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01}
data := make([]byte, 128+256)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
cert := keys_and_cert.Certificate()
_, _, err := NewKeysAndCert(data)
if assert.NotNil(err) {
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) {
assert := assert.New(t)
@@ -31,9 +25,10 @@ func TestCertificateWithValidData(t *testing.T) {
data := make([]byte, 128+256)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
assert.Nil(err)
cert := keys_and_cert.Certificate()
assert.Nil(err)
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 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())
}
func TestReadKeysAndCertWithMissingData(t *testing.T) {
func TestNewKeysAndCertWithMissingData(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128)
@@ -177,10 +172,9 @@ func TestReadKeysAndCertWithMissingData(t *testing.T) {
if assert.NotNil(err) {
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)
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)
cert_data := make([]byte, 128+256)
@@ -202,7 +196,7 @@ func TestReadKeysAndCertWithValidDataWithCertificate(t *testing.T) {
assert.Nil(err)
}
func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
func TestNewKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)
@@ -212,7 +206,7 @@ func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
assert.Nil(err)
}
func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
func TestNewKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)
@@ -224,7 +218,7 @@ func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
assert.Nil(err)
}
func TestReadKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T) {
func TestNewKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T) {
assert := assert.New(t)
cert_data := make([]byte, 128+256)

View File

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

View File

@@ -14,9 +14,9 @@ import (
func buildDestination() *router_identity.RouterIdentity {
router_ident_data := make([]byte, 128+256)
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)
return ident
return &ident
}
func buildPublicKey() []byte {
@@ -77,7 +77,7 @@ func TestDestinationIsCorrect(t *testing.T) {
dest, err := lease_set.Destination()
assert.Nil(err)
dest_cert := dest.Certificate()
//assert.Nil(err)
// assert.Nil(err)
cert_type := dest_cert.Type()
assert.Nil(err)
assert.Equal(certificate.CERT_KEY, cert_type)

View File

@@ -3,6 +3,10 @@ package router_address
import (
"errors"
"fmt"
"net"
"strconv"
"strings"
. "github.com/go-i2p/go-i2p/lib/common/data"
log "github.com/sirupsen/logrus"
@@ -63,71 +67,215 @@ options :: Mapping
//
// https://geti2p.net/spec/common-structures#routeraddress
type RouterAddress struct {
cost *Integer
expiration *Date
Transport_Style *I2PString
options *Mapping
parserErr error
TransportCost *Integer
ExpirationDate *Date
TransportType I2PString
TransportOptions *Mapping
}
// 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.
func (router_address RouterAddress) Bytes() []byte {
bytes := make([]byte, 0)
bytes = append(bytes, router_address.cost.Bytes()...)
bytes = append(bytes, router_address.expiration.Bytes()...)
strData, err := router_address.Transport_Style.Data()
bytes = append(bytes, router_address.TransportCost.Bytes()...)
bytes = append(bytes, router_address.ExpirationDate.Bytes()...)
strData, err := router_address.TransportType.Data()
if err != nil {
log.WithFields(log.Fields{
"error": err,
}).Error("RouterAddress.Bytes: error getting Transport_Style bytes")
}).Error("RouterAddress.Bytes: error getting transport_style bytes")
} else {
bytes = append(bytes, strData...)
}
//bytes = append(bytes, router_address.options.Bytes()...)
bytes = append(bytes, router_address.TransportOptions.Data()...)
return bytes
}
// Cost returns the cost for this RouterAddress as a Go integer.
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.
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.
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.
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.
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
}
@@ -135,62 +283,40 @@ func (router_address RouterAddress) checkValid() (err error, exit bool) {
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []byte, err error) {
if data == nil || len(data) == 0 {
log.WithField("at", "(RouterAddress) ReadRouterAddress").Error("no data")
if len(data) == 0 {
log.WithField("at", "(RouterAddress) ReadRouterAddress").Error("error parsing RouterAddress: no data")
err = errors.New("error parsing RouterAddress: no data")
router_address.parserErr = err
return
}
cost, remainder, err := NewInteger([]byte{data[0]}, 1)
router_address.cost = cost
router_address.TransportCost, remainder, err = NewInteger(data, 1)
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing cost",
}).Warn("error parsing RouterAddress")
router_address.parserErr = err
}
expiration, remainder, err := NewDate(remainder)
router_address.expiration = expiration
router_address.ExpirationDate, remainder, err = NewDate(remainder)
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing expiration",
}).Error("error parsing RouterAddress")
router_address.parserErr = err
}
Transport_Style, remainder, err := NewI2PString(remainder)
router_address.Transport_Style = Transport_Style
router_address.TransportType, remainder, err = ReadI2PString(remainder)
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing Transport_Style",
"reason": "error parsing transport_style",
}).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 {
log.WithFields(log.Fields{
"at": "(RouterAddress) ReadNewRouterAddress",
"reason": "error parsing options",
}).Error("error parsing RouterAddress")
router_address.parserErr = err
}
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
"error": err,
}).Error("error parsing RozuterAddress")
}
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()
assert.Equal(exit, false, "checkValid indicates to stop parsing when some fields may be present")
}
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})
mapping, err := GoMapToMapping(map[string]string{"host": "127.0.0.1", "port": "4567"})
assert.Nil(err, "GoMapToMapping() returned error with valid data")
router_address.options = mapping
//router_address = append(router_address, mapping...)
router_address.TransportOptions = mapping
// router_address = append(router_address, mapping...)
err, exit := router_address.checkValid()
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
type RouterIdentity struct {
*KeysAndCert
KeysAndCert
}
// ReadRouterIdentity returns RouterIdentity from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
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{
keys_and_cert,
}
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 (
"errors"
"net"
"strconv"
"strings"
. "github.com/go-i2p/go-i2p/lib/common/data"
@@ -15,6 +15,11 @@ import (
const ROUTER_INFO_MIN_SIZE = 439
const (
MIN_GOOD_VERSION = 58
MAX_GOOD_VERSION = 99
)
/*
[RouterInfo]
Accurate for version 0.9.49
@@ -99,7 +104,7 @@ signature :: Signature
//
// https://geti2p.net/spec/common-structures#routerinfo
type RouterInfo struct {
router_identity *RouterIdentity
router_identity RouterIdentity
published *Date
size *Integer
addresses []*RouterAddress
@@ -108,13 +113,8 @@ type RouterInfo struct {
signature *Signature
}
var routerInfoTest net.Addr = &RouterInfo{}
// Bytes returns the RouterInfo as a []byte suitable for writing to a stream.
func (router_info RouterInfo) Bytes() ([]byte, error) {
var err error
var bytes []byte
func (router_info RouterInfo) Bytes() (bytes []byte, err error) {
bytes = append(bytes, router_info.router_identity.KeysAndCert.Bytes()...)
bytes = append(bytes, router_info.published.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_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)...)
return bytes, err
}
// Network Implements net.Addr, returns comma-separated list of transport types
func (router_info *RouterInfo) Network() string {
var str []string
for _, addr := range router_info.addresses {
t, err := addr.Transport_Style.Data()
if err != nil {
return strings.Join(str, ",")
}
str = append(str, t)
func (router_info RouterInfo) String() string {
str := "Certificate: " + string(router_info.router_identity.KeysAndCert.Bytes())
str += "Published: " + string(router_info.published.Bytes())
str += "Addresses:" + string(router_info.size.Bytes())
for index, router_address := range router_info.addresses {
str += "Address " + strconv.Itoa(index) + ": " + router_address.String()
}
return strings.Join(str, ",")
}
// String Implements net.Addr, returns router-info `Bytes` converted to a string
func (router_info *RouterInfo) String() string {
bytes, err := router_info.Bytes()
if err != nil {
// TODO handle this issue
return ""
}
return string(bytes)
str += "Peer Size: " + string(router_info.peer_size.Bytes())
str += "Options: " + string(router_info.options.Data())
str += "Signature: " + string([]byte(*router_info.signature))
return str
}
// RouterIdentity returns the router identity as *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.
func (router_info *RouterInfo) IdentHash() Hash {
ri := router_info.RouterIdentity()
h := HashData(ri.KeysAndCert.Certificate().Data())
return h
data, _ := router_info.RouterIdentity().KeyCertificate.Data()
return HashData(data)
}
// 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 the signature of this router info
//
// Signature returns the signature for this RouterInfo as an I2P Signature.
func (router_info RouterInfo) Signature() (signature Signature) {
return *router_info.signature
}
//
// Used during parsing to determine where in the RouterInfo the Mapping data begins.
//
/*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
}*/
// Network implements net.Addr
func (router_info RouterInfo) Network() string {
return "i2p"
}
// ReadRouterInfo returns RouterInfo from a []byte.
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error) {
identity, remainder, err := NewRouterIdentity(bytes)
info.router_identity = identity
info.router_identity, remainder, err = ReadRouterIdentity(bytes)
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo",
@@ -265,9 +202,9 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
return
}
date, remainder, err := NewDate(remainder)
info.published = date
info.published, remainder, err = NewDate(remainder)
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo",
@@ -277,36 +214,32 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
}
size, remainder, err := NewInteger(remainder, 1)
info.size = size
info.size, remainder, err = NewInteger(remainder, 1)
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo",
"data_len": len(remainder),
"required_len": size.Int(),
"reason": "not enough data",
}).Error("error parsing router info")
err = errors.New("error parsing router info: not enough data")
"required_len": info.size.Int(),
"reason": "read error",
}).Error("error parsing router info size")
}
addresses := make([]*RouterAddress, size.Int())
for i := 0; i < size.Int(); i++ {
address, remainder, err := NewRouterAddress(remainder)
for i := 0; i < info.size.Int(); i++ {
address, more, err := ReadRouterAddress(remainder)
remainder = more
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo",
"data_len": len(remainder),
//"required_len": ROUTER_ADDRESS_SIZE,
"reason": "not enough data",
}).Error("error parsing router info")
}).Error("error parsing router address")
err = errors.New("error parsing router info: not enough data")
}
addresses = append(addresses, address)
info.addresses = append(info.addresses, &address)
}
info.addresses = addresses
peer_size := Integer(remainder[:1])
info.peer_size = &peer_size
remainder = remainder[1:]
options, remainder, errs := NewMapping(remainder)
info.peer_size, remainder, err = NewInteger(remainder, 1)
var errs []error
info.options, remainder, errs = NewMapping(remainder)
if len(errs) != 0 {
log.WithFields(log.Fields{
"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)
}
info.options = options
info.signature, remainder, err = NewSignature(remainder)
if err != nil {
log.WithFields(log.Fields{
"at": "(RouterInfo) ReadRouterInfo",
@@ -333,10 +266,57 @@ func ReadRouterInfo(bytes []byte) (info RouterInfo, remainder []byte, err error)
return
}
// NewRouterInfo creates a new *RouterInfo from []byte using ReadRouterInfo.
// Returns a pointer to RouterInfo unlike ReadRouterInfo.
func NewRouterInfo(data []byte) (router_info *RouterInfo, remainder []byte, err error) {
routerInfo, remainder, err := ReadRouterInfo(data)
router_info = &routerInfo
return
func (router_info *RouterInfo) RouterCapabilities() string {
str, err := ToI2PString("caps")
if err != nil {
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) {
@@ -162,7 +161,6 @@ func TestRouterAddressesReturnsAddressesWithMultiple(t *testing.T) {
)
}
}
}
func TestPeerSizeIsZero(t *testing.T) {
@@ -200,7 +198,7 @@ func TestRouterIdentityIsCorrect(t *testing.T) {
router_info, _ := buildFullRouterInfo()
router_identity := router_info.RouterIdentity()
//assert.Nil(err)
// assert.Nil(err)
assert.Equal(
0,
bytes.Compare(