Compare commits

21 Commits

Author SHA1 Message Date
idk
4f19c48da3 Update the checklist, clarify method for filling it in 2021-04-26 20:54:32 -04:00
idk
961dfe4266 Passing implementation of certificates 2021-04-25 02:25:43 -04:00
idk
afb38b6165 Passing implementation of certificates 2021-04-25 02:23:54 -04:00
idk
0aa32b4aad start fixing up the tests on the new struct implementations 2021-04-25 02:09:12 -04:00
idk
3adf694c25 start fixing up the tests on the new struct implementations 2021-04-25 02:07:59 -04:00
idk
a11c3b73cb start fixing up the tests on the new struct implementations 2021-04-25 02:06:57 -04:00
idk
853bc79f8f start fixing up the tests on the new struct implementations 2021-04-24 23:23:29 -04:00
idk
77f1c6dd0a start fixing up the tests on the new struct implementations 2021-04-24 22:48:48 -04:00
idk
ee7d8a0d63 OK before I go any further on this I should go back and check it against the tests. 2021-04-24 19:20:37 -04:00
idk
c253bf31ac fix likely issue in ReadKeys 2021-04-24 18:36:57 -04:00
idk
b97b2854c1 add a stub file for leaseset2 2021-04-24 18:07:57 -04:00
idk
d5266f8980 finish structifying lease, add a stub file for lease2 2021-04-24 18:04:10 -04:00
idk
6de4dde1f2 Don't redundantly(and falsely) count the remainder when reading KeysAndCert 2021-04-24 16:25:21 -04:00
idk
648c05b15f Make an interface of KeysAndCert 2021-04-24 16:05:23 -04:00
idk
bfc7237ba6 work on leasesets 2021-04-24 15:59:38 -04:00
idk
ffbdc7f967 Comment IntegerBytes 2021-04-24 15:35:08 -04:00
idk
1cd9d16760 Read in public and private keys when reading in keysandcert from a byte slice 2021-04-24 15:32:45 -04:00
idk
896df4e483 Update README.md with some of the plan 2021-04-22 23:49:00 -04:00
idk
49d7eeb441 Update README.md with some of the plan 2021-04-22 23:47:15 -04:00
idk
7893694c91 Update README.md with some of the plan 2021-04-22 23:47:04 -04:00
idk
1ea426da9c Begin to convert the common structures from being byte-slice based to struct based 2021-04-22 22:55:32 -04:00
15 changed files with 697 additions and 279 deletions

View File

@ -23,3 +23,6 @@ test:
clean: clean:
$(GO) clean -v $(GO) clean -v
fmt:
find . -name '*.go' -exec gofmt -w -s {} \;

View File

@ -4,10 +4,35 @@ A pure Go implementation of the I2P router.
## Status ## Status
go-i2p is in early development. go-i2p was in early development. Now it's being restructured in some
fundamental ways, so it's even less done than before(on this branch, for now)
but when this restructuring is complete, it will be a fully-fledged I2P router
and library for writing, embedding, and possiblly extending I2P routers in Go
applications.
The go module is declared as: `github.com/go-i2p/go-i2p`, in order to clone
anonymously you may use `torsocks` with `go get`(YMMV) or you may clone
it from git.idk.i2p using:
#Set your $GOPATH, if it isn't set already then GOPATH=$HOME/go
$GOPATH/go/src/i2pgit.org/idk/
git clone git@127.0.0.1:idk/go-i2p $GOPATH/go/src/github.com/go-i2p/go-i2p
$GOPATH/go/src/github.com/go-i2p/go-i2p
And build with `GO111MODULES=off` or use a `replace` directive in your `go.mod`
to direct to the local module source. Or you may run your own Go Modules proxy as
a hidden service. I'll make this about a billion times easier in the near future I
promise.
### Implemented Features ### Implemented Features
As the application is restructured and moved away from representing I2P data
structures as byte slices, this chart will be filled in, when the tests pass,
the item will be checked off. Currently, much of this is partially implemented
in byte-slice versions and partially implemented as Go Structs. Very little of
it will work until it's all moved to Go Structs where appropriate. Most of
this will happen in /lib/common.
- Cryptographic primitives - Cryptographic primitives
- Signing - Signing
- [ ] ECDSA_SHA256_P256 - [ ] ECDSA_SHA256_P256
@ -23,8 +48,38 @@ go-i2p is in early development.
- [ ] RSA_SHA384_3072 - [ ] RSA_SHA384_3072
- [ ] RSA_SHA512_4096 - [ ] RSA_SHA512_4096
- [ ] Ed25519 - [ ] Ed25519
- [ ] ElGamal - [x] ElGamal
- [ ] AES256 - [x] AES256
- Common Structures
- Common Type Specification
- [x] Integer
- [x] Date
- [x] String
- [x] PublicKey* As interface in lib/crypto
- [x] PrivateKey* As interface in lib/crypto
- [ ] SessionKey
- [ ] SigningPublicKey
- [ ] Signature
- [x] Hash
- [ ] Session Tag
- [ ] Tunnel ID
- [x] Certificate
- [ ] Mapping
- Common Structure Specification
- [ ] KeysAndCert
- [ ] RouterIdentity
- [ ] Destination
- [ ] Lease
- [ ] LeaseSet
- [ ] Lease2
- [ ] OfflineSigntature
- [ ] LeaseSet2Header
- [ ] LeaseSet2
- [ ] MetaLease
- [ ] MetaLeaseSet
- [ ] EncryptedLeaseSet
- [ ] RouterAddress
- [ ] RouterInfo
- I2NP - I2NP
- [ ] Message parsing - [ ] Message parsing
- [ ] Message handling - [ ] Message handling

View File

