more lease set work, certificate completed

This commit is contained in:
Hayden Parker
2016-02-14 22:28:20 -08:00
parent a64fe87dbe
commit e19d6fa0ab
5 changed files with 190 additions and 63 deletions

View File

@ -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")
}

View File

@ -1,7 +1,34 @@
package common 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 ( import (
"errors" "errors"
log "github.com/Sirupsen/logrus"
) )
// Certificate Types // Certificate Types
@ -14,11 +41,24 @@ const (
CERT_KEY CERT_KEY
) )
const (
CERT_MIN_LENGTH = 3
)
type Certificate []byte 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) { func (certificate Certificate) Type() (cert_type int, err error) {
if len(certificate) < 1 { cert_len := len(certificate)
err = errors.New("") 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 return
} }
cert_type = Integer([]byte{certificate[0]}) 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 // Look up the length of the Certificate, reporting errors if the certificate is
// errors if the certificate is invalid or the specified // shorter than the minimum certificate size or if the reported length doesn't
// length does not match the provided data. // match the provided data.
// //
func (certificate Certificate) Length() (int, error) { func (certificate Certificate) Length() (length int, err 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
cert_len := len(certificate) 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 { if inferred_len > cert_len {
// log log.WithFields(log.Fields{
return length, errors.New("certificate parsing warning: certificate data is shorter than specified by length") "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 { } else if cert_len > inferred_len {
//log log.WithFields(log.Fields{
return length, errors.New("certificate parsing warning: certificate contains data beyond length") "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 // Return the Certificate data and any errors encountered parsing the Certificate.
// encountered by Length.
// //
func (certificate Certificate) Data() ([]byte, error) { func (certificate Certificate) Data() (data []byte, err error) {
length, err := certificate.Length() 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 make([]byte, 0), err 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":
return certificate[3:], err data = certificate[CERT_MIN_LENGTH:]
return
case "certificate parsing warning: certificate contains data beyond length": 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 // Read a Certificate from a slice of bytes, returning any extra data on the end of the slice
// 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) { func ReadCertificate(data []byte) (certificate Certificate, remainder []byte, err error) {
certificate := Certificate(data) certificate = Certificate(data)
length, err := certificate.Length() length, err := certificate.Length()
if err != nil { if err != nil && err.Error() == "certificate parsing warning: certificate contains data beyond length" {
switch err.Error() { certificate = Certificate(data[:length+CERT_MIN_LENGTH])
case "error parsing certificate length: certificate is too short": remainder = data[length+CERT_MIN_LENGTH:]
return Certificate{}, make([]byte, 0), err err = nil
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
}
} }
return certificate, make([]byte, 0), nil return
} }

View File

@ -151,8 +151,8 @@ func TestReadCertificateWithInvalidLength(t *testing.T) {
bytes := []byte{0x00, 0x00} bytes := []byte{0x00, 0x00}
cert, remainder, err := ReadCertificate(bytes) cert, remainder, err := ReadCertificate(bytes)
cert_len := len(cert) cert_len := len(cert)
if cert_len != 0 { if cert_len != 2 {
t.Fatal("ReadCertificate() did not return 0 length certificate with invalid length:", cert_len) t.Fatal("ReadCertificate() did not populate certificate even though data invalid", cert_len)
} }
remainder_len := len(remainder) remainder_len := len(remainder)
if remainder_len != 0 { if remainder_len != 0 {

View File

@ -147,3 +147,22 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
} }
return 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)]
}

View File

@ -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) { 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 return
} }
@ -42,32 +81,63 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) {
return return
} }
func (lease_set LeaseSet) Leases() []Lease { func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
leases := make([]Lease, 0) destination, err := lease_set.Destination()
offset := 0 if err != nil {
return
}
offset := len(destination) + 256 + 128 + 1
count, err := lease_set.LeaseCount() count, err := lease_set.LeaseCount()
if err != nil { if err != nil {
return leases return
} }
// read as many as possible, returning errors
for i := 0; i < count; i++ { for i := 0; i < count; i++ {
start := offset + (i * 44) start := offset + (i * 44)
end := offset + (start + 44) end := start + 44
if len(lease_set) < end {
err = errors.New("")
return
}
var lease Lease var lease Lease
copy(lease[:], lease_set[start:end]) copy(lease[:], lease_set[start:end])
leases = append(leases, lease) leases = append(leases, lease)
} }
return leases return
} }
func (lease_set LeaseSet) Signature() (signature Signature, err error) { 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 return
} }
func (lease_set LeaseSet) Verify() error { func (lease_set LeaseSet) Verify() error {
//data_end := 387 + //data_end := len(destination) +
// 256 + // 256 +
// lease_set.signingKeySize() + // 128 +
// 1 + // 1 +
// (44 * lease_set.LeaseCount()) // (44 * lease_set.LeaseCount())
//data := lease_set[:data_end] //data := lease_set[:data_end]
@ -80,3 +150,7 @@ func (lease_set LeaseSet) Verify() error {
//} //}
return nil // verifier.Verify(data, lease_set.Signature()) return nil // verifier.Verify(data, lease_set.Signature())
} }
func (lease_set LeaseSet) OldestExpiration() (date Date, err error) {
return
}