From f409aa79e851f333aa5ce42823c68edc10193406 Mon Sep 17 00:00:00 2001 From: Hayden Parker Date: Sat, 13 Feb 2016 21:00:29 -0800 Subject: [PATCH] working on key certificates and keys and cert --- .gitignore | 4 +- go_i2p_suite_test.go | 13 +++ lib/common/certificate.go | 39 ++------ lib/common/certificate_test.go | 6 +- lib/common/destination.go | 2 +- lib/common/key_certificate.go | 157 +++++++++++++++++++++++++++------ lib/common/keys_and_cert.go | 106 ++++++++++++++++------ lib/common/lease_set.go | 10 +-- lib/common/router_identity.go | 2 +- lib/common/router_info.go | 26 +++--- lib/common/router_info_test.go | 22 +++++ lib/crypto/sign.go | 5 ++ 12 files changed, 287 insertions(+), 105 deletions(-) create mode 100644 go_i2p_suite_test.go diff --git a/.gitignore b/.gitignore index 298d9cf..f9f7afd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *~ \#* -.\#* \ No newline at end of file +.\#* +.*.sw? +*.coverprofile diff --git a/go_i2p_suite_test.go b/go_i2p_suite_test.go new file mode 100644 index 0000000..ed542b0 --- /dev/null +++ b/go_i2p_suite_test.go @@ -0,0 +1,13 @@ +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 9bd506f..195a2f9 100644 --- a/lib/common/certificate.go +++ b/lib/common/certificate.go @@ -4,6 +4,7 @@ import ( "errors" ) +// Certificate Types const ( CERT_NULL = iota CERT_HASHCASH @@ -13,25 +14,15 @@ const ( CERT_KEY ) -const ( - KEYCERT_SIGN_DSA_SHA1 = iota - KEYCERT_SIGN_P256 - KEYCERT_SIGN_P384 - KEYCERT_SIGN_P521 - KEYCERT_SIGN_RSA2048 - KEYCERT_SIGN_RSA3072 - KEYCERT_SIGN_RSA4096 - KEYCERT_SIGN_ED25519 -) - -const ( - KEYCERT_CRYPTO_ELG = iota -) - type Certificate []byte -func (certificate Certificate) Type() byte { - return certificate[0] +func (certificate Certificate) Type() (cert_type int, err error) { + if len(certificate) < 1 { + err = errors.New("") + return + } + cert_type = Integer([]byte{certificate[0]}) + return } // @@ -76,20 +67,6 @@ func (certificate Certificate) Data() ([]byte, error) { return certificate[3:], nil } -func (certificate Certificate) SignatureSize() 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, - } - return sizes[int(certificate.Type())] -} - // // Read a certificate from a slice of bytes, returning // any extra data on the end of the slice. diff --git a/lib/common/certificate_test.go b/lib/common/certificate_test.go index be52dc3..af2b6c0 100644 --- a/lib/common/certificate_test.go +++ b/lib/common/certificate_test.go @@ -5,9 +5,13 @@ import "testing" func TestCertificateTypeIsFirstByte(t *testing.T) { bytes := []byte{0x03, 0x00, 0x00} certificate := Certificate(bytes) - if certificate.Type() != 0x03 { + cert_type, err := certificate.Type() + if cert_type != 3 { t.Fatal("certificate.Type() is not first byte") } + if err != nil { + t.Fatal("certificate.Type returned error on valid data:", err) + } } func TestCertificateLengthCorrect(t *testing.T) { diff --git a/lib/common/destination.go b/lib/common/destination.go index 27f6ea2..fef26a4 100644 --- a/lib/common/destination.go +++ b/lib/common/destination.go @@ -9,7 +9,7 @@ import ( type Destination []byte -func (destination Destination) PublicKey() (crypto.ElgPublicKey, error) { +func (destination Destination) PublicKey() (crypto.PublicKey, error) { return KeysAndCert(destination).PublicKey() } diff --git a/lib/common/key_certificate.go b/lib/common/key_certificate.go index 2ad23ff..7046349 100644 --- a/lib/common/key_certificate.go +++ b/lib/common/key_certificate.go @@ -1,46 +1,149 @@ package common import ( + "errors" "github.com/bounce-chat/go-i2p/lib/crypto" ) +// Key Certificate Signing Key Types +const ( + KEYCERT_SIGN_DSA_SHA1 = iota + KEYCERT_SIGN_P256 + KEYCERT_SIGN_P384 + KEYCERT_SIGN_P521 + KEYCERT_SIGN_RSA2048 + KEYCERT_SIGN_RSA3072 + KEYCERT_SIGN_RSA4096 + KEYCERT_SIGN_ED25519 + KEYCERT_SIGN_ED25519PH +) + +// Key Certificate Public Key Types +const ( + KEYCERT_CRYPTO_ELG = iota +) + +// SigningPublicKey sizes for Signing Key Types +const ( + KEYCERT_SIGN_DSA_SHA1_SIZE = 128 + KEYCERT_SIGN_P256_SIZE = 64 + KEYCERT_SIGN_P384_SIZE = 96 + KEYCERT_SIGN_P521_SIZE = 132 + KEYCERT_SIGN_RSA2048_SIZE = 256 + KEYCERT_SIGN_RSA3072_SIZE = 384 + KEYCERT_SIGN_RSA4096_SIZE = 512 + KEYCERT_SIGN_ED25519_SIZE = 32 + KEYCERT_SIGN_ED25519PH_SIZE = 32 +) + +// PublicKey sizes for Public Key Types +const ( + KEYCERT_CRYPTO_ELG_SIZE = 256 +) + type KeyCertificate []byte -func (key_certificate KeyCertificate) Type() byte { - return Certificate(key_certificate).Type() -} - +// +// The data contained in the Certificate. +// func (key_certificate KeyCertificate) Data() ([]byte, error) { return Certificate(key_certificate).Data() } -// get the signing public key from this key cert -func (key_certificate KeyCertificate) SigningPublicKey() (k crypto.SigningPublicKey) { +// +// +// +func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int, err error) { data, err := key_certificate.Data() if err != nil { return } - ktype := Integer(data[:2]) - // set data to be the key data now - data = data[4:] - // determine the key type - if ktype == KEYCERT_SIGN_DSA_SHA1 { - var pk crypto.DSAPublicKey - copy(pk[:], data[:pk.Len()]) - k = pk - } else if ktype == KEYCERT_SIGN_P256 { - var pk crypto.ECP256PublicKey - copy(pk[:], data[:pk.Len()]) - k = pk - } else if ktype == KEYCERT_SIGN_P384 { - var pk crypto.ECP384PublicKey - copy(pk[:], data[:pk.Len()]) - k = pk - } else if ktype == KEYCERT_SIGN_P521 { - var pk crypto.ECP521PublicKey - copy(pk[:], data[:pk.Len()]) - k = pk + if len(data) < 2 { + err = errors.New("") + return + } + signing_pubkey_type = Integer(data[:2]) + return +} + +// +// +// +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("") + return + } + pubkey_type = Integer(data[2:4]) + return +} + +// +// +// +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("") + return + } + switch key_type { + case KEYCERT_CRYPTO_ELG: + var elg_key crypto.ElgPublicKey + copy(elg_key[:], data[256-KEYCERT_CRYPTO_ELG_SIZE:256]) + public_key = elg_key + } + return +} + +// +// +// +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("") + 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]) + signing_public_key = dsa_key + case KEYCERT_SIGN_P256: + var ec_key crypto.ECP256PublicKey + copy(ec_key[:], data[128-KEYCERT_SIGN_P256_SIZE:128]) + signing_public_key = ec_key + case KEYCERT_SIGN_P384: + var ec_key crypto.ECP384PublicKey + copy(ec_key[:], data[128-KEYCERT_SIGN_P384_SIZE:128]) + signing_public_key = ec_key + case KEYCERT_SIGN_P521: + var ec_key crypto.ECP521PublicKey + extra := KEYCERT_SIGN_P521_SIZE - 128 + copy(ec_key[:], data) + copy(ec_key[128:], key_certificate[4:4+extra]) + signing_public_key = ec_key + case KEYCERT_SIGN_RSA2048: + //var rsa_key crypto.RSA2048PublicKey + //extra := KEYCERT_SIGN_RSA2048_SIZE - 128 + //copy(rsa_key[:], data) + //copy(rsa_key[128:], key_certificate[4:4+extra]) + //signing_public_key = rsa_key + case KEYCERT_SIGN_RSA3072: + case KEYCERT_SIGN_RSA4096: + case KEYCERT_SIGN_ED25519: + case KEYCERT_SIGN_ED25519PH: } - // TODO: rsa/eddsa return } diff --git a/lib/common/keys_and_cert.go b/lib/common/keys_and_cert.go index c376909..8a51562 100644 --- a/lib/common/keys_and_cert.go +++ b/lib/common/keys_and_cert.go @@ -7,54 +7,110 @@ import ( type KeysAndCert []byte -func (keys_and_cert KeysAndCert) PublicKey() (key crypto.ElgPublicKey, err error) { - keys_cert_len := len(keys_and_cert) - if keys_cert_len < 387 { - if keys_cert_len < 256 { - err = errors.New("error parsing KeysAndCert: data smaller than ElgPublicKey size") - return - } - err = errors.New("warning parsing KeysAndCert: data is smaller than minimum valid size") +// +// Return the ElgPublicKey for this KeysAndCert, reading from the Key Certificate +// if it is present first, then the first 256 bytes of the KeysAndCert. +// +func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) { + cert, err := keys_and_cert.Certificate() + cert_len, err := cert.Length() + if err != nil { + return + } + if cert_len == 0 { + // No Certificate is present, return the 256 byte + // PublicKey space as ElgPublicKey. + var elg_key crypto.ElgPublicKey + copy(keys_and_cert[:256], 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[:256]) + } else { + // Key Certificate is not present, return the 256 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[:]) + key = elg_key + } + } - copy(keys_and_cert[:256], key[:]) return } +// +// Return the SigningPublicKey for this KeysAndCert, reading from the Key Certificate +// if it is present first, then the SigningPublicKey space in the KeysAndCert. +// func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) { cert, err := keys_and_cert.Certificate() - switch err.Error() { - case "": + cert_len, err := cert.Length() + if err != nil { + return } - if cert.Type() == CERT_KEY { - signing_public_key = KeyCertificate(cert).SigningPublicKey() + 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[:], keys_and_cert[256:256+128]) + signing_public_key = dsa_pk } else { - // Only Key Certificates are currently used: - // https://geti2p.net/en/docs/spec/common-structures#type_Certificate + // 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 = KeyCertificate(cert).ConstructSigningPublicKey(keys_and_cert[256 : 256+128]) + } else { + // Key Certificate is not present, return the 128 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]) + signing_public_key = dsa_pk + } + } return } +// +// Return the Certificate cointained in the KeysAndCert and 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 { - if keys_cert_len < 384 { - err = errors.New("error parsing KeysAndCert: data smaller than needed for Certificate") - return - } err = errors.New("warning parsing KeysAndCert: data is smaller than minimum valid size") + return } - copy(keys_and_cert[256+128:], cert) + cert, _, err = ReadCertificate(keys_and_cert[256+128:]) return } -func ReadKeysAndCert(data []byte) (KeysAndCert, []byte, error) { - var keys_and_cert KeysAndCert +// +// +// +func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) { + if len(data) < 387 { + err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size") + return + } copy(data[:387], keys_and_cert) cert, _ := keys_and_cert.Certificate() n, err := cert.Length() if err != nil { - return keys_and_cert, data, err + remainder = data[387:] + return } - keys_and_cert = append(keys_and_cert, data[387:n]...) - return keys_and_cert, data[387+n:], nil + keys_and_cert = append(keys_and_cert, data[387:n+3]...) + remainder = data[387+n+3:] + return } diff --git a/lib/common/lease_set.go b/lib/common/lease_set.go index 0455989..a123e26 100644 --- a/lib/common/lease_set.go +++ b/lib/common/lease_set.go @@ -46,11 +46,11 @@ func (lease_set LeaseSet) Signature() []byte { lease_set.signingKeySize() + 1 + (44 * lease_set.LeaseCount()) - sig_cert, _ := lease_set. - Destination(). - Certificate() - sig_size := sig_cert.SignatureSize() - return lease_set[data_end : data_end+sig_size] + //sig_cert, _ := lease_set. + // Destination(). + // Certificate() + //sig_size, _ := sig_cert.SignatureSize() + return lease_set[data_end : data_end+128] //sig_size] } func (lease_set LeaseSet) Verify() error { diff --git a/lib/common/router_identity.go b/lib/common/router_identity.go index ec91d76..5702d9e 100644 --- a/lib/common/router_identity.go +++ b/lib/common/router_identity.go @@ -6,7 +6,7 @@ import ( type RouterIdentity []byte -func (router_identity RouterIdentity) PublicKey() (crypto.ElgPublicKey, error) { +func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) { return KeysAndCert(router_identity).PublicKey() } diff --git a/lib/common/router_info.go b/lib/common/router_info.go index dc029aa..1faf842 100644 --- a/lib/common/router_info.go +++ b/lib/common/router_info.go @@ -22,7 +22,7 @@ func (router_info RouterInfo) RouterIdentity() (router_identity RouterIdentity, func (router_info RouterInfo) Published() (date Date, err error) { _, remainder, _ := ReadRouterIdentity(router_info) if len(remainder) < 8 { - err = errors.New("") + err = errors.New("error parsing date: not enough data") return } copy(remainder[:8], date[:]) @@ -36,7 +36,7 @@ func (router_info RouterInfo) Published() (date Date, err error) { func (router_info RouterInfo) RouterAddressCount() (count int, err error) { _, remainder, _ := ReadRouterIdentity(router_info) if len(remainder) < 9 { - err = errors.New("") + err = errors.New("error parsing router addresses: not enough data") return } count = Integer([]byte{remainder[8]}) @@ -50,7 +50,7 @@ func (router_info RouterInfo) RouterAddressCount() (count int, err error) { func (router_info RouterInfo) RouterAddresses() (router_addresses []RouterAddress, err error) { _, remainder, _ := ReadRouterIdentity(router_info) if len(remainder) < 9 { - err = errors.New("") + err = errors.New("error parsing router addresses: not enough data") return } remaining := router_info[9:] @@ -79,7 +79,7 @@ func (router_info RouterInfo) PeerSize() int { } // -// +// Return the Options Mapping inside this RouterInfo. // func (router_info RouterInfo) Options() Mapping { head := router_info.optionsLocation() @@ -88,18 +88,17 @@ func (router_info RouterInfo) Options() Mapping { } // -// +// Return the 40 bytes that follow the Mapping in the RouterInfo. // func (router_info RouterInfo) Signature() []byte { - offset := router_info.optionsLocation() + router_info.optionsSize() - router_identity, _ := router_info.RouterIdentity() - cert, _ := router_identity.Certificate() - sig_size := cert.SignatureSize() - return router_info[offset:sig_size] + head := router_info.optionsLocation() + size := head + router_info.optionsSize() + return router_info[head+size : head+size+40] } // -// +// Used to determine where in the RouterInfo the Mapping +// data begins for parsing. // func (router_info RouterInfo) optionsLocation() int { offset := 9 @@ -114,9 +113,10 @@ func (router_info RouterInfo) optionsLocation() int { } // -// +// Used to determine the size of the options in the RouterInfo +// for parsing. // func (router_info RouterInfo) optionsSize() int { head := router_info.optionsLocation() - return Integer(router_info[head : head+1]) + return Integer(router_info[head:head+1]) + 1 } diff --git a/lib/common/router_info_test.go b/lib/common/router_info_test.go index 805d0c7..69d46ba 100644 --- a/lib/common/router_info_test.go +++ b/lib/common/router_info_test.go @@ -1 +1,23 @@ package common + +import ( + "testing" +) + +func TestRouterIdentityReadsRouterIdentity(t *testing.T) { +} + +func TestRouterIdentityWithZeroLenSlice(t *testing.T) { +} + +func TestRouterIdentityWithInvalidData(t *testing.T) { +} + +func TestPublishedReturnsCorrectDate(t *testing.T) { +} + +func TestPublishedWithZeroLenSlice(t *testing.T) { +} + +func TestPublishedWithInvalidData(t *testing.T) { +} diff --git a/lib/crypto/sign.go b/lib/crypto/sign.go index 1f98e6b..b3b4ccb 100644 --- a/lib/crypto/sign.go +++ b/lib/crypto/sign.go @@ -26,6 +26,11 @@ type SigningPublicKey interface { Len() int } +type PublicKey interface { + Len() int + NewEncrypter() (Encrypter, error) +} + // type for signing data type Signer interface { // sign data with our private key by calling SignHash after hashing the data we are given