mirror of
https://github.com/go-i2p/go-i2p.git
synced 2025-07-05 14:13:30 -04:00
adding logging, headers, godoc to common data structures
This commit is contained in:
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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) {
|
||||
|
||||
}
|
||||
|
@ -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")
|
||||
|
Reference in New Issue
Block a user