adding logging, headers, godoc to common data structures

This commit is contained in:
Hayden Parker
2016-02-16 01:04:40 -08:00
parent 270259b59d
commit fc98518cdb
7 changed files with 372 additions and 106 deletions

View File

@ -42,7 +42,7 @@ const (
) )
const ( const (
CERT_MIN_LENGTH = 3 CERT_MIN_SIZE = 3
) )
type Certificate []byte type Certificate []byte
@ -53,10 +53,10 @@ type Certificate []byte
// //
func (certificate Certificate) Type() (cert_type int, err error) { func (certificate Certificate) Type() (cert_type int, err error) {
cert_len := len(certificate) cert_len := len(certificate)
if cert_len < CERT_MIN_LENGTH { if cert_len < CERT_MIN_SIZE {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"certificate_bytes_length": cert_len, "certificate_bytes_length": cert_len,
"reason": "too short (len < CERT_MIN_LENGTH)", "reason": "too short (len < CERT_MIN_SIZE)",
}).Error("invalid certificate") }).Error("invalid certificate")
err = errors.New("error parsing certificate length: certificate is too short") err = errors.New("error parsing certificate length: certificate is too short")
return return
@ -76,8 +76,8 @@ func (certificate Certificate) Length() (length int, err error) {
if err != nil { if err != nil {
return return
} }
length = Integer(certificate[1:CERT_MIN_LENGTH]) length = Integer(certificate[1:CERT_MIN_SIZE])
inferred_len := length + CERT_MIN_LENGTH inferred_len := length + CERT_MIN_SIZE
if inferred_len > cert_len { if inferred_len > cert_len {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"certificate_bytes_length": cert_len, "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": case "error parsing certificate length: certificate is too short":
return return
case "certificate parsing warning: certificate data is shorter than specified by length": case "certificate parsing warning: certificate data is shorter than specified by length":
data = certificate[CERT_MIN_LENGTH:] data = certificate[CERT_MIN_SIZE:]
return return
case "certificate parsing warning: certificate contains data beyond length": 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 return
} }
} }
data = certificate[CERT_MIN_LENGTH:] data = certificate[CERT_MIN_SIZE:]
return return
} }
@ -127,8 +127,8 @@ func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, er
certificate = Certificate(data) certificate = Certificate(data)
length, err := certificate.Length() length, err := certificate.Length()
if err != nil && err.Error() == "certificate parsing warning: certificate contains data beyond length" { if err != nil && err.Error() == "certificate parsing warning: certificate contains data beyond length" {
certificate = Certificate(data[:length+CERT_MIN_LENGTH]) certificate = Certificate(data[:length+CERT_MIN_SIZE])
remainder = data[length+CERT_MIN_LENGTH:] remainder = data[length+CERT_MIN_SIZE:]
err = nil err = nil
} }
return return

View File

