working on key certificates and keys and cert

This commit is contained in:
Hayden Parker
2016-02-13 21:00:29 -08:00
parent 7e9aee0714
commit f409aa79e8
12 changed files with 287 additions and 105 deletions

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
*~ *~
\#* \#*
.\#* .\#*
.*.sw?
*.coverprofile

13
go_i2p_suite_test.go Normal file
View File

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

View File

@ -4,6 +4,7 @@ import (
"errors" "errors"
) )
// Certificate Types
const ( const (
CERT_NULL = iota CERT_NULL = iota
CERT_HASHCASH CERT_HASHCASH
@ -13,25 +14,15 @@ const (
CERT_KEY 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 type Certificate []byte
func (certificate Certificate) Type() byte { func (certificate Certificate) Type() (cert_type int, err error) {
return certificate[0] 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 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 // 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.

View File

@ -5,9 +5,13 @@ import "testing"
func TestCertificateTypeIsFirstByte(t *testing.T) { func TestCertificateTypeIsFirstByte(t *testing.T) {
bytes := []byte{0x03, 0x00, 0x00} bytes := []byte{0x03, 0x00, 0x00}
certificate := Certificate(bytes) certificate := Certificate(bytes)
if certificate.Type() != 0x03 { cert_type, err := certificate.Type()
if cert_type != 3 {
t.Fatal("certificate.Type() is not first byte") 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) { func TestCertificateLengthCorrect(t *testing.T) {

View File

@ -9,7 +9,7 @@ import (
type Destination []byte type Destination []byte
func (destination Destination) PublicKey() (crypto.ElgPublicKey, error) { func (destination Destination) PublicKey() (crypto.PublicKey, error) {
return KeysAndCert(destination).PublicKey() return KeysAndCert(destination).PublicKey()
} }

View File

@ -1,46 +1,149 @@
package common package common
import ( import (
"errors"
"github.com/bounce-chat/go-i2p/lib/crypto" "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 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) { func (key_certificate KeyCertificate) Data() ([]byte, error) {
return Certificate(key_certificate).Data() 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() data, err := key_certificate.Data()
if err != nil { if err != nil {
return return
} }
ktype := Integer(data[:2]) if len(data) < 2 {
// set data to be the key data now err = errors.New("")
data = data[4:] return
// determine the key type }
if ktype == KEYCERT_SIGN_DSA_SHA1 { signing_pubkey_type = Integer(data[:2])
var pk crypto.DSAPublicKey return
copy(pk[:], data[:pk.Len()]) }
k = pk
} else if ktype == KEYCERT_SIGN_P256 { //
var pk crypto.ECP256PublicKey //
copy(pk[:], data[:pk.Len()]) //
k = pk func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int, err error) {
} else if ktype == KEYCERT_SIGN_P384 { data, err := key_certificate.Data()
var pk crypto.ECP384PublicKey if err != nil {
copy(pk[:], data[:pk.Len()]) return
k = pk }
} else if ktype == KEYCERT_SIGN_P521 { if len(data) < 4 {
var pk crypto.ECP521PublicKey err = errors.New("")
copy(pk[:], data[:pk.Len()]) return
k = pk }
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 return
} }

View File

@ -7,54 +7,110 @@ import (
type KeysAndCert []byte type KeysAndCert []byte
func (keys_and_cert KeysAndCert) PublicKey() (key crypto.ElgPublicKey, err error) { //
keys_cert_len := len(keys_and_cert) // Return the ElgPublicKey for this KeysAndCert, reading from the Key Certificate
if keys_cert_len < 387 { // if it is present first, then the first 256 bytes of the KeysAndCert.
if keys_cert_len < 256 { //
err = errors.New("error parsing KeysAndCert: data smaller than ElgPublicKey size") func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) {
return cert, err := keys_and_cert.Certificate()
} cert_len, err := cert.Length()
err = errors.New("warning parsing KeysAndCert: data is smaller than minimum valid size") 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
} }
//
// 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) { func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) {
cert, err := keys_and_cert.Certificate() cert, err := keys_and_cert.Certificate()
switch err.Error() { cert_len, err := cert.Length()
case "": if err != nil {
return
} }
if cert.Type() == CERT_KEY { if cert_len == 0 {
signing_public_key = KeyCertificate(cert).SigningPublicKey() // 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 { } else {
// Only Key Certificates are currently used: // A Certificate is present in this KeysAndCert
// https://geti2p.net/en/docs/spec/common-structures#type_Certificate 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
} }
//
// 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) { func (keys_and_cert KeysAndCert) Certificate() (cert Certificate, err error) {
keys_cert_len := len(keys_and_cert) keys_cert_len := len(keys_and_cert)
if keys_cert_len < 387 { 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") 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 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) copy(data[:387], keys_and_cert)
cert, _ := keys_and_cert.Certificate() cert, _ := keys_and_cert.Certificate()
n, err := cert.Length() n, err := cert.Length()
if err != nil { if err != nil {
return keys_and_cert, data, err remainder = data[387:]
return
} }
keys_and_cert = append(keys_and_cert, data[387:n]...) keys_and_cert = append(keys_and_cert, data[387:n+3]...)
return keys_and_cert, data[387+n:], nil remainder = data[387+n+3:]
return
} }

View File

@ -46,11 +46,11 @@ func (lease_set LeaseSet) Signature() []byte {
lease_set.signingKeySize() + lease_set.signingKeySize() +
1 + 1 +
(44 * lease_set.LeaseCount()) (44 * lease_set.LeaseCount())
sig_cert, _ := lease_set. //sig_cert, _ := lease_set.
Destination(). // Destination().
Certificate() // Certificate()
sig_size := sig_cert.SignatureSize() //sig_size, _ := sig_cert.SignatureSize()
return lease_set[data_end : data_end+sig_size] return lease_set[data_end : data_end+128] //sig_size]
} }
func (lease_set LeaseSet) Verify() error { func (lease_set LeaseSet) Verify() error {

View File

@ -6,7 +6,7 @@ import (
type RouterIdentity []byte type RouterIdentity []byte
func (router_identity RouterIdentity) PublicKey() (crypto.ElgPublicKey, error) { func (router_identity RouterIdentity) PublicKey() (crypto.PublicKey, error) {
return KeysAndCert(router_identity).PublicKey() return KeysAndCert(router_identity).PublicKey()
} }

View File

@ -22,7 +22,7 @@ func (router_info RouterInfo) RouterIdentity() (router_identity RouterIdentity,
func (router_info RouterInfo) Published() (date Date, err error) { func (router_info RouterInfo) Published() (date Date, err error) {
_, remainder, _ := ReadRouterIdentity(router_info) _, remainder, _ := ReadRouterIdentity(router_info)
if len(remainder) < 8 { if len(remainder) < 8 {
err = errors.New("") err = errors.New("error parsing date: not enough data")
return return
} }
copy(remainder[:8], date[:]) 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) { func (router_info RouterInfo) RouterAddressCount() (count int, err error) {
_, remainder, _ := ReadRouterIdentity(router_info) _, remainder, _ := ReadRouterIdentity(router_info)
if len(remainder) < 9 { if len(remainder) < 9 {
err = errors.New("") err = errors.New("error parsing router addresses: not enough data")
return return
} }
count = Integer([]byte{remainder[8]}) 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) { func (router_info RouterInfo) RouterAddresses() (router_addresses []RouterAddress, err error) {
_, remainder, _ := ReadRouterIdentity(router_info) _, remainder, _ := ReadRouterIdentity(router_info)
if len(remainder) < 9 { if len(remainder) < 9 {
err = errors.New("") err = errors.New("error parsing router addresses: not enough data")
return return
} }
remaining := router_info[9:] 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 { func (router_info RouterInfo) Options() Mapping {
head := router_info.optionsLocation() 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 { func (router_info RouterInfo) Signature() []byte {
offset := router_info.optionsLocation() + router_info.optionsSize() head := router_info.optionsLocation()
router_identity, _ := router_info.RouterIdentity() size := head + router_info.optionsSize()
cert, _ := router_identity.Certificate() return router_info[head+size : head+size+40]
sig_size := cert.SignatureSize()
return router_info[offset:sig_size]
} }
// //
// // Used to determine where in the RouterInfo the Mapping
// data begins for parsing.
// //
func (router_info RouterInfo) optionsLocation() int { func (router_info RouterInfo) optionsLocation() int {
offset := 9 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 { func (router_info RouterInfo) optionsSize() int {
head := router_info.optionsLocation() head := router_info.optionsLocation()
return Integer(router_info[head : head+1]) return Integer(router_info[head:head+1]) + 1
} }

View File

@ -1 +1,23 @@
package common 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) {
}

View File

@ -26,6 +26,11 @@ type SigningPublicKey interface {
Len() int Len() int
} }
type PublicKey interface {
Len() int
NewEncrypter() (Encrypter, error)
}
// type for signing data // type for signing data
type Signer interface { type Signer interface {
// sign data with our private key by calling SignHash after hashing the data we are given // sign data with our private key by calling SignHash after hashing the data we are given