@ -46,25 +46,45 @@ const (
CERT_MIN_SIZE = 3 CERT_MIN_SIZE = 3
) )
type Certificate []byte type CertificateInterface interface {
Cert() []byte
Length() (length int, err error)
Data() (data []byte, err error)
Type() (cert_type int, err error)
SignatureSize() (size int)
}
type Certificate struct {
CertType int
CertLen int
CertBytes []byte
}
var ci CertificateInterface = &Certificate{}
func (certificate Certificate) SignatureSize() (size int) {
return 40
}
func (certificate Certificate) Cert() []byte {
var ret []byte
ret = append(ret, IntegerBytes(certificate.CertType)...)
data, _ := certificate.Data()
if certificate.CertLen != 0 && len(data) != 0 {
ret = append(ret, LengthBytes(certificate.CertLen)...)
ret = append(ret, data...)
} else {
ret = append(ret, IntegerBytes(certificate.CertLen)...)
}
return ret
}
// //
// Return the Certificate Type specified in the first byte of the Certificate, // Return the Certificate Type specified in the first byte of the Certificate,
// and an error if the certificate is shorter than the minimum certificate size. // and an error if the certificate is shorter than the minimum certificate size.
// //
func (certificate Certificate) Type() (cert_type int, err error) { func (certificate Certificate) Type() (cert_type int, err error) {
cert_len := len(certificate) return certificate.CertType, nil
if cert_len < CERT_MIN_SIZE {
log.WithFields(log.Fields{
"at": "(Certificate) Type",
"certificate_bytes_length": cert_len,
"reason": "too short (len < CERT_MIN_SIZE)",
}).Error("invalid certificate")
err = errors.New("error parsing certificate length: certificate is too short")
return
}
cert_type = Integer([]byte{certificate[0]})
return
} }
// //
@ -73,31 +93,39 @@ func (certificate Certificate) Type() (cert_type int, err error) {
// match the provided data. // match the provided data.
// //
func (certificate Certificate) Length() (length int, err error) { func (certificate Certificate) Length() (length int, err error) {
cert_len := len(certificate) if certificate.CertLen < 1 {
_, err = certificate.Type()
if err != nil {
return
}
length = Integer(certificate[1:CERT_MIN_SIZE])
inferred_len := length + CERT_MIN_SIZE
if inferred_len > cert_len {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Certificate) Length", "at": "(Certificate) Length",
"certificate_bytes_length": cert_len, "certificate_bytes_length": certificate.CertLen,
"certificate_length_field": length, "certificate_min_size": CERT_MIN_SIZE - 1,
"expected_bytes_length": inferred_len, "reason": "certificate is too short",
"reason": "data shorter than specified", }).Warn("certificate format warning")
err = errors.New("error parsing certificate length: certificate is too short")
}
if certificate.CertLen > len(certificate.CertBytes) {
log.WithFields(log.Fields{
"at": "(Certificate) Length",
"certificate_bytes_length": certificate.CertLen,
"certificate_actual_length": len(certificate.CertBytes),
"reason": "certificate data is shorter than specified by length",
}).Warn("certificate format warning") }).Warn("certificate format warning")
err = errors.New("certificate parsing warning: certificate data is shorter than specified by length") err = errors.New("certificate parsing warning: certificate data is shorter than specified by length")
} else if cert_len > inferred_len { length = len(certificate.CertBytes)
}
if certificate.CertLen < len(certificate.CertBytes) {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(Certificate) Length", "at": "(Certificate) Length",
"certificate_bytes_length": cert_len, "certificate_bytes_length": certificate.CertLen,
"certificate_length_field": length, "certificate_actual_length": len(certificate.CertBytes),
"expected_bytes_length": inferred_len, "reason": "certificate contains data beyond length",
"reason": "data longer than expected",
}).Warn("certificate format warning") }).Warn("certificate format warning")
err = errors.New("certificate parsing warning: certificate contains data beyond length") err = errors.New("certificate parsing warning: certificate contains data beyond length")
length = certificate.CertLen
return
}
length = certificate.CertLen
if err != nil {
return
} }
return return
} }
@ -106,20 +134,20 @@ func (certificate Certificate) Length() (length int, err error) {
// Return the Certificate data and any errors encountered parsing the Certificate. // Return the Certificate data and any errors encountered parsing the Certificate.
// //
func (certificate Certificate) Data() (data []byte, err error) { func (certificate Certificate) Data() (data []byte, err error) {
length, err := certificate.Length() _, err = certificate.Length()
if err != nil { if err != nil {
switch err.Error() { switch 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_SIZE:] data = certificate.CertBytes
return return
case "certificate parsing warning: certificate contains data beyond length": case "certificate parsing warning: certificate contains data beyond length":
data = certificate[CERT_MIN_SIZE : length+CERT_MIN_SIZE] data = certificate.CertBytes[:certificate.CertLen]
return return
} }
} }
data = certificate[CERT_MIN_SIZE:] data = certificate.CertBytes
return return
} }
@ -128,12 +156,41 @@ func (certificate Certificate) Data() (data []byte, err error) {
// and any errors if a valid Certificate could not be read. // and any errors if a valid Certificate could not be read.
// //
func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) { func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
certificate = Certificate(data) certificate.CertType = Integer(data[0:1])
length, err := certificate.Length() cert_len := len(data)
if err != nil && err.Error() == "certificate parsing warning: certificate contains data beyond length" {
certificate = Certificate(data[:length+CERT_MIN_SIZE]) if cert_len < CERT_MIN_SIZE {
remainder = data[length+CERT_MIN_SIZE:] log.WithFields(log.Fields{
err = nil "at": "(Certificate) ReadCertificate",
"certificate_bytes_length": cert_len,
"certificate_min_size": CERT_MIN_SIZE,
"reason": "certificate is too short",
}).Warn("certificate format warning")
err = errors.New("error parsing certificate length: certificate is too short")
return
} else {
certificate.CertLen = Integer(data[1:CERT_MIN_SIZE])
_, err = certificate.Type()
if err != nil {
return
}
certificate.CertBytes = data[CERT_MIN_SIZE:]
_, err = certificate.Length()
if err != nil {
switch err.Error() {
case "error parsing certificate length: certificate is too short":
return
case "certificate parsing warning: certificate data is shorter than specified by length":
//err = nil
return
case "certificate parsing warning: certificate contains data beyond length":
certificate.CertBytes = data[CERT_MIN_SIZE:]
remainder = data[CERT_MIN_SIZE+certificate.CertLen:]
err = nil
return
}
}
} }
return return
} }