@ -8,6 +8,7 @@ Accurate for version 0.9.24
import ( import (
"errors" "errors"
log "github.com/Sirupsen/logrus"
"github.com/bounce-chat/go-i2p/lib/crypto" "github.com/bounce-chat/go-i2p/lib/crypto"
) )
@ -47,25 +48,37 @@ const (
KEYCERT_CRYPTO_ELG_SIZE = 256 KEYCERT_CRYPTO_ELG_SIZE = 256
) )
const (
KEYCERT_PUBKEY_SIZE = 256
KEYCERT_SPK_SIZE = 128
)
type KeyCertificate []byte type KeyCertificate []byte
// //
// The data contained in the Certificate. // The data contained in the Key Certificate.
// //
func (key_certificate KeyCertificate) Data() ([]byte, error) { func (key_certificate KeyCertificate) Data() ([]byte, error) {
return Certificate(key_certificate).Data() 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) { func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int, err error) {
data, err := key_certificate.Data() data, err := key_certificate.Data()
if err != nil { if err != nil {
return return
} }
if len(data) < 2 { data_len := len(data)
err = errors.New("") 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 return
} }
signing_pubkey_type = Integer(data[:2]) 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) { func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int, err error) {
data, err := key_certificate.Data() data, err := key_certificate.Data()
if err != nil { if err != nil {
return return
} }
if len(data) < 4 { data_len := len(data)
err = errors.New("") 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 return
} }
pubkey_type = Integer(data[2:4]) 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) { func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) {
key_type, err := key_certificate.PublicKeyType() key_type, err := key_certificate.PublicKeyType()
if err != nil { if err != nil {
return return
} }
if len(data) < 256 { data_len := len(data)
err = errors.New("") 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 return
} }
switch key_type { switch key_type {
case KEYCERT_CRYPTO_ELG: case KEYCERT_CRYPTO_ELG:
var elg_key crypto.ElgPublicKey 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 public_key = elg_key
} }
return 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) { func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey) {
signing_key_type, err := key_certificate.PublicKeyType() signing_key_type, err := key_certificate.PublicKeyType()
if err != nil { if err != nil {
return return
} }
if len(data) < 128 { data_len := len(data)
err = errors.New("") 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 return
} }
switch signing_key_type { switch signing_key_type {
case KEYCERT_SIGN_DSA_SHA1: case KEYCERT_SIGN_DSA_SHA1:
var dsa_key crypto.DSAPublicKey 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 signing_public_key = dsa_key
case KEYCERT_SIGN_P256: case KEYCERT_SIGN_P256:
var ec_key crypto.ECP256PublicKey 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 signing_public_key = ec_key
case KEYCERT_SIGN_P384: case KEYCERT_SIGN_P384:
var ec_key crypto.ECP384PublicKey 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 signing_public_key = ec_key
case KEYCERT_SIGN_P521: case KEYCERT_SIGN_P521:
var ec_key crypto.ECP521PublicKey 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[:], 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 signing_public_key = ec_key
case KEYCERT_SIGN_RSA2048: case KEYCERT_SIGN_RSA2048:
//var rsa_key crypto.RSA2048PublicKey //var rsa_key crypto.RSA2048PublicKey
@ -154,6 +188,10 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
return return
} }
//
// 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: 40,

View File

@ -1,15 +1,67 @@
package common 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 ( import (
"errors" "errors"
log "github.com/Sirupsen/logrus"
"github.com/bounce-chat/go-i2p/lib/crypto" "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 type KeysAndCert []byte
// //
// Return the ElgPublicKey for this KeysAndCert, reading from the Key Certificate // Return the PublicKey for this KeysAndCert, reading from the Key Certificate if it is present to
// if it is present first, then the first 256 bytes of the KeysAndCert. // determine correct lengths.
// //
func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) { func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) {
cert, err := keys_and_cert.Certificate() cert, err := keys_and_cert.Certificate()
@ -18,10 +70,10 @@ func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) {
return return
} }
if cert_len == 0 { 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. // PublicKey space as ElgPublicKey.
var elg_key crypto.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 key = elg_key
} else { } else {
// A Certificate is present in this KeysAndCert // 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 // This KeysAndCert contains a Key Certificate, construct
// a PublicKey from the data in the KeysAndCert and // a PublicKey from the data in the KeysAndCert and
// any additional data in the Certificate. // 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 { } 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 // PublicKey space as ElgPublicKey. No other Certificate
// types are currently in use // types are currently in use
var elg_key crypto.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 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 // Return the SigningPublicKey for this KeysAndCert, reading from the Key Certificate if it is present to
// if it is present first, then the SigningPublicKey space in the KeysAndCert. // determine correct lengths.
// //
func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) { func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) {
cert, err := keys_and_cert.Certificate() cert, err := keys_and_cert.Certificate()
@ -55,10 +109,10 @@ func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.S
return return
} }
if cert_len == 0 { 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. // SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey 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 signing_public_key = dsa_pk
} else { } else {
// A Certificate is present in this KeysAndCert // 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 // This KeysAndCert contains a Key Certificate, construct
// a SigningPublicKey from the data in the KeysAndCert and // a SigningPublicKey from the data in the KeysAndCert and
// any additional data in the Certificate. // 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 { } 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. // SigningPublicKey space as legacy SHA DSA1 SigningPublicKey.
// No other Certificate types are currently in use. // No other Certificate types are currently in use.
var dsa_pk crypto.DSAPublicKey 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 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 // Return the Certificate contained in the KeysAndCert and any errors encountered while parsing the
// while parsing the KeysAndCert or Certificate. // KeysAndCert or Certificate.
// //
func (keys_and_cert KeysAndCert) Certificate() (cert Certificate, err error) { func (keys_and_cert KeysAndCert) Certificate() (cert Certificate, err error) {
keys_cert_len := len(keys_and_cert) keys_cert_len := len(keys_and_cert)
if keys_cert_len < 387 { if keys_cert_len < KEYS_AND_CERT_MIN_SIZE {
err = errors.New("warning parsing KeysAndCert: data is smaller than minimum valid 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 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 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) { 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") err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
return return
} }
copy(data[:387], keys_and_cert) copy(data[:KEYS_AND_CERT_MIN_SIZE], keys_and_cert)
cert, _ := keys_and_cert.Certificate() cert, _ := keys_and_cert.Certificate()
n, err := cert.Length() n, err := cert.Length()
if err != nil { if err != nil {
remainder = data[387:] remainder = data[KEYS_AND_CERT_MIN_SIZE:]
return return
} }
keys_and_cert = append(keys_and_cert, data[387:n+3]...) keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:n+3]...)
remainder = data[387+n+3:] remainder = data[KEYS_AND_CERT_MIN_SIZE+n+3:]
return return
} }

