Added constructors and readers

-NewLeaseSet()
-NewLeaseSetFromBytes()
-ReadLease()
-NewLeaseFromBytes()
This commit is contained in:
Haris Khan
2024-11-17 14:00:41 -05:00
parent ee56e0f40f
commit 59c53bc5c1
2 changed files with 230 additions and 6 deletions

View File

@ -1,7 +1,14 @@
// Package lease implements the I2P lease common data structure
package lease
import . "github.com/go-i2p/go-i2p/lib/common/data"
import (
"encoding/binary"
"errors"
. "github.com/go-i2p/go-i2p/lib/common/data"
"github.com/go-i2p/go-i2p/lib/util/logger"
"github.com/sirupsen/logrus"
"time"
)
// Sizes in bytes of various components of a Lease
const (
@ -47,6 +54,9 @@ end_date :: Date
// Lease is the represenation of an I2P Lease.
//
// https://geti2p.net/spec/common-structures#lease
var log = logger.GetGoI2PLogger()
type Lease [LEASE_SIZE]byte
// TunnelGateway returns the tunnel gateway as a Hash.
@ -73,13 +83,76 @@ func (lease Lease) Date() (date Date) {
// The remaining bytes after the specified length are also returned.
// Returns a list of errors that occurred during parsing.
func ReadLease(data []byte) (lease Lease, remainder []byte, err error) {
// TODO: stub
log.WithField("input_length", len(data)).Debug("Reading Lease from bytes")
if len(data) < LEASE_SIZE {
err = errors.New("error parsing lease: not enough data")
log.WithFields(logrus.Fields{
"data_length": len(data),
"required_length": LEASE_SIZE,
}).Error("Failed to read lease: insufficient data")
return
}
copy(lease[:], data[:LEASE_SIZE])
remainder = data[LEASE_SIZE:]
log.WithFields(logrus.Fields{
"tunnel_id": lease.TunnelID(),
"expiration": lease.Date().Time(),
"remainder_length": len(remainder),
}).Debug("Successfully read Lease")
return
}
// NewLease creates a new *NewLease from []byte using ReadLease.
// Returns a pointer to KeysAndCert unlike ReadLease.
func NewLease(data []byte) (lease *Lease, remainder []byte, err error) {
// TODO: stub
// NewLease creates a new Lease with the provided parameters.
func NewLease(tunnelGateway Hash, tunnelID uint32, expirationTime time.Time) (*Lease, error) {
log.Debug("Creating new Lease")
var lease Lease
// Gateway hash
copy(lease[:LEASE_HASH_SIZE], tunnelGateway[:])
// Convert and copy tunnel ID
tunnelIDBytes := make([]byte, LEASE_TUNNEL_ID_SIZE)
binary.BigEndian.PutUint32(tunnelIDBytes, tunnelID)
copy(lease[LEASE_HASH_SIZE:LEASE_HASH_SIZE+LEASE_TUNNEL_ID_SIZE], tunnelIDBytes)
// Convert and copy expiration date
millis := expirationTime.UnixNano() / int64(time.Millisecond)
dateBytes := make([]byte, DATE_SIZE)
binary.BigEndian.PutUint64(dateBytes, uint64(millis))
copy(lease[LEASE_HASH_SIZE+LEASE_TUNNEL_ID_SIZE:], dateBytes)
log.WithFields(logrus.Fields{
"tunnel_id": tunnelID,
"expiration": expirationTime,
}).Debug("Successfully created new Lease")
return &lease, nil
}
// NewLeaseFromBytes creates a new *Lease from []byte using ReadLease.
// Returns a pointer to Lease unlike ReadLease.
func NewLeaseFromBytes(data []byte) (lease *Lease, remainder []byte, err error) {
log.WithField("input_length", len(data)).Debug("Creating Lease from bytes")
var l Lease
l, remainder, err = ReadLease(data)
if err != nil {
log.WithError(err).Error("Failed to read Lease from bytes")
return nil, remainder, err
}
lease = &l
log.WithFields(logrus.Fields{
"tunnel_id": lease.TunnelID(),
"expiration": lease.Date().Time(),
"remainder_length": len(remainder),
}).Debug("Successfully created Lease from bytes")
return
}

View File

@ -406,3 +406,154 @@ func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
log.WithField("oldest_expiration", earliest.Time()).Debug("Found oldest expiration in LeaseSet")
return
}
func NewLeaseSet(
destination Destination,
encryptionKey crypto.PublicKey,
signingKey crypto.SigningPublicKey,
leases []Lease,
signingPrivateKey crypto.SigningPrivateKey,
) (LeaseSet, error) {
log.Debug("Creating new LeaseSet")
// Validate inputs
if len(leases) > 16 {
return nil, errors.New("invalid lease set: more than 16 leases")
}
// Build LeaseSet data
data := make([]byte, 0)
// Add Destination
data = append(data, destination.KeysAndCert.Bytes()...)
// Add encryption key
data = append(data, encryptionKey.Bytes()...)
// Add signing key
data = append(data, signingKey.Bytes()...)
// Add lease count
leaseCount, err := NewIntegerFromInt(len(leases), 1)
if err != nil {
log.WithError(err).Error("Failed to create lease count")
return nil, err
}
data = append(data, leaseCount.Bytes()...)
// Add leases
for _, lease := range leases {
data = append(data, lease[:]...)
}
// Create signature for all data up to this point
signer, err := signingPrivateKey.NewSigner()
if err != nil {
log.WithError(err).Error("Failed to create signer")
return nil, err
}
signature, err := signer.Sign(data)
if err != nil {
log.WithError(err).Error("Failed to sign LeaseSet")
return nil, err
}
// Add signature
data = append(data, signature...)
log.WithFields(logrus.Fields{
"destination_length": len(destination.KeysAndCert.Bytes()),
"encryption_key_length": len(encryptionKey.Bytes()),
"signing_key_length": len(signingKey.Bytes()),
"lease_count": len(leases),
"total_length": len(data),
}).Debug("Successfully created new LeaseSet")
return LeaseSet(data), nil
}
// NewLeaseSetFromBytes creates a LeaseSet from raw byte data.
func NewLeaseSetFromBytes(data []byte) (LeaseSet, error) {
log.WithField("data_length", len(data)).Debug("Creating LeaseSet from bytes")
// Basic size validation
minSize := LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1 + LEASE_SET_SIG_SIZE
if len(data) < minSize {
return nil, errors.New("error parsing lease set: data too short")
}
leaseSet := LeaseSet(data)
// Verify the LeaseSet is valid by trying to read its components
_, err := leaseSet.Destination()
if err != nil {
return nil, err
}
_, err = leaseSet.PublicKey()
if err != nil {
return nil, err
}
_, err = leaseSet.SigningKey()
if err != nil {
return nil, err
}
count, err := leaseSet.LeaseCount()
if err != nil {
return nil, err
}
if count > 16 {
return nil, errors.New("invalid lease set: more than 16 leases")
}
_, err = leaseSet.Leases()
if err != nil {
return nil, err
}
_, err = leaseSet.Signature()
if err != nil {
return nil, err
}
log.Debug("Successfully created LeaseSet from bytes")
return leaseSet, nil
}
func NewLeaseSetFromLease(
destination Destination,
encryptionKey crypto.PublicKey,
signingKey crypto.SigningPublicKey,
lease Lease,
signingPrivateKey crypto.SigningPrivateKey,
) (LeaseSet, error) {
log.Debug("Creating LeaseSet from single Lease")
// Create slice containing just the one lease
leases := []Lease{lease}
// Create LeaseSet using the main constructor
leaseSet, err := NewLeaseSet(
destination,
encryptionKey,
signingKey,
leases,
signingPrivateKey,
)
if err != nil {
log.WithError(err).Error("Failed to create LeaseSet from Lease")
return nil, err
}
log.WithFields(logrus.Fields{
"tunnel_gateway": lease.TunnelGateway(),
"tunnel_id": lease.TunnelID(),
"expiration": lease.Date().Time(),
}).Debug("Successfully created LeaseSet from Lease")
return leaseSet, nil
}