diff --git a/lib/common/certificate.go b/lib/common/certificate.go index 2e534e7..e3aab7b 100644 --- a/lib/common/certificate.go +++ b/lib/common/certificate.go @@ -42,7 +42,7 @@ const ( ) const ( - CERT_MIN_LENGTH = 3 + CERT_MIN_SIZE = 3 ) type Certificate []byte @@ -53,10 +53,10 @@ type Certificate []byte // func (certificate Certificate) Type() (cert_type int, err error) { cert_len := len(certificate) - if cert_len < CERT_MIN_LENGTH { + if cert_len < CERT_MIN_SIZE { log.WithFields(log.Fields{ "certificate_bytes_length": cert_len, - "reason": "too short (len < CERT_MIN_LENGTH)", + "reason": "too short (len < CERT_MIN_SIZE)", }).Error("invalid certificate") err = errors.New("error parsing certificate length: certificate is too short") return @@ -76,8 +76,8 @@ func (certificate Certificate) Length() (length int, err error) { if err != nil { return } - length = Integer(certificate[1:CERT_MIN_LENGTH]) - inferred_len := length + CERT_MIN_LENGTH + length = Integer(certificate[1:CERT_MIN_SIZE]) + inferred_len := length + CERT_MIN_SIZE if inferred_len > cert_len { log.WithFields(log.Fields{ "certificate_bytes_length": cert_len, @@ -108,14 +108,14 @@ func (certificate Certificate) Data() (data []byte, err error) { case "error parsing certificate length: certificate is too short": return case "certificate parsing warning: certificate data is shorter than specified by length": - data = certificate[CERT_MIN_LENGTH:] + data = certificate[CERT_MIN_SIZE:] return case "certificate parsing warning: certificate contains data beyond length": - data = certificate[CERT_MIN_LENGTH : length+CERT_MIN_LENGTH] + data = certificate[CERT_MIN_SIZE : length+CERT_MIN_SIZE] return } } - data = certificate[CERT_MIN_LENGTH:] + data = certificate[CERT_MIN_SIZE:] return } @@ -127,8 +127,8 @@ func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, er certificate = Certificate(data) length, err := certificate.Length() if err != nil && err.Error() == "certificate parsing warning: certificate contains data beyond length" { - certificate = Certificate(data[:length+CERT_MIN_LENGTH]) - remainder = data[length+CERT_MIN_LENGTH:] + certificate = Certificate(data[:length+CERT_MIN_SIZE]) + remainder = data[length+CERT_MIN_SIZE:] err = nil } return diff --git a/lib/common/key_certificate.go b/lib/common/key_certificate.go index aceb874..0050aa1 100644 --- a/lib/common/key_certificate.go +++ b/lib/common/key_certificate.go @@ -8,6 +8,7 @@ Accurate for version 0.9.24 import ( "errors" + log "github.com/Sirupsen/logrus" "github.com/bounce-chat/go-i2p/lib/crypto" ) @@ -47,25 +48,37 @@ const ( KEYCERT_CRYPTO_ELG_SIZE = 256 ) +const ( + KEYCERT_PUBKEY_SIZE = 256 + KEYCERT_SPK_SIZE = 128 +) + type KeyCertificate []byte // -// The data contained in the Certificate. +// The data contained in the Key Certificate. // func (key_certificate KeyCertificate) Data() ([]byte, error) { return Certificate(key_certificate).Data() } // -// +// The SigningPublicKey type this Key Certificate describes and any errors encountered +// parsing the KeyCertificate. // func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int, err error) { data, err := key_certificate.Data() if err != nil { return } - if len(data) < 2 { - err = errors.New("") + data_len := len(data) + if data_len < 2 { + log.WithFields(log.Fields{ + "data_len": data_len, + "required_len": 2, + "reason": "not enough data", + }).Error("error parsing key certificate") + err = errors.New("error parsing key certificate: not enough data") return } signing_pubkey_type = Integer(data[:2]) @@ -73,15 +86,22 @@ func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_typ } // -// +// The PublicKey type this Key Certificate describes and any errors encountered parsing +// this KeyCertificate. // func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int, err error) { data, err := key_certificate.Data() if err != nil { return } - if len(data) < 4 { - err = errors.New("") + data_len := len(data) + if data_len < 4 { + log.WithFields(log.Fields{ + "data_len": data_len, + "required_len": 4, + "reason": "not enough data", + }).Error("error parsing key certificate") + err = errors.New("error parsing key certificate: not enough data") return } pubkey_type = Integer(data[2:4]) @@ -89,56 +109,70 @@ func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int, err erro } // -// +// Given some bytes, build a PublicKey using any excess data that may be stored in the KeyCertificate and return +// it along with any errors encountered constructing the PublicKey. // func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) { key_type, err := key_certificate.PublicKeyType() if err != nil { return } - if len(data) < 256 { - err = errors.New("") + data_len := len(data) + if data_len < KEYCERT_PUBKEY_SIZE { + log.WithFields(log.Fields{ + "data_len": data_len, + "required_len": KEYCERT_PUBKEY_SIZE, + "reason": "not enough data", + }).Error("error constructing public key") + err = errors.New("error constucting public key: not enough data") return } switch key_type { case KEYCERT_CRYPTO_ELG: var elg_key crypto.ElgPublicKey - copy(elg_key[:], data[256-KEYCERT_CRYPTO_ELG_SIZE:256]) + copy(elg_key[:], data[KEYCERT_PUBKEY_SIZE-KEYCERT_CRYPTO_ELG_SIZE:KEYCERT_PUBKEY_SIZE]) public_key = elg_key } return } // -// +// Given some bytes, build a SigningPublicKey using any excess data that may be stored in the KeyCertificate and return +// it along with any errors encountered constructing the SigningPublicKey. // func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey) { signing_key_type, err := key_certificate.PublicKeyType() if err != nil { return } - if len(data) < 128 { - err = errors.New("") + data_len := len(data) + if data_len < KEYCERT_SPK_SIZE { + log.WithFields(log.Fields{ + "data_len": data_len, + "required_len": KEYCERT_SPK_SIZE, + "reason": "not enough data", + }).Error("error constructing signing public key") + err = errors.New("error constucting signing public key: not enough data") return } switch signing_key_type { case KEYCERT_SIGN_DSA_SHA1: var dsa_key crypto.DSAPublicKey - copy(dsa_key[:], data[128-KEYCERT_SIGN_DSA_SHA1_SIZE:128]) + copy(dsa_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_DSA_SHA1_SIZE:KEYCERT_SPK_SIZE]) signing_public_key = dsa_key case KEYCERT_SIGN_P256: var ec_key crypto.ECP256PublicKey - copy(ec_key[:], data[128-KEYCERT_SIGN_P256_SIZE:128]) + copy(ec_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P256_SIZE:KEYCERT_SPK_SIZE]) signing_public_key = ec_key case KEYCERT_SIGN_P384: var ec_key crypto.ECP384PublicKey - copy(ec_key[:], data[128-KEYCERT_SIGN_P384_SIZE:128]) + copy(ec_key[:], data[KEYCERT_SPK_SIZE-KEYCERT_SIGN_P384_SIZE:KEYCERT_SPK_SIZE]) signing_public_key = ec_key case KEYCERT_SIGN_P521: var ec_key crypto.ECP521PublicKey - extra := KEYCERT_SIGN_P521_SIZE - 128 + extra := KEYCERT_SIGN_P521_SIZE - KEYCERT_SPK_SIZE copy(ec_key[:], data) - copy(ec_key[128:], key_certificate[4:4+extra]) + copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate[4:4+extra]) signing_public_key = ec_key case KEYCERT_SIGN_RSA2048: //var rsa_key crypto.RSA2048PublicKey @@ -154,6 +188,10 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si return } +// +// 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, diff --git a/lib/common/keys_and_cert.go b/lib/common/keys_and_cert.go index 8a51562..eb9ca9a 100644 --- a/lib/common/keys_and_cert.go +++ b/lib/common/keys_and_cert.go @@ -1,15 +1,67 @@ package common +/* +I2P KeysAndCert +https://geti2p.net/en/docs/spec/common-structures#struct_KeysAndCert +Accurate for version 0.9.24 + ++----+----+----+----+----+----+----+----+ +| public_key | ++ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| padding (optional) | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| signing_key | ++ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| certificate | ++----+----+----+-// + +public_key :: PublicKey (partial or full) + length -> 256 bytes or as specified in key certificate + +padding :: random data + length -> 0 bytes or as specified in key certificate + padding length + signing_key length == KEYS_AND_CERT_SPK_SIZE bytes + +signing__key :: SigningPublicKey (partial or full) + length -> 128 bytes or as specified in key certificate + padding length + signing_key length == KEYS_AND_CERT_SPK_SIZE bytes + +certificate :: Certificate + length -> >= 3 bytes + +total length: 387+ bytes +*/ + import ( "errors" + log "github.com/Sirupsen/logrus" "github.com/bounce-chat/go-i2p/lib/crypto" ) +const ( + KEYS_AND_CERT_PUBKEY_SIZE = 256 + KEYS_AND_CERT_SPK_SIZE = 128 + KEYS_AND_CERT_MIN_SIZE = 387 +) + type KeysAndCert []byte // -// Return the ElgPublicKey for this KeysAndCert, reading from the Key Certificate -// if it is present first, then the first 256 bytes of the KeysAndCert. +// Return the PublicKey for this KeysAndCert, reading from the Key Certificate if it is present to +// determine correct lengths. // func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) { cert, err := keys_and_cert.Certificate() @@ -18,10 +70,10 @@ func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) { return } if cert_len == 0 { - // No Certificate is present, return the 256 byte + // 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[:256], elg_key[:]) + copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:]) key = elg_key } else { // A Certificate is present in this KeysAndCert @@ -30,13 +82,15 @@ func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) { // This KeysAndCert contains a Key Certificate, construct // a PublicKey from the data in the KeysAndCert and // any additional data in the Certificate. - key, err = KeyCertificate(cert).ConstructPublicKey(keys_and_cert[:256]) + key, err = KeyCertificate(cert).ConstructPublicKey( + keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], + ) } else { - // Key Certificate is not present, return the 256 byte + // 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[:256], elg_key[:]) + copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:]) key = elg_key } @@ -45,8 +99,8 @@ func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) { } // -// Return the SigningPublicKey for this KeysAndCert, reading from the Key Certificate -// if it is present first, then the SigningPublicKey space in the KeysAndCert. +// Return the SigningPublicKey for this KeysAndCert, reading from the Key Certificate if it is present to +// determine correct lengths. // func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) { cert, err := keys_and_cert.Certificate() @@ -55,10 +109,10 @@ func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.S return } if cert_len == 0 { - // No Certificate is present, return the 128 byte + // 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[256:256+128]) + 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 @@ -67,13 +121,15 @@ func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.S // 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 = KeyCertificate(cert).ConstructSigningPublicKey(keys_and_cert[256 : 256+128]) + signing_public_key = KeyCertificate(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 128 byte + // 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[256:256+128]) + 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 } @@ -82,35 +138,47 @@ func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.S } // -// Return the Certificate cointained in the KeysAndCert and errors encountered -// while parsing the KeysAndCert or Certificate. +// Return the Certificate contained in the KeysAndCert and any errors encountered while parsing the +// KeysAndCert or Certificate. // func (keys_and_cert KeysAndCert) Certificate() (cert Certificate, err error) { keys_cert_len := len(keys_and_cert) - if keys_cert_len < 387 { - err = errors.New("warning parsing KeysAndCert: data is smaller than minimum valid size") + if keys_cert_len < KEYS_AND_CERT_MIN_SIZE { + log.WithFields(log.Fields{ + "data_len": keys_cert_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, _, err = ReadCertificate(keys_and_cert[256+128:]) + cert, _, err = ReadCertificate(keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE:]) return } // -// +// Read a KeysAndCert from a slice of bytes, retuning it and the remaining data as well as any errors +// encoutered parsing the KeysAndCert. // func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) { - if len(data) < 387 { + data_len := len(data) + if data_len < KEYS_AND_CERT_MIN_SIZE { + log.WithFields(log.Fields{ + "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 } - copy(data[:387], keys_and_cert) + copy(data[:KEYS_AND_CERT_MIN_SIZE], keys_and_cert) cert, _ := keys_and_cert.Certificate() n, err := cert.Length() if err != nil { - remainder = data[387:] + remainder = data[KEYS_AND_CERT_MIN_SIZE:] return } - keys_and_cert = append(keys_and_cert, data[387:n+3]...) - remainder = data[387+n+3:] + keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:n+3]...) + remainder = data[KEYS_AND_CERT_MIN_SIZE+n+3:] return } diff --git a/lib/common/lease_set.go b/lib/common/lease_set.go index 984dbbf..0873b59 100644 --- a/lib/common/lease_set.go +++ b/lib/common/lease_set.go @@ -1,35 +1,138 @@ package common +/* +I2P LeaseSet +https://geti2p.net/en/docs/spec/common-structures#struct_LeaseSet +Accurate for version 0.9.24 + ++----+----+----+----+----+----+----+----+ +| destination | ++ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| encryption_key | ++ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| signing_key | ++ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +|num | Lease 0 | ++----+ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| Lease 1 | ++ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| Lease ($num-1) | ++ + +| | +~ ~ +~ ~ +| | ++----+----+----+----+----+----+----+----+ +| signature | ++ + +| | ++ + +| | ++ + +| | ++ + +| | ++----+----+----+----+----+----+----+----+ + +destination :: Destination + length -> >= 387 bytes + +encryption_key :: PublicKey + length -> 256 bytes + +signing_key :: SigningPublicKey + length -> 128 bytes or as specified in destination's key certificate + +num :: Integer + length -> 1 byte + Number of leases to follow + value: 0 <= num <= 16 + +leases :: [Lease] + length -> $num*44 bytes + +signature :: Signature + length -> 40 bytes or as specified in destination's key certificate +*/ + import ( "errors" + log "github.com/Sirupsen/logrus" "github.com/bounce-chat/go-i2p/lib/crypto" ) +const ( + LEASE_SET_PUBKEY_SIZE = 256 + LEASE_SET_SPK_SIZE = 128 + LEASE_SET_SIG_SIZE = 40 +) + type LeaseSet []byte +// +// Read a Destination from the LeaseSet. +// func (lease_set LeaseSet) Destination() (destination Destination, err error) { keys_and_cert, _, err := ReadKeysAndCert(lease_set) destination = Destination(keys_and_cert) return } +// +// Return the PublicKey in this LeaseSet and any errors ancountered parsing the LeaseSet. +// func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error) { _, remainder, err := ReadKeysAndCert(lease_set) - if len(remainder) < 256 { + remainder_len := len(remainder) + if remainder_len < LEASE_SET_PUBKEY_SIZE { + log.WithFields(log.Fields{ + "data_len": remainder_len, + "required_len": LEASE_SET_PUBKEY_SIZE, + "reason": "not enough data", + }).Error("error parsing public key") err = errors.New("error parsing public key: not enough data") copy(public_key[:], remainder) return } - copy(public_key[:], remainder[:256]) + copy(public_key[:], remainder[:LEASE_SET_PUBKEY_SIZE]) return } +// +// Return the SigningPublicKey, as specified in the LeaseSet's Destination's Key Certificate if +// present, or a legacy DSA key. +// func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicKey, err error) { destination, err := lease_set.Destination() if err != nil { return } - offset := len(destination) + 256 + offset := len(destination) + LEASE_SET_PUBKEY_SIZE cert, err := destination.Certificate() if err != nil { return @@ -38,15 +141,21 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK if err != nil { return } - if len(lease_set) < offset+128 { - err = errors.New("") + lease_set_len := len(lease_set) + if lease_set_len < offset+LEASE_SET_SPK_SIZE { + log.WithFields(log.Fields{ + "data_len": lease_set_len, + "required_len": offset + LEASE_SET_SPK_SIZE, + "reason": "not enough data", + }).Error("error parsing signing public key") + err = errors.New("error parsing signing public key: not enough data") return } if cert_len == 0 { - // No Certificate is present, return the 128 byte + // No Certificate is present, return the LEASE_SET_SPK_SIZE byte // SigningPublicKey space as legacy DSA SHA1 SigningPublicKey. var dsa_pk crypto.DSAPublicKey - copy(dsa_pk[:], lease_set[offset:offset+128]) + copy(dsa_pk[:], lease_set[offset:offset+LEASE_SET_SPK_SIZE]) signing_public_key = dsa_pk } else { // A Certificate is present in this LeaseSet's Destination @@ -55,12 +164,14 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK // This LeaseSet's Destination's Certificate is a Key Certificate, // create the signing publickey key using any data that might be // contained in the key certificate. - signing_public_key = KeyCertificate(cert).ConstructSigningPublicKey(lease_set[offset : offset+128]) + signing_public_key = KeyCertificate(cert).ConstructSigningPublicKey( + lease_set[offset : offset+LEASE_SET_SPK_SIZE], + ) } else { - // No Certificate is present, return the 128 byte + // No Certificate is present, return the LEASE_SET_SPK_SIZE byte // SigningPublicKey space as legacy DSA SHA1 SigningPublicKey. var dsa_pk crypto.DSAPublicKey - copy(dsa_pk[:], lease_set[offset:offset+128]) + copy(dsa_pk[:], lease_set[offset:offset+LEASE_SET_SPK_SIZE]) signing_public_key = dsa_pk } @@ -68,34 +179,52 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK return } +// +// Return the number of Leases specified by the LeaseCount value in this LeaseSet. +// func (lease_set LeaseSet) LeaseCount() (count int, err error) { _, remainder, err := ReadKeysAndCert(lease_set) if err != nil { return } - if len(remainder) < 256+128+1 { + remainder_len := len(remainder) + if remainder_len < LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE+1 { + log.WithFields(log.Fields{ + "data_len": remainder_len, + "required_len": LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1, + "reason": "not enough data", + }).Error("error parsing lease count") err = errors.New("error parsing lease count: not enough data") return } - count = Integer([]byte{remainder[256+128]}) + count = Integer([]byte{remainder[LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE]}) return } +// +// Read the Leases in this LeaseSet, returning a partial set if there is insufficient data. +// func (lease_set LeaseSet) Leases() (leases []Lease, err error) { destination, err := lease_set.Destination() if err != nil { return } - offset := len(destination) + 256 + 128 + 1 + offset := len(destination) + LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1 count, err := lease_set.LeaseCount() if err != nil { return } for i := 0; i < count; i++ { - start := offset + (i * 44) - end := start + 44 - if len(lease_set) < end { - err = errors.New("") + start := offset + (i * LEASE_SIZE) + end := start + LEASE_SIZE + lease_set_len := len(lease_set) + if lease_set_len < end { + log.WithFields(log.Fields{ + "data_len": lease_set_len, + "required_len": end, + "reason": "some leases missing", + }).Error("error parsnig lease set") + err = errors.New("error parsing lease set: some leases missing") return } var lease Lease @@ -105,6 +234,10 @@ func (lease_set LeaseSet) Leases() (leases []Lease, err error) { return } +// +// Return the Signature data for the LeaseSet, as specified in the Destination's +// Key Certificate if present or the 40 bytes following the Leases. +// func (lease_set LeaseSet) Signature() (signature Signature, err error) { destination, err := lease_set.Destination() if err != nil { @@ -114,7 +247,11 @@ func (lease_set LeaseSet) Signature() (signature Signature, err error) { if err != nil { return } - start := len(destination) + 256 + 128 + 1 + (44 * lease_count) + start := len(destination) + + LEASE_SET_PUBKEY_SIZE + + LEASE_SET_SPK_SIZE + + 1 + + (LEASE_SIZE * lease_count) cert, err := destination.Certificate() if err != nil { @@ -124,20 +261,29 @@ func (lease_set LeaseSet) Signature() (signature Signature, err error) { if cert_type == CERT_KEY { end = start + KeyCertificate(cert).SignatureSize() } else { - end = start + 40 + end = start + LEASE_SET_SIG_SIZE } - if len(lease_set) < end { - err = errors.New("") + lease_set_len := len(lease_set) + if lease_set_len < end { + log.WithFields(log.Fields{ + "data_len": lease_set_len, + "required_len": end, + "reason": "not enough data", + }).Error("error parsing signatre") + err = errors.New("error parsing signature: not enough data") return } copy(signature[:], lease_set[start:end]) return } +// +// +// func (lease_set LeaseSet) Verify() error { //data_end := len(destination) + - // 256 + - // 128 + + // LEASE_SET_PUBKEY_SIZE + + // LEASE_SET_SPK_SIZE + // 1 + // (44 * lease_set.LeaseCount()) //data := lease_set[:data_end] @@ -151,6 +297,9 @@ func (lease_set LeaseSet) Verify() error { return nil // verifier.Verify(data, lease_set.Signature()) } +// +// Return the oldest date from all the Leases in the LeaseSet. +// func (lease_set LeaseSet) OldestExpiration() (date Date, err error) { return } diff --git a/lib/common/router_address.go b/lib/common/router_address.go index bf0b4c5..83aa0bb 100644 --- a/lib/common/router_address.go +++ b/lib/common/router_address.go @@ -41,7 +41,7 @@ import ( ) const ( - ROUTER_ADDRESS_MIN_LENGTH = 9 + ROUTER_ADDRESS_MIN_SIZE = 9 ) type RouterAddress []byte @@ -51,8 +51,7 @@ type RouterAddress []byte // parsing the RouterAddress. // func (router_address RouterAddress) Cost() (cost int, err error) { - verr, exit := router_address.checkValid() - err = verr + err, exit := router_address.checkValid() if exit { return } @@ -65,12 +64,11 @@ func (router_address RouterAddress) Cost() (cost int, err error) { // parsing the RouterAddress. // func (router_address RouterAddress) Expiration() (date Date, err error) { - verr, exit := router_address.checkValid() - err = verr + err, exit := router_address.checkValid() if exit { return } - copy(date[:], router_address[1:ROUTER_ADDRESS_MIN_LENGTH]) + copy(date[:], router_address[1:ROUTER_ADDRESS_MIN_SIZE]) return } @@ -79,12 +77,11 @@ func (router_address RouterAddress) Expiration() (date Date, err error) { // parsing the RouterAddress. // func (router_address RouterAddress) TransportStyle() (str String, err error) { - verr, exit := router_address.checkValid() - err = verr + err, exit := router_address.checkValid() if exit { return } - str, _, err = ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:]) + str, _, err = ReadString(router_address[ROUTER_ADDRESS_MIN_SIZE:]) return } @@ -93,12 +90,11 @@ func (router_address RouterAddress) TransportStyle() (str String, err error) { // errors encountered parsing the RouterAddress. // func (router_address RouterAddress) Options() (mapping Mapping, err error) { - verr, exit := router_address.checkValid() - err = verr + err, exit := router_address.checkValid() if exit { return } - _, remainder, err := ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:]) + _, remainder, err := ReadString(router_address[ROUTER_ADDRESS_MIN_SIZE:]) if len(remainder) == 0 { return } @@ -118,9 +114,9 @@ func (router_address RouterAddress) checkValid() (err error, exit bool) { }).Error("invalid router address") err = errors.New("error parsing RouterAddress: no data") exit = true - } else if addr_len < ROUTER_ADDRESS_MIN_LENGTH { + } else if addr_len < ROUTER_ADDRESS_MIN_SIZE { log.WithFields(log.Fields{ - "reason": "data too small (len < ROUTER_ADDRESS_MIN_LENGTH)", + "reason": "data too small (len < ROUTER_ADDRESS_MIN_SIZE)", }).Warn("router address format warning") err = errors.New("warning parsing RouterAddress: data too small") } @@ -137,8 +133,8 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b if err != nil { return } - router_address = append(router_address, data[:ROUTER_ADDRESS_MIN_LENGTH]...) - str, remainder, err := ReadString(data[ROUTER_ADDRESS_MIN_LENGTH:]) + router_address = append(router_address, data[:ROUTER_ADDRESS_MIN_SIZE]...) + str, remainder, err := ReadString(data[ROUTER_ADDRESS_MIN_SIZE:]) if err != nil { return } @@ -150,6 +146,6 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b mapping = remainder[:map_size+2] router_address = append(router_address, mapping...) } - remainder = data[ROUTER_ADDRESS_MIN_LENGTH+len(str)+len(mapping):] + remainder = data[ROUTER_ADDRESS_MIN_SIZE+len(str)+len(mapping):] return } diff --git a/lib/common/router_info_test.go b/lib/common/router_info_test.go index 69d46ba..11379ec 100644 --- a/lib/common/router_info_test.go +++ b/lib/common/router_info_test.go @@ -4,20 +4,35 @@ import ( "testing" ) -func TestRouterIdentityReadsRouterIdentity(t *testing.T) { -} - -func TestRouterIdentityWithZeroLenSlice(t *testing.T) { -} - -func TestRouterIdentityWithInvalidData(t *testing.T) { +func buildFullRouterInfo() RouterInfo { + // starts with a keys_and_cert + router_address_bytes := []byte{0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + str, _ := ToI2PString("foo") + mapping, _ := GoMapToMapping(map[string]string{"host": "127.0.0.1", "port": "4567"}) + router_address_bytes = append(router_address_bytes, []byte(str)...) + router_address_bytes = append(router_address_bytes, mapping...) + //RouterAddress(router_address_bytes) + return nil } func TestPublishedReturnsCorrectDate(t *testing.T) { } -func TestPublishedWithZeroLenSlice(t *testing.T) { +func TestRouterAddressCountReturnsCorrectCount(t *testing.T) { } -func TestPublishedWithInvalidData(t *testing.T) { +func TestRouterAdrressesReturnsAddresses(t *testing.T) { + +} + +func TestRouterAdrressesReturnsPartialListWithMissing(t *testing.T) { + +} + +func TestPeerSizeIsZero(t *testing.T) { + +} + +func TestSignatureIsCorrectSize(t *testing.T) { + } diff --git a/lib/common/string.go b/lib/common/string.go index 4b63491..9d70be3 100644 --- a/lib/common/string.go +++ b/lib/common/string.go @@ -12,7 +12,7 @@ import ( ) const ( - STRING_MAX_LENGTH = 256 + STRING_MAX_SIZE = 256 ) type String []byte @@ -79,10 +79,10 @@ func (str String) Data() (data string, err error) { // func ToI2PString(data string) (str String, err error) { data_len := len(data) - if data_len >= STRING_MAX_LENGTH { + if data_len >= STRING_MAX_SIZE { log.WithFields(log.Fields{ "string_len": data_len, - "max_len": STRING_MAX_LENGTH, + "max_len": STRING_MAX_SIZE, "reason": "too much data", }).Error("cannot create I2P string") err = errors.New("cannot store that much data in I2P string")