View File

@ -9,7 +9,10 @@ func TestCertificateTypeIsFirstByte(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x00} bytes := []byte{0x03, 0x00, 0x00}
certificate := Certificate(bytes) certificate, _, err := ReadCertificate(bytes)
if err != nil {
t.Log(err)
}
cert_type, err := certificate.Type() cert_type, err := certificate.Type()
assert.Equal(cert_type, 3, "certificate.Type() should be the first bytes in a certificate") assert.Equal(cert_type, 3, "certificate.Type() should be the first bytes in a certificate")
@ -20,7 +23,7 @@ func TestCertificateLengthCorrect(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff} bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
certificate := Certificate(bytes) certificate, _, err := ReadCertificate(bytes)
cert_len, err := certificate.Length() cert_len, err := certificate.Length()
assert.Equal(cert_len, 2, "certificate.Length() should return integer from second two bytes") assert.Equal(cert_len, 2, "certificate.Length() should return integer from second two bytes")
@ -31,7 +34,10 @@ func TestCertificateLengthErrWhenTooShort(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x01} bytes := []byte{0x03, 0x01}
certificate := Certificate(bytes) certificate, _, err := ReadCertificate(bytes)
if assert.NotNil(err) {
assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned")
}
cert_len, err := certificate.Length() cert_len, err := certificate.Length()
assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data") assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data")
@ -44,7 +50,7 @@ func TestCertificateLengthErrWhenDataTooShort(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff} bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate := Certificate(bytes) certificate, _, err := ReadCertificate(bytes)
cert_len, err := certificate.Length() cert_len, err := certificate.Length()
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was actually missing") assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was actually missing")
@ -57,28 +63,31 @@ func TestCertificateDataWhenCorrectSize(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x01, 0xaa} bytes := []byte{0x03, 0x00, 0x01, 0xaa}
certificate := Certificate(bytes) certificate, _, err := ReadCertificate(bytes)
cert_data, err := certificate.Data() assert.Nil(err, "certificate.Data() returned error with valid data")
cert_len, err := certificate.Length()
assert.Nil(err, "certificate.Data() returned error with valid data") assert.Nil(err, "certificate.Data() returned error with valid data")
cert_len := len(cert_data)
assert.Equal(cert_len, 1, "certificate.Length() did not return indicated length when data was valid") assert.Equal(cert_len, 1, "certificate.Length() did not return indicated length when data was valid")
assert.Equal(170, int(cert_data[0]), "certificate.Data() returned incorrect data") data := Integer(certificate.CertBytes)
assert.Equal(170, data, "certificate.Data() returned incorrect data")
} }
func TestCertificateDataWhenTooLong(t *testing.T) { func TestCertificateDataWhenTooLong(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa} bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
certificate := Certificate(bytes) certificate, _, err := ReadCertificate(bytes)
cert_data, err := certificate.Data()
cert_len, err := certificate.Length()
if assert.NotNil(err) { if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate contains data beyond length", err.Error(), "correct error message should be returned") assert.Equal("certificate parsing warning: certificate contains data beyond length", err.Error(), "correct error message should be returned")
} }
cert_len := len(cert_data)
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was too long") assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was too long")
if cert_data[0] != 0xff || cert_data[1] != 0xff { if certificate.CertBytes[0] != 0xff || certificate.CertBytes[1] != 0xff {
t.Fatal("certificate.Data() returned incorrect data when data was too long") t.Fatal("certificate.Data() returned incorrect data when data was too long")
} }
} }
@ -87,7 +96,7 @@ func TestCertificateDataWhenTooShort(t *testing.T) {
assert := assert.New(t) assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff} bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate := Certificate(bytes) certificate, _, err := ReadCertificate(bytes)
cert_data, err := certificate.Data() cert_data, err := certificate.Data()
if assert.NotNil(err) { if assert.NotNil(err) {
@ -104,7 +113,7 @@ func TestReadCertificateWithCorrectData(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff} bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff}
cert, remainder, err := ReadCertificate(bytes) cert, remainder, err := ReadCertificate(bytes)
assert.Equal(len(cert), 5, "ReadCertificate() did not return correct amount of data for valid certificate") assert.Equal(len(cert.Cert()), 5, "ReadCertificate() did not return correct amount of data for valid certificate")
assert.Equal(len(remainder), 0, "ReadCertificate() did not return a zero length remainder on a valid certificate") assert.Equal(len(remainder), 0, "ReadCertificate() did not return a zero length remainder on a valid certificate")
assert.Nil(err, "ReadCertificate() should not return an error with valid data") assert.Nil(err, "ReadCertificate() should not return an error with valid data")
} }
@ -115,7 +124,7 @@ func TestReadCertificateWithDataTooShort(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff} bytes := []byte{0x00, 0x00, 0x02, 0xff}
cert, remainder, err := ReadCertificate(bytes) cert, remainder, err := ReadCertificate(bytes)
assert.Equal(len(cert), 4, "ReadCertificate() did not return correct amount of data for certificate with missing data") assert.Equal(len(cert.Cert()), 4, "ReadCertificate() did not return correct amount of data for certificate with missing data")
assert.Equal(len(remainder), 0, "ReadCertificate() did not return a zero length remainder on certificate with missing data") assert.Equal(len(remainder), 0, "ReadCertificate() did not return a zero length remainder on certificate with missing data")
if assert.NotNil(err) { if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error(), "correct error message should be returned") assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error(), "correct error message should be returned")
@ -128,7 +137,7 @@ func TestReadCertificateWithRemainder(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff, 0x01} bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff, 0x01}
cert, remainder, err := ReadCertificate(bytes) cert, remainder, err := ReadCertificate(bytes)
assert.Equal(len(cert), 5, "ReadCertificate() did not return correct amount of data for certificate with extra data") assert.Equal(len(cert.Cert()), 5, "ReadCertificate() did not return correct amount of data for certificate with extra data")
assert.Equal(len(remainder), 1, "ReadCertificate() returned incorrect length remainder on certificate with extra data") assert.Equal(len(remainder), 1, "ReadCertificate() returned incorrect length remainder on certificate with extra data")
assert.Equal(1, int(remainder[0]), "ReadCertificate() did not return correct remainder value") assert.Equal(1, int(remainder[0]), "ReadCertificate() did not return correct remainder value")
assert.Nil(err) assert.Nil(err)
@ -140,7 +149,7 @@ func TestReadCertificateWithInvalidLength(t *testing.T) {
bytes := []byte{0x00, 0x00} bytes := []byte{0x00, 0x00}
cert, remainder, err := ReadCertificate(bytes) cert, remainder, err := ReadCertificate(bytes)
assert.Equal(len(cert), 2, "ReadCertificate() should populate the certificate with the provided data even when invalid") assert.Equal(len(cert.Cert()), 2, "ReadCertificate() should populate the certificate with the provided data even when invalid")
assert.Equal(len(remainder), 0, "ReadCertificate() returned non-zero length remainder on invalid certificate") assert.Equal(len(remainder), 0, "ReadCertificate() returned non-zero length remainder on invalid certificate")
if assert.NotNil(err) { if assert.NotNil(err) {
assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned") assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned")

View File

@ -19,31 +19,27 @@ import (
// A Destination is a KeysAndCert with functionallity // A Destination is a KeysAndCert with functionallity
// for generating base32 and base64 addresses. // for generating base32 and base64 addresses.
// //
type Destination []byte type Destination struct {
KeysAndCert
}
func (destination Destination) PublicKey() (crypto.PublicKey, error) { func (destination Destination) PublicKey() (crypto.PublicKey, error) {
return KeysAndCert(destination).PublicKey() return destination.KeysAndCert.GetPublicKey()
} }
func (destination Destination) SigningPublicKey() (crypto.SigningPublicKey, error) { func (destination Destination) SigningPublicKey() (crypto.SigningPublicKey, error) {
return KeysAndCert(destination).SigningPublicKey() return destination.KeysAndCert.GetSigningPublicKey()
} }
func (destination Destination) Certificate() (Certificate, error) { func (destination Destination) Certificate() (CertificateInterface, error) {
return KeysAndCert(destination).Certificate() return destination.KeysAndCert.GetCertificate()
}
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
keys_and_cert, remainder, err := ReadKeysAndCert(data)
destination = Destination(keys_and_cert)
return
} }
// //
// Generate the I2P base32 address for this Destination. // Generate the I2P base32 address for this Destination.
// //
func (destination Destination) Base32Address() (str string) { func (destination Destination) Base32Address() (str string) {
hash := crypto.SHA256(destination) hash := crypto.SHA256(destination.Cert())
str = strings.Trim(base32.EncodeToString(hash[:]), "=") str = strings.Trim(base32.EncodeToString(hash[:]), "=")
str = str + ".b32.i2p" str = str + ".b32.i2p"
return return
@ -53,5 +49,14 @@ func (destination Destination) Base32Address() (str string) {
// Generate the I2P base64 address for this Destination. // Generate the I2P base64 address for this Destination.
// //
func (destination Destination) Base64() string { func (destination Destination) Base64() string {
return base64.EncodeToString(destination) return base64.EncodeToString(destination.Cert())
}
func ReadDestination(data []byte) (destination Destination, remainder []byte, err error) {
keys_and_cert, remainder, err := ReadKeysAndCert(data)
if err != nil {
return
}
destination.KeysAndCert = keys_and_cert
return
} }

View File

@ -30,3 +30,23 @@ func Integer(number []byte) (value int) {
value = int(binary.BigEndian.Uint64(number)) value = int(binary.BigEndian.Uint64(number))
return return
} }
//
// Take an int representation and return a big endian integer.
//
func IntegerBytes(value int) (number []byte) {
onumber := make([]byte, INTEGER_SIZE)
// var number []byte
binary.BigEndian.PutUint64(onumber, uint64(value))
var index int
for i, j := range onumber {
index = i
if j != 0 {
break
}
}
number = onumber[index:]
return
}

View File

@ -74,13 +74,25 @@ const (
KEYCERT_SPK_SIZE = 128 KEYCERT_SPK_SIZE = 128
) )
type KeyCertificate []byte type KeyCertificate struct {
Certificate
PKType int
PKExtra []byte
SPKType int
SPKExtra []byte
} //[]byte
// //
// The data contained in the Key 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() var r []byte
r = append(r, key_certificate.Certificate.Cert()...)
pk := IntegerBytes(key_certificate.PKType)
r = append(r, pk...)
spk := IntegerBytes(key_certificate.SPKType)
r = append(r, spk...)
return r, nil
} }
// //
@ -88,27 +100,7 @@ func (key_certificate KeyCertificate) Data() ([]byte, error) {
// parsing the KeyCertificate. // 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() return key_certificate.SPKType, nil
if err != nil {
log.WithFields(log.Fields{
"at": "(KeyCertificate) SigningPublicKeyType",
"reason": err.Error(),
}).Error("error getting signing public key")
return
}
data_len := len(data)
if data_len < 2 {
log.WithFields(log.Fields{
"at": "(KeyCertificate) SigningPublicKeyType",
"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])
return
} }
// //
@ -116,23 +108,7 @@ func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_typ
// this KeyCertificate. // 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() return key_certificate.PKType, nil
if err != nil {
return
}
data_len := len(data)
if data_len < 4 {
log.WithFields(log.Fields{
"at": "(KeyCertificate) PublicKeyType",
"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])
return
} }
// //
@ -201,7 +177,8 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
var ec_key crypto.ECP521PublicKey var ec_key crypto.ECP521PublicKey
extra := KEYCERT_SIGN_P521_SIZE - KEYCERT_SPK_SIZE extra := KEYCERT_SIGN_P521_SIZE - KEYCERT_SPK_SIZE
copy(ec_key[:], data) copy(ec_key[:], data)
copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate[4:4+extra]) d, _ := key_certificate.Data()
copy(ec_key[KEYCERT_SPK_SIZE:], d[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
@ -244,3 +221,38 @@ func (key_certificate KeyCertificate) SignatureSize() (size int) {
} }
return sizes[int(key_type)] return sizes[int(key_type)]
} }
//
// Read a KeyCertificate from a slice of bytes
//
func ReadKeyCertificate(data []byte) (key_certificate KeyCertificate, err error) {
cert, data, err := ReadCertificate(data)
if err != nil {
return
}
key_certificate.Certificate = cert
data_len := len(data)
if data_len < 2 {
log.WithFields(log.Fields{
"at": "(KeyCertificate) SigningPublicKeyType",
"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
}
key_certificate.SPKType = Integer(data[:2])
if data_len < 4 {
log.WithFields(log.Fields{
"at": "(KeyCertificate) PublicKeyType",
"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
}
key_certificate.PKType = Integer(data[2:4])
return
}

View File

@ -59,14 +59,33 @@ const (
KEYS_AND_CERT_DATA_SIZE = 384 KEYS_AND_CERT_DATA_SIZE = 384
) )
type KeysAndCert []byte type KeysAndCertInterface interface {
GetPublicKey() (key crypto.PublicKey, err error)
GetSigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error)
GetCertificate() (cert Certificate, err error)
}
type KeysAndCert struct {
crypto.SigningPublicKey
crypto.PublicKey
CertificateInterface
}
func (keys_and_cert KeysAndCert) Bytes() (bytes []byte) { //, err error) {
elg_key := keys_and_cert.PublicKey.(crypto.ElgPublicKey)
dsa_key := keys_and_cert.SigningPublicKey.(crypto.DSAPublicKey)
bytes = append(bytes, dsa_key[:]...)
bytes = append(bytes, elg_key[:]...)
bytes = append(bytes, keys_and_cert.CertificateInterface.Cert()...)
return
}
// //
// Return the PublicKey for this KeysAndCert, reading from the Key Certificate if it is present to // Return the PublicKey for this KeysAndCert, reading from the Key Certificate if it is present to
// determine correct lengths. // determine correct lengths.
// //
func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) { func (keys_and_cert KeysAndCert) GetPublicKey() (key crypto.PublicKey, err error) {
cert, err := keys_and_cert.Certificate() cert, err := keys_and_cert.GetCertificate()
if err != nil { if err != nil {
return return
} }
@ -74,35 +93,8 @@ func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) {
if err != nil { if err != nil {
return return
} }
if cert_len == 0 { if cert_len != 0 {
// No Certificate is present, return the KEYS_AND_CERT_PUBKEY_SIZE byte key = keys_and_cert.PublicKey
// PublicKey space as ElgPublicKey.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
} else {
// A Certificate is present in this KeysAndCert
cert_type, _ := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a PublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
key, err = KeyCertificate(cert).ConstructPublicKey(
keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey. No other Certificate
// types are currently in use.
var elg_key crypto.ElgPublicKey
copy(keys_and_cert[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
key = elg_key
log.WithFields(log.Fields{
"at": "(KeysAndCert) PublicKey",
"cert_type": cert_type,
}).Warn("unused certificate type observed")
}
} }
return return
} }
@ -111,8 +103,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 to // Return the SigningPublicKey for this KeysAndCert, reading from the Key Certificate if it is present to
// determine correct lengths. // determine correct lengths.
// //
func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) { func (keys_and_cert KeysAndCert) GetSigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) {
cert, err := keys_and_cert.Certificate() cert, err := keys_and_cert.GetCertificate()
if err != nil { if err != nil {
return return
} }
@ -120,31 +112,8 @@ func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.S
if err != nil { if err != nil {
return return
} }
if cert_len == 0 { if cert_len != 0 {
// No Certificate is present, return the KEYS_AND_CERT_SPK_SIZE byte signing_public_key = keys_and_cert.SigningPublicKey
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
} else {
// A Certificate is present in this KeysAndCert
cert_type, _ := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a SigningPublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
signing_public_key, err = 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 KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy SHA DSA1 SigningPublicKey.
// No other Certificate types are currently in use.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], keys_and_cert[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
signing_public_key = dsa_pk
}
} }
return return
} }
@ -153,19 +122,12 @@ func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.S
// Return the Certificate contained in the KeysAndCert and any errors encountered while parsing the // Return the Certificate contained in the KeysAndCert and any errors encountered while parsing the
// KeysAndCert or Certificate. // KeysAndCert or Certificate.
// //
func (keys_and_cert KeysAndCert) Certificate() (cert Certificate, err error) { func (keys_and_cert KeysAndCert) GetCertificate() (cert CertificateInterface, err error) {
keys_cert_len := len(keys_and_cert) _, err = keys_and_cert.CertificateInterface.Type()
if keys_cert_len < KEYS_AND_CERT_MIN_SIZE { if err != nil {
log.WithFields(log.Fields{
"at": "(KeysAndCert) Certificate",
"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[KEYS_AND_CERT_DATA_SIZE:]) cert = keys_and_cert.CertificateInterface
return return
} }
@ -185,19 +147,93 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
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
} }
keys_and_cert = KeysAndCert(data[:KEYS_AND_CERT_MIN_SIZE]) cert, remainder, err := ReadCertificate(data[:KEYS_AND_CERT_MIN_SIZE])
cert, _ := keys_and_cert.Certificate() if err != nil {
cert_len, cert_len_err := cert.Length() return
}
spk, pk, remainder, err := ReadKeys(data, cert)
if err != nil {
return
}
keys_and_cert = KeysAndCert{
SigningPublicKey: spk,
PublicKey: pk,
CertificateInterface: cert,
}
return
}
func ReadKeys(data []byte, cert CertificateInterface) (spk crypto.SigningPublicKey, pk crypto.PublicKey, remainder []byte, err error) {
data_len := len(data)
if data_len < KEYS_AND_CERT_MIN_SIZE {
log.WithFields(log.Fields{
"at": "ReadKeysAndCert",
"data_len": data_len,
"required_len": KEYS_AND_CERT_MIN_SIZE,
"reason": "not enough data",
}).Error("error parsing keys and cert")
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
return
}
if cert == nil {
// No Certificate is present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey.
var elg_key crypto.ElgPublicKey
copy(data[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
pk = elg_key
} else {
// A Certificate is present in this KeysAndCert
cert_type, _ := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a PublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
pk, err = KeyCertificate{PKType: cert_type}.ConstructPublicKey(
data[:KEYS_AND_CERT_PUBKEY_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// PublicKey space as ElgPublicKey. No other Certificate
// types are currently in use.
var elg_key crypto.ElgPublicKey
copy(data[:KEYS_AND_CERT_PUBKEY_SIZE], elg_key[:])
pk = elg_key
log.WithFields(log.Fields{
"at": "(KeysAndCert) PublicKey",
"cert_type": cert_type,
}).Warn("unused certificate type observed")
}
}
if data_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy DSA SHA1 SigningPublicKey.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], data[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
spk = dsa_pk
} else {
// A Certificate is present in this KeysAndCert
cert_type, _ := cert.Type()
if cert_type == CERT_KEY {
// This KeysAndCert contains a Key Certificate, construct
// a SigningPublicKey from the data in the KeysAndCert and
// any additional data in the Certificate.
spk, err = KeyCertificate{SPKType: cert_type}.ConstructSigningPublicKey(
data[KEYS_AND_CERT_PUBKEY_SIZE : KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE],
)
} else {
// Key Certificate is not present, return the KEYS_AND_CERT_SPK_SIZE byte
// SigningPublicKey space as legacy SHA DSA1 SigningPublicKey.
// No other Certificate types are currently in use.
var dsa_pk crypto.DSAPublicKey
copy(dsa_pk[:], data[KEYS_AND_CERT_PUBKEY_SIZE:KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE])
spk = dsa_pk
}
}
cert_len, err := cert.Length()
if cert_len == 0 { if cert_len == 0 {
remainder = data[KEYS_AND_CERT_MIN_SIZE:] remainder = data[KEYS_AND_CERT_MIN_SIZE:]
return return
} }
if data_len < KEYS_AND_CERT_MIN_SIZE+cert_len { remainder = data[KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE:]
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:]...)
err = cert_len_err
} else {
keys_and_cert = append(keys_and_cert, data[KEYS_AND_CERT_MIN_SIZE:KEYS_AND_CERT_MIN_SIZE+cert_len]...)
remainder = data[KEYS_AND_CERT_MIN_SIZE+cert_len:]
}
return return
} }

View File

@ -31,34 +31,56 @@ end_date :: Date
// Sizes or various components of a Lease // Sizes or various components of a Lease
const ( const (
LEASE_SIZE = 44 LEASE_SIZE = 44
LEASE_HASH_SIZE = 32 LEASE_HASH_SIZE = 32
LEASE_TUNNEL_ID_SIZE = 4 LEASE_TUNNEL_ID_SIZE = 4
LEASE_TUNNEL_DATE_SIZE = 8
) )
type Lease [LEASE_SIZE]byte type LeaseInterface interface {
TunnelGateway() (hash Hash)
TunnelID() uint32
Date() (date Date)
}
type Lease struct {
LeaseHash Hash
TunnelIdent int
TunnelDate Date
} //[LEASE_SIZE]byte
var li LeaseInterface = &Lease{}
// //
// Return the first 32 bytes of the Lease as a Hash. // Return the first 32 bytes of the Lease as a Hash.
// //
func (lease Lease) TunnelGateway() (hash Hash) { func (lease Lease) TunnelGateway() (hash Hash) {
copy(hash[:], lease[:LEASE_HASH_SIZE]) copy(hash[:], lease.LeaseHash[:])
return return
} }
// //
// Parse the TunnelID Integer in the Lease. // Return the TunnelID Integer in the Lease.
// //
func (lease Lease) TunnelID() uint32 { func (lease Lease) TunnelID() uint32 {
return uint32( return uint32(lease.TunnelIdent)
Integer(lease[LEASE_HASH_SIZE : LEASE_HASH_SIZE+LEASE_TUNNEL_ID_SIZE]),
)
} }
// //
// Return the Date inside the Lease. // Return the Date inside the Lease.
// //
func (lease Lease) Date() (date Date) { func (lease Lease) Date() (date Date) {
copy(date[:], lease[LEASE_HASH_SIZE+LEASE_TUNNEL_ID_SIZE:]) copy(date[:], lease.TunnelDate[:])
return return
} }
//
// Possibly temporary? Just to make it compile for now
//
func (lease Lease) Bytes() (bytes []byte) {
var r []byte
r = append(r, lease.LeaseHash[:]...)
r = append(r, IntegerBytes(lease.TunnelIdent)[:]...)
r = append(r, lease.TunnelDate[:]...)
return r
}

40
lib/common/lease2.go Normal file
View File

@ -0,0 +1,40 @@
package common
/*
Lease2
https://geti2p.net/spec/common-structures#lease2
Description
Defines the authorization for a particular tunnel to receive messages targeting a Destination. Same as Lease but with a 4-byte end_date. Used by LeaseSet2. Supported as of 0.9.38; see proposal 123 for more information.
Contents
SHA256 Hash of the RouterIdentity of the gateway router, then the TunnelId, and finally a 4 byte end date.
+----+----+----+----+----+----+----+----+
| tunnel_gw |
+ +
| |
+ +
| |
+ +
| |
+----+----+----+----+----+----+----+----+
| tunnel_id | end_date |
+----+----+----+----+----+----+----+----+
tunnel_gw :: Hash of the RouterIdentity of the tunnel gateway
length -> 32 bytes
tunnel_id :: TunnelId
length -> 4 bytes
end_date :: 4 byte date
length -> 4 bytes
Seconds since the epoch, rolls over in 2106.
Notes
Total size: 40 bytes
JavaDoc: http://echelon.i2p/javadoc/net/i2p/data/Lease2.html
*/

View File

@ -93,35 +93,52 @@ const (
LEASE_SET_SIG_SIZE = 40 LEASE_SET_SIG_SIZE = 40
) )
type LeaseSet []byte type LeaseSetInterface interface {
GetPublicKey() (public_key crypto.ElgPublicKey, err error)
GetSigningKey() (signing_public_key crypto.SigningPublicKey, err error)
/* LeaseCount() (count int, err error)
Leases() (leases []Lease, err error)
Signature() (signature Signature, err error)
Verify() error
NewestExpiration() (oldest Date, err error)
OldestExpiration() (earliest Date, err error)*/
}
type LeaseSet struct {
Destination
crypto.SigningPublicKey
crypto.ElgPublicKey
LeaseList []Lease
}
var lsi LeaseSetInterface = &LeaseSet{}
// //
// Read a Destination from the LeaseSet. // Read a Destination from the LeaseSet.
// //
func (lease_set LeaseSet) Destination() (destination Destination, err error) { func (lease_set LeaseSet) GetDestination() (destination Destination, err error) {
keys_and_cert, _, err := ReadKeysAndCert(lease_set) if &lease_set.Destination != nil {
destination = Destination(keys_and_cert) destination = lease_set.Destination
} else {
err = errors.New("Error leaseset does not contain a destination")
}
return return
} }
// //
// Return the PublicKey in this LeaseSet and any errors ancountered parsing the LeaseSet. // 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) GetPublicKey() (public_key crypto.ElgPublicKey, err error) {
_, remainder, err := ReadKeysAndCert(lease_set) if lease_set.PublicKey == nil {
remainder_len := len(remainder)
if remainder_len < LEASE_SET_PUBKEY_SIZE {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(LeaseSet) PublicKey", "at": "(LeaseSet) PublicKey",
"data_len": remainder_len, "public": lease_set.PublicKey,
"required_len": LEASE_SET_PUBKEY_SIZE, "reason": "not enough data",
"reason": "not enough data",
}).Error("error parsing public key") }).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)
return return
} }
copy(public_key[:], remainder[:LEASE_SET_PUBKEY_SIZE]) public_key = lease_set.ElgPublicKey
return return
} }
@ -129,63 +146,24 @@ func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error
// Return the SigningPublicKey, as specified in the LeaseSet's Destination's Key Certificate if // Return the SigningPublicKey, as specified in the LeaseSet's Destination's Key Certificate if
// present, or a legacy DSA key. // present, or a legacy DSA key.
// //
func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicKey, err error) { func (lease_set LeaseSet) GetSigningKey() (signing_public_key crypto.SigningPublicKey, err error) {
destination, err := lease_set.Destination() if lease_set.SigningPublicKey == nil {
if err != nil {
return
}
offset := len(destination) + LEASE_SET_PUBKEY_SIZE
cert, err := destination.Certificate()
if err != nil {
return
}
cert_len, err := cert.Length()
if err != nil {
return
}
lease_set_len := len(lease_set)
if lease_set_len < offset+LEASE_SET_SPK_SIZE {
log.WithFields(log.Fields{ log.WithFields(log.Fields{
"at": "(LeaseSet) SigningKey", "at": "(LeaseSet) SigningKey",
"data_len": lease_set_len, "public": lease_set.SigningPublicKey,
"required_len": offset + LEASE_SET_SPK_SIZE, "reason": "not enough data",
"reason": "not enough data",
}).Error("error parsing signing public key") }).Error("error parsing signing public key")
err = errors.New("error parsing signing public key: not enough data") err = errors.New("error parsing signing public key: not enough data")
return return
} }
if cert_len == 0 { signing_public_key = lease_set.SigningPublicKey
// 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+LEASE_SET_SPK_SIZE])
signing_public_key = dsa_pk
} else {
// A Certificate is present in this LeaseSet's Destination
cert_type, _ := cert.Type()
if cert_type == CERT_KEY {
// 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, err = KeyCertificate(cert).ConstructSigningPublicKey(
lease_set[offset : offset+LEASE_SET_SPK_SIZE],
)
} else {
// 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+LEASE_SET_SPK_SIZE])
signing_public_key = dsa_pk
}
}
return return
} }
// //
// Return the number of Leases specified by the LeaseCount value in this LeaseSet. // 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
@ -211,12 +189,12 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) {
err = errors.New("invalid lease set: more than 16 leases") err = errors.New("invalid lease set: more than 16 leases")
} }
return return
} }*/
// //
// Read the Leases in this LeaseSet, returning a partial set if there is insufficient data. // 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
@ -241,17 +219,17 @@ func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
return return
} }
var lease Lease var lease Lease
copy(lease[:], lease_set[start:end]) copy(lease.Bytes(), lease_set[start:end])
leases = append(leases, lease) leases = append(leases, lease)
} }
return return
} }*/
// //
// Return the Signature data for the LeaseSet, as specified in the Destination's // Return the Signature data for the LeaseSet, as specified in the Destination's
// Key Certificate if present or the 40 bytes following the Leases. // 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 {
return return
@ -289,11 +267,12 @@ func (lease_set LeaseSet) Signature() (signature Signature, err error) {
} }
signature = []byte(lease_set[start:end]) signature = []byte(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) +
// LEASE_SET_PUBKEY_SIZE + // LEASE_SET_PUBKEY_SIZE +
@ -345,4 +324,24 @@ func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
} }
} }
return return
}*/
func ReadLeaseSet(data []byte) (lease_set LeaseSet, remainder []byte, err error) {
destination, remainder, err := ReadDestination(data)
if err != nil {
return
}
lease_set.Destination = destination
spk, pk, remainder, err := ReadKeys(remainder, nil)
if err != nil {
return
}
lease_set.SigningPublicKey = spk
switch pk.(type) {
case crypto.ElgPublicKey:
lease_set.ElgPublicKey = pk.(crypto.ElgPublicKey)
default:
err = errors.New("LeaseSet1 uses Elgamal public keys.")
}
return
} }

