From e19d6fa0abf703aff80d5e83c40e928ab50e13cb Mon Sep 17 00:00:00 2001 From: Hayden Parker Date: Sun, 14 Feb 2016 22:28:20 -0800 Subject: [PATCH] more lease set work, certificate completed --- go_i2p_suite_test.go | 13 ---- lib/common/certificate.go | 123 +++++++++++++++++++++++---------- lib/common/certificate_test.go | 4 +- lib/common/key_certificate.go | 19 +++++ lib/common/lease_set.go | 94 ++++++++++++++++++++++--- 5 files changed, 190 insertions(+), 63 deletions(-) delete mode 100644 go_i2p_suite_test.go diff --git a/go_i2p_suite_test.go b/go_i2p_suite_test.go deleted file mode 100644 index ed542b0..0000000 --- a/go_i2p_suite_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package main_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "testing" -) - -func TestGoI2p(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "GoI2p Suite") -} diff --git a/lib/common/certificate.go b/lib/common/certificate.go index 195a2f9..2e534e7 100644 --- a/lib/common/certificate.go +++ b/lib/common/certificate.go @@ -1,7 +1,34 @@ package common +/* +I2P Certificate +https://geti2p.net/en/docs/spec/common-structures#type_Certificate +Accurate for version 0.9.24 + ++----+----+----+----+----+-// +|type| length | payload ++----+----+----+----+----+-// + +type :: Integer + length -> 1 byte + + case 0 -> NULL + case 1 -> HASHCASH + case 2 -> HIDDEN + case 3 -> SIGNED + case 4 -> MULTIPLE + case 5 -> KEY + +length :: Integer + length -> 2 bytes + +payload :: data + length -> $length bytes +*/ + import ( "errors" + log "github.com/Sirupsen/logrus" ) // Certificate Types @@ -14,11 +41,24 @@ const ( CERT_KEY ) +const ( + CERT_MIN_LENGTH = 3 +) + type Certificate []byte +// +// 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. +// func (certificate Certificate) Type() (cert_type int, err error) { - if len(certificate) < 1 { - err = errors.New("") + cert_len := len(certificate) + if cert_len < CERT_MIN_LENGTH { + log.WithFields(log.Fields{ + "certificate_bytes_length": cert_len, + "reason": "too short (len < CERT_MIN_LENGTH)", + }).Error("invalid certificate") + err = errors.New("error parsing certificate length: certificate is too short") return } cert_type = Integer([]byte{certificate[0]}) @@ -26,63 +66,70 @@ func (certificate Certificate) Type() (cert_type int, err error) { } // -// Look up the length of the certificate, reporting -// errors if the certificate is invalid or the specified -// length does not match the provided data. +// Look up the length of the Certificate, reporting errors if the certificate is +// shorter than the minimum certificate size or if the reported length doesn't +// match the provided data. // -func (certificate Certificate) Length() (int, error) { - if len(certificate) < 3 { - // log - return 0, errors.New("error parsing certificate length: certificate is too short") - } - length := Integer(certificate[1:3]) - inferred_len := length + 3 +func (certificate Certificate) Length() (length int, err error) { cert_len := len(certificate) + _, err = certificate.Type() + if err != nil { + return + } + length = Integer(certificate[1:CERT_MIN_LENGTH]) + inferred_len := length + CERT_MIN_LENGTH if inferred_len > cert_len { - // log - return length, errors.New("certificate parsing warning: certificate data is shorter than specified by length") + log.WithFields(log.Fields{ + "certificate_bytes_length": cert_len, + "certificate_length_field": length, + "expected_bytes_length": inferred_len, + "reason": "data shorter than specified", + }).Warn("certificate format warning") + err = errors.New("certificate parsing warning: certificate data is shorter than specified by length") } else if cert_len > inferred_len { - //log - return length, errors.New("certificate parsing warning: certificate contains data beyond length") + log.WithFields(log.Fields{ + "certificate_bytes_length": cert_len, + "certificate_length_field": length, + "expected_bytes_length": inferred_len, + "reason": "data longer than expected", + }).Error("certificate format warning") + err = errors.New("certificate parsing warning: certificate contains data beyond length") } - return length, nil + return } // -// Return the certificate data and any errors -// encountered by Length. +// Return the Certificate data and any errors encountered parsing the Certificate. // -func (certificate Certificate) Data() ([]byte, error) { +func (certificate Certificate) Data() (data []byte, err error) { length, err := certificate.Length() if err != nil { switch err.Error() { case "error parsing certificate length: certificate is too short": - return make([]byte, 0), err + return case "certificate parsing warning: certificate data is shorter than specified by length": - return certificate[3:], err + data = certificate[CERT_MIN_LENGTH:] + return case "certificate parsing warning: certificate contains data beyond length": - return certificate[3 : length+3], err + data = certificate[CERT_MIN_LENGTH : length+CERT_MIN_LENGTH] + return } } - return certificate[3:], nil + data = certificate[CERT_MIN_LENGTH:] + return } // -// Read a certificate from a slice of bytes, returning -// any extra data on the end of the slice. +// Read a Certificate from a slice of bytes, returning any extra data on the end of the slice +// and any errors if a valid Certificate could not be read. // -func ReadCertificate(data []byte) (Certificate, []byte, error) { - certificate := Certificate(data) +func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) { + certificate = Certificate(data) length, err := certificate.Length() - if err != nil { - switch err.Error() { - case "error parsing certificate length: certificate is too short": - return Certificate{}, make([]byte, 0), err - case "certificate parsing warning: certificate data is shorter than specified by length": - return certificate, make([]byte, 0), err - case "certificate parsing warning: certificate contains data beyond length": - return Certificate(certificate[:length+3]), certificate[length+3:], nil - } + 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:] + err = nil } - return certificate, make([]byte, 0), nil + return } diff --git a/lib/common/certificate_test.go b/lib/common/certificate_test.go index af2b6c0..bfd02d9 100644 --- a/lib/common/certificate_test.go +++ b/lib/common/certificate_test.go @@ -151,8 +151,8 @@ func TestReadCertificateWithInvalidLength(t *testing.T) { bytes := []byte{0x00, 0x00} cert, remainder, err := ReadCertificate(bytes) cert_len := len(cert) - if cert_len != 0 { - t.Fatal("ReadCertificate() did not return 0 length certificate with invalid length:", cert_len) + if cert_len != 2 { + t.Fatal("ReadCertificate() did not populate certificate even though data invalid", cert_len) } remainder_len := len(remainder) if remainder_len != 0 { diff --git a/lib/common/key_certificate.go b/lib/common/key_certificate.go index 7046349..e1ca17a 100644 --- a/lib/common/key_certificate.go +++ b/lib/common/key_certificate.go @@ -147,3 +147,22 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si } return } + +func (key_certificate KeyCertificate) SignatureSize() (size int) { + sizes := map[int]int{ + KEYCERT_SIGN_DSA_SHA1: 40, + KEYCERT_SIGN_P256: 64, + KEYCERT_SIGN_P384: 96, + KEYCERT_SIGN_P521: 132, + KEYCERT_SIGN_RSA2048: 256, + KEYCERT_SIGN_RSA3072: 384, + KEYCERT_SIGN_RSA4096: 512, + KEYCERT_SIGN_ED25519: 64, + KEYCERT_SIGN_ED25519PH: 64, + } + key_type, err := key_certificate.SigningPublicKeyType() + if err != nil { + return 0 + } + return sizes[int(key_type)] +} diff --git a/lib/common/lease_set.go b/lib/common/lease_set.go index d55b2be..984dbbf 100644 --- a/lib/common/lease_set.go +++ b/lib/common/lease_set.go @@ -25,7 +25,46 @@ func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error } func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicKey, err error) { - // check if the destination has a cert, if its a key cert, etc + destination, err := lease_set.Destination() + if err != nil { + return + } + offset := len(destination) + 256 + cert, err := destination.Certificate() + if err != nil { + return + } + cert_len, err := cert.Length() + if err != nil { + return + } + if len(lease_set) < offset+128 { + err = errors.New("") + return + } + if cert_len == 0 { + // No Certificate is present, return the 128 byte + // SigningPublicKey space as legacy DSA SHA1 SigningPublicKey. + var dsa_pk crypto.DSAPublicKey + copy(dsa_pk[:], lease_set[offset:offset+128]) + 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 = KeyCertificate(cert).ConstructSigningPublicKey(lease_set[offset : offset+128]) + } else { + // No Certificate is present, return the 128 byte + // SigningPublicKey space as legacy DSA SHA1 SigningPublicKey. + var dsa_pk crypto.DSAPublicKey + copy(dsa_pk[:], lease_set[offset:offset+128]) + signing_public_key = dsa_pk + } + + } return } @@ -42,32 +81,63 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) { return } -func (lease_set LeaseSet) Leases() []Lease { - leases := make([]Lease, 0) - offset := 0 +func (lease_set LeaseSet) Leases() (leases []Lease, err error) { + destination, err := lease_set.Destination() + if err != nil { + return + } + offset := len(destination) + 256 + 128 + 1 count, err := lease_set.LeaseCount() if err != nil { - return leases + return } - // read as many as possible, returning errors for i := 0; i < count; i++ { start := offset + (i * 44) - end := offset + (start + 44) + end := start + 44 + if len(lease_set) < end { + err = errors.New("") + return + } var lease Lease copy(lease[:], lease_set[start:end]) leases = append(leases, lease) } - return leases + return } func (lease_set LeaseSet) Signature() (signature Signature, err error) { + destination, err := lease_set.Destination() + if err != nil { + return + } + lease_count, err := lease_set.LeaseCount() + if err != nil { + return + } + start := len(destination) + 256 + 128 + 1 + (44 * lease_count) + cert, err := destination.Certificate() + if err != nil { + + } + cert_type, _ := cert.Type() + var end int + if cert_type == CERT_KEY { + end = start + KeyCertificate(cert).SignatureSize() + } else { + end = start + 40 + } + if len(lease_set) < end { + err = errors.New("") + return + } + copy(signature[:], lease_set[start:end]) return } func (lease_set LeaseSet) Verify() error { - //data_end := 387 + + //data_end := len(destination) + // 256 + - // lease_set.signingKeySize() + + // 128 + // 1 + // (44 * lease_set.LeaseCount()) //data := lease_set[:data_end] @@ -80,3 +150,7 @@ func (lease_set LeaseSet) Verify() error { //} return nil // verifier.Verify(data, lease_set.Signature()) } + +func (lease_set LeaseSet) OldestExpiration() (date Date, err error) { + return +}