View File

@ -1,35 +1,138 @@
package common 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 ( import (
"errors" "errors"
log "github.com/Sirupsen/logrus"
"github.com/bounce-chat/go-i2p/lib/crypto" "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 type LeaseSet []byte
//
// Read a Destination from the LeaseSet.
//
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)
destination = Destination(keys_and_cert) destination = Destination(keys_and_cert)
return 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) { func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error) {
_, remainder, err := ReadKeysAndCert(lease_set) _, 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") err = errors.New("error parsing public key: not enough data")
copy(public_key[:], remainder) copy(public_key[:], remainder)
return return
} }
copy(public_key[:], remainder[:256]) copy(public_key[:], remainder[:LEASE_SET_PUBKEY_SIZE])
return 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) { func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicKey, err error) {
destination, err := lease_set.Destination() destination, err := lease_set.Destination()
if err != nil { if err != nil {
return return
} }
offset := len(destination) + 256 offset := len(destination) + LEASE_SET_PUBKEY_SIZE
cert, err := destination.Certificate() cert, err := destination.Certificate()
if err != nil { if err != nil {
return return
@ -38,15 +141,21 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
if err != nil { if err != nil {
return return
} }
if len(lease_set) < offset+128 { lease_set_len := len(lease_set)
err = errors.New("") 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 return
} }
if cert_len == 0 { 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. // SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey 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 signing_public_key = dsa_pk
} else { } else {
// A Certificate is present in this LeaseSet's Destination // 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, // This LeaseSet's Destination's Certificate is a Key Certificate,
// create the signing publickey key using any data that might be // create the signing publickey key using any data that might be
// contained in the key certificate. // 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 { } 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. // SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey 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 signing_public_key = dsa_pk
} }
@ -68,34 +179,52 @@ func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicK
return return
} }
//
// Return the number of Leases specified by the LeaseCount value in this LeaseSet.
//
func (lease_set LeaseSet) LeaseCount() (count int, err error) { func (lease_set LeaseSet) LeaseCount() (count int, err error) {
_, remainder, err := ReadKeysAndCert(lease_set) _, remainder, err := ReadKeysAndCert(lease_set)
if err != nil { if err != nil {
return 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") err = errors.New("error parsing lease count: not enough data")
return return
} }
count = Integer([]byte{remainder[256+128]}) count = Integer([]byte{remainder[LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE]})
return 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) { func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
destination, err := lease_set.Destination() destination, err := lease_set.Destination()
if err != nil { if err != nil {
return return
} }
offset := len(destination) + 256 + 128 + 1 offset := len(destination) + LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1
count, err := lease_set.LeaseCount() count, err := lease_set.LeaseCount()
if err != nil { if err != nil {
return return
} }
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
start := offset + (i * 44) start := offset + (i * LEASE_SIZE)
end := start + 44 end := start + LEASE_SIZE
if len(lease_set) < end { lease_set_len := len(lease_set)
err = errors.New("") 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 return
} }
var lease Lease var lease Lease
@ -105,6 +234,10 @@ func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
return 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) { func (lease_set LeaseSet) Signature() (signature Signature, err error) {
destination, err := lease_set.Destination() destination, err := lease_set.Destination()
if err != nil { if err != nil {
@ -114,7 +247,11 @@ func (lease_set LeaseSet) Signature() (signature Signature, err error) {
if err != nil { if err != nil {
return 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() cert, err := destination.Certificate()
if err != nil { if err != nil {
@ -124,20 +261,29 @@ func (lease_set LeaseSet) Signature() (signature Signature, err error) {
if cert_type == CERT_KEY { if cert_type == CERT_KEY {
end = start + KeyCertificate(cert).SignatureSize() end = start + KeyCertificate(cert).SignatureSize()
} else { } else {
end = start + 40 end = start + LEASE_SET_SIG_SIZE
} }
if len(lease_set) < end { lease_set_len := len(lease_set)
err = errors.New("") 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 return
} }
copy(signature[:], lease_set[start:end]) copy(signature[:], lease_set[start:end])
return return
} }
//
//
//
func (lease_set LeaseSet) Verify() error { func (lease_set LeaseSet) Verify() error {
//data_end := len(destination) + //data_end := len(destination) +
// 256 + // LEASE_SET_PUBKEY_SIZE +
// 128 + // LEASE_SET_SPK_SIZE +
// 1 + // 1 +
// (44 * lease_set.LeaseCount()) // (44 * lease_set.LeaseCount())
//data := lease_set[:data_end] //data := lease_set[:data_end]
@ -151,6 +297,9 @@ func (lease_set LeaseSet) Verify() error {
return nil // verifier.Verify(data, lease_set.Signature()) 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) { func (lease_set LeaseSet) OldestExpiration() (date Date, err error) {
return return
} }

View File

@ -41,7 +41,7 @@ import (
) )
const ( const (
ROUTER_ADDRESS_MIN_LENGTH = 9 ROUTER_ADDRESS_MIN_SIZE = 9
) )
type RouterAddress []byte type RouterAddress []byte
@ -51,8 +51,7 @@ type RouterAddress []byte
// parsing the RouterAddress. // parsing the RouterAddress.
// //
func (router_address RouterAddress) Cost() (cost int, err error) { func (router_address RouterAddress) Cost() (cost int, err error) {
verr, exit := router_address.checkValid() err, exit := router_address.checkValid()
err = verr
if exit { if exit {
return return
} }
@ -65,12 +64,11 @@ func (router_address RouterAddress) Cost() (cost int, err error) {
// parsing the RouterAddress. // parsing the RouterAddress.
// //
func (router_address RouterAddress) Expiration() (date Date, err error) { func (router_address RouterAddress) Expiration() (date Date, err error) {
verr, exit := router_address.checkValid() err, exit := router_address.checkValid()
err = verr
if exit { if exit {
return return
} }
copy(date[:], router_address[1:ROUTER_ADDRESS_MIN_LENGTH]) copy(date[:], router_address[1:ROUTER_ADDRESS_MIN_SIZE])
return return
} }
@ -79,12 +77,11 @@ func (router_address RouterAddress) Expiration() (date Date, err error) {
// parsing the RouterAddress. // parsing the RouterAddress.
// //
func (router_address RouterAddress) TransportStyle() (str String, err error) { func (router_address RouterAddress) TransportStyle() (str String, err error) {
verr, exit := router_address.checkValid() err, exit := router_address.checkValid()
err = verr
if exit { if exit {
return return
} }
str, _, err = ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:]) str, _, err = ReadString(router_address[ROUTER_ADDRESS_MIN_SIZE:])
return return
} }
@ -93,12 +90,11 @@ func (router_address RouterAddress) TransportStyle() (str String, err error) {
// errors encountered parsing the RouterAddress. // errors encountered parsing the RouterAddress.
// //
func (router_address RouterAddress) Options() (mapping Mapping, err error) { func (router_address RouterAddress) Options() (mapping Mapping, err error) {
verr, exit := router_address.checkValid() err, exit := router_address.checkValid()
err = verr
if exit { if exit {
return return
} }
_, remainder, err := ReadString(router_address[ROUTER_ADDRESS_MIN_LENGTH:]) _, remainder, err := ReadString(router_address[ROUTER_ADDRESS_MIN_SIZE:])
if len(remainder) == 0 { if len(remainder) == 0 {
return return
} }
@ -118,9 +114,9 @@ func (router_address RouterAddress) checkValid() (err error, exit bool) {
}).Error("invalid router address") }).Error("invalid router address")
err = errors.New("error parsing RouterAddress: no data") err = errors.New("error parsing RouterAddress: no data")
exit = true exit = true
} else if addr_len < ROUTER_ADDRESS_MIN_LENGTH { } else if addr_len < ROUTER_ADDRESS_MIN_SIZE {
log.WithFields(log.Fields{ 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") }).Warn("router address format warning")
err = errors.New("warning parsing RouterAddress: data too small") 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 { if err != nil {
return return
} }
router_address = append(router_address, data[:ROUTER_ADDRESS_MIN_LENGTH]...) router_address = append(router_address, data[:ROUTER_ADDRESS_MIN_SIZE]...)
str, remainder, err := ReadString(data[ROUTER_ADDRESS_MIN_LENGTH:]) str, remainder, err := ReadString(data[ROUTER_ADDRESS_MIN_SIZE:])
if err != nil { if err != nil {
return return
} }
@ -150,6 +146,6 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
mapping = remainder[:map_size+2] mapping = remainder[:map_size+2]
router_address = append(router_address, mapping...) 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 return
} }

View File

@ -4,20 +4,35 @@ import (
"testing" "testing"
) )
func TestRouterIdentityReadsRouterIdentity(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}
func TestRouterIdentityWithZeroLenSlice(t *testing.T) { str, _ := ToI2PString("foo")
} mapping, _ := GoMapToMapping(map[string]string{"host": "127.0.0.1", "port": "4567"})
router_address_bytes = append(router_address_bytes, []byte(str)...)
func TestRouterIdentityWithInvalidData(t *testing.T) { router_address_bytes = append(router_address_bytes, mapping...)
//RouterAddress(router_address_bytes)
return nil
} }
func TestPublishedReturnsCorrectDate(t *testing.T) { 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) {
} }

View File

@ -12,7 +12,7 @@ import (
) )
const ( const (
STRING_MAX_LENGTH = 256 STRING_MAX_SIZE = 256
) )
type String []byte type String []byte
@ -79,10 +79,10 @@ func (str String) Data() (data string, err error) {
// //
func ToI2PString(data string) (str String, err error) { func ToI2PString(data string) (str String, err error) {
data_len := len(data) data_len := len(data)
if data_len >= STRING_MAX_LENGTH { if data_len >= STRING_MAX_SIZE {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"string_len": data_len, "string_len": data_len,
"max_len": STRING_MAX_LENGTH, "max_len": STRING_MAX_SIZE,
"reason": "too much data", "reason": "too much data",
}).Error("cannot create I2P string") }).Error("cannot create I2P string")
err = errors.New("cannot store that much data in I2P string") err = errors.New("cannot store that much data in I2P string")