105
lib/common/lease_set_2.go Normal file
View File

@ -0,0 +1,105 @@
package common
/*
https://geti2p.net/spec/common-structures#leaseset2
LeaseSet2
Description
Contained in a I2NP DatabaseStore message of type 3. Supported as of 0.9.38; see proposal 123 for more information.
Contains all of the currently authorized Lease2 for a particular Destination, and the PublicKey to which garlic messages can be encrypted. A LeaseSet is one of the two structures stored in the network database (the other being RouterInfo), and is keyed under the SHA256 of the contained Destination.
Contents
LeaseSet2Header, followed by a options, then one or more PublicKey for encryption, Integer specifying how many Lease2 structures are in the set, followed by the actual Lease2 structures and finally a Signature of the previous bytes signed by the Destination's SigningPrivateKey or the transient key.
+----+----+----+----+----+----+----+----+
| ls2_header |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
| options |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
|numk| keytype0| keylen0 | |
+----+----+----+----+----+ +
| encryption_key_0 |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
| keytypen| keylenn | |
+----+----+----+----+ +
| encryption_key_n |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
| num| Lease2 0 |
+----+ +
| |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
| Lease2($num-1) |
+ +
| |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
| signature |
~ ~
~ ~
| |
+----+----+----+----+----+----+----+----+
ls2header :: LeaseSet2Header
length -> varies
options :: Mapping
length -> varies, 2 bytes minimum
numk :: Integer
length -> 1 byte
Number of key types, key lengths, and PublicKeys to follow
value: 1 <= numk <= max TBD
keytype :: The encryption type of the PublicKey to follow.
length -> 2 bytes
keylen :: The length of the PublicKey to follow.
Must match the specified length of the encryption type.
length -> 2 bytes
encryption_key :: PublicKey
length -> 256 bytes
num :: Integer
length -> 1 byte
Number of Lease2s to follow
value: 0 <= num <= 16
leases :: [Lease2]
length -> $num*40 bytes
signature :: Signature
length -> 40 bytes or as specified in destination's key
certificate, or by the sigtype of the transient public key,
if present in the header
Notes
The public key of the destination was used for the old I2CP-to-I2CP encryption which was disabled in version 0.6, it is currently unused.
The encryption keys are used for end-to-end ElGamal/AES+SessionTag encryption [ELGAMAL-AES] (type 0) or other end-to-end encryption schemes. See [ECIES] and proposals 145 and 156. They may be generated anew at every router startup or they may be persistent. X25519 (type 4, see [ECIES]) is supported as of release 0.9.44.
The signature is over the data above, PREPENDED with the single byte containing the DatabaseStore type (3).
The signature may be verified using the signing public key of the destination, or the transient signing public key, if an offline signature is included in the leaseset2 header.
The key length is provided for each key, so that floodfills and clients may parse the structure even if not all encryption types are known or supported.
JavaDoc: http://echelon.i2p/javadoc/net/i2p/data/LeaseSet2.html
*/

50
lib/common/length.go Normal file
View File

@ -0,0 +1,50 @@
package common
/*
Length, an extension of Integer
https://geti2p.net/spec/common-structures#integer
Accurate for version 0.9.24
*/
import (
"encoding/binary"
)
//
// Interpret a slice of bytes from length 0 to length 8 as a big-endian
// integer and return an int representation.
//
func Length(number []byte) (value int) {
num_len := len(number)
if num_len < INTEGER_SIZE {
number = append(
make([]byte, INTEGER_SIZE-num_len),
number...,
)
}
value = int(binary.BigEndian.Uint64(number))
return
}
//
// Take an int representation and return a big endian integer.
//
func LengthBytes(value int) (number []byte) {
onumber := make([]byte, INTEGER_SIZE)
// var number []byte
binary.BigEndian.PutUint64(onumber, uint64(value))
var index int
for i, j := range onumber {
index = i
if j != 0 {
break
}
}
if len(onumber[index:]) == 1 {
index--
}
number = onumber[index:]
return
}

View File

@ -15,22 +15,27 @@ import (
// //
// A RouterIdentity is identical to KeysAndCert. // A RouterIdentity is identical to KeysAndCert.
// //
type RouterIdentity []byte type RouterIdentity struct {
KeysAndCert
}
func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) { func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) {
return KeysAndCert(router_identity).PublicKey() return router_identity.PublicKey()
} }
func (router_identity RouterIdentity) SigningPublicKey() (crypto.SigningPublicKey, error) { func (router_identity RouterIdentity) SigningPublicKey() (crypto.SigningPublicKey, error) {
return KeysAndCert(router_identity).SigningPublicKey() return router_identity.SigningPublicKey()
} }
func (router_identity RouterIdentity) Certificate() (Certificate, error) { func (router_identity RouterIdentity) Certificate() (Certificate, error) {
return KeysAndCert(router_identity).Certificate() return router_identity.Certificate()
} }
func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) { func ReadRouterIdentity(data []byte) (router_identity RouterIdentity, remainder []byte, err error) {
keys_and_cert, remainder, err := ReadKeysAndCert(data) keys_and_cert, remainder, err := ReadKeysAndCert(data)
router_identity = RouterIdentity(keys_and_cert) if err != nil {
return
}
router_identity.KeysAndCert = keys_and_cert
return return
} }

View File

@ -97,7 +97,7 @@ func (router_info RouterInfo) IdentHash() (h Hash, err error) {
var ri RouterIdentity var ri RouterIdentity
ri, err = router_info.RouterIdentity() ri, err = router_info.RouterIdentity()
if err == nil { if err == nil {
h = HashData(ri) h = HashData(ri.Bytes())
} }
return return
} }
@ -210,7 +210,7 @@ func (router_info RouterInfo) Signature() (signature Signature) {
head := router_info.optionsLocation() head := router_info.optionsLocation()
size := head + router_info.optionsSize() size := head + router_info.optionsSize()
ident, _ := router_info.RouterIdentity() ident, _ := router_info.RouterIdentity()
keyCert := KeyCertificate(ident) keyCert := ident.CertificateInterface //KeyCertificate(ident)
sigSize := keyCert.SignatureSize() sigSize := keyCert.SignatureSize()
signature = Signature(router_info[size : size+sigSize]) signature = Signature(router_info[size : size+sigSize])
return return
@ -224,7 +224,7 @@ func (router_info RouterInfo) optionsLocation() (location int) {
if err != nil { if err != nil {
return return
} }
location += len(data) location += len(data.Bytes())
remainder_len := len(remainder) remainder_len := len(remainder)
if remainder_len < 9 { if remainder_len < 9 {