8 Commits

Author SHA1 Message Date
idk
f113977419 refactor certs, keycerts 2022-04-27 10:50:10 -04:00
idk
86dc323348 refactor certs, keycerts 2022-04-27 10:48:59 -04:00
idk
a80c9973f9 Merge pull request #1 from eyedeekay/circleci-project-setup
Add .circleci/config.yml
2021-05-11 10:46:52 -07:00
idk
7adf3d7577 Add .circleci/config.yml 2021-05-11 07:34:35 -07:00
idk
42be0d6b5c Merge pull request #1 from kpetku/drop-libsodium-dep
remove libsodium dependency in favor of the native go/crypto ed25519 library
2021-05-07 20:07:10 -07:00
d837630ff6 remove libsodium dependency in favor of the native go/crypto ed25519 library 2021-05-07 21:02:54 -04:00
idk
590d576b74 Merge branch 'checklist' into 'master'
Checklist update: Add items, remove NTCP 1

See merge request idk/go-i2p!1
2021-04-27 14:10:02 +00:00
zzz
fa86f8e3b3 Checklist update: Add items, remove NTCP 1 2021-04-27 10:03:52 -04:00
34 changed files with 815 additions and 1319 deletions

26
.circleci/config.yml Normal file
View File

@@ -0,0 +1,26 @@
# Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/golang:1.15.8
steps:
- checkout
- restore_cache:
keys:
- go-mod-v4-{{ checksum "go.sum" }}
- run:
name: Install Dependencies
command: go mod download
- save_cache:
key: go-mod-v4-{{ checksum "go.sum" }}
paths:
- "/go/pkg/mod"
- run:
name: Run tests
command: |
mkdir -p /tmp/test-reports
gotestsum --junitfile /tmp/test-reports/unit-tests.xml
- store_test_results:
path: /tmp/test-reports

2
.gitignore vendored
View File

@@ -5,4 +5,4 @@
*.coverprofile
*exportable-fuzz.zip
go-i2p
*.exe*.log
*.exe

9
.vscode/launch.json vendored
View File

@@ -1,9 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
]
}

View File

@@ -9,7 +9,6 @@ Install required dependencies
This example assumes Ubuntu 16.04
```sh
sudo apt-get install pkg-config libsodium-dev
go get github.com/hkparker/go-i2p
go get github.com/Sirupsen/logrus
go get github.com/stretchr/testify/assert

View File

@@ -19,13 +19,7 @@ $(EXE):
$(GO) build -v -o $(EXE)
test:
$(GO) test -failfast ./...
$(GO) test -v -failfast ./lib/common
clean:
$(GO) clean -v
fmt:
find . -name '*.go' -exec gofmt -w -s {} \;
testcommon:
$(GO) test -failfast ./lib/common/...

View File

@@ -4,35 +4,17 @@ A pure Go implementation of the I2P router.
## Status
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.
go-i2p is in early development.
### 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.
- Clients
- [ ] Datagrams
- [ ] I2CP
- [ ] Message routing
- [ ] SAM
- [ ] Streaming
- [ ] Tunnel Manager
- Cryptographic primitives
- Signing
- [ ] ECDSA_SHA256_P256
@@ -48,38 +30,19 @@ this will happen in /lib/common.
- [ ] RSA_SHA384_3072
- [ ] RSA_SHA512_4096
- [ ] Ed25519
- [x] ElGamal
- [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
- [ ] Red25519
- [ ] ElGamal
- [ ] AES256
- [ ] X25519
- [ ] ChaCha20/Poly1305
- [ ] Elligator2
- [ ] HKDF
- [ ] HMAC
- [ ] Noise subsystem
- End-to-End Crypto
- [ ] Garlic messages
- [ ] ElGamal/AES+SessionTag
- [ ] Ratchet/X25519
- I2NP
- [ ] Message parsing
- [ ] Message handling
@@ -92,17 +55,26 @@ this will happen in /lib/common.
- [ ] Exploration
- [ ] Publishing
- [ ] Floodfill
- [ ] LS2 and Encrypted Leasesets
- Transports
- [ ] Transport manager
- NTCP
- [ ] Handshake
- [ ] Session tracking
- [ ] Automatic session creation
- NTCP2
- [ ] Handshake
- [ ] Session tracking
- [ ] Automatic session creation
- [ ] SSU
- SSU
- [ ] Handshake
- [ ] Session tracking
- [ ] Automatic session creation
- [ ] Peer Tests
- [ ] Introducers
- Tunnels
- [ ] Building
- [ ] Build Message Crypto (ElGamal)
- [ ] Build Message Crypto (ECIES)
- [ ] Participating
- [ ] Tunnel Message Crypto
- [ ] Tunnel Message Fragmentation/Reassembly
## Contributing

View File

@@ -27,7 +27,7 @@ payload :: data
*/
import (
"errors"
"fmt"
log "github.com/sirupsen/logrus"
)
@@ -47,49 +47,42 @@ const (
CERT_MIN_SIZE = 3
)
type CertificateInterface interface {
Cert() []byte
Length() (length int, err error)
Data() (data []byte, err error)
Type() (cert_type int, type_bytes []byte, err error)
SignatureSize() (size int)
}
type Certificate struct {
CertType *Integer
CertLen *Integer
CertBytes []byte
kind Integer
leng Integer
payl []byte
}
var ci CertificateInterface = &Certificate{}
func (certificate Certificate) SignatureSize() (size int) {
return 40
func (c *Certificate) RawBytes() []byte {
bytes := c.kind.Bytes()
bytes = append(bytes, c.leng.Bytes()...)
bytes = append(bytes, c.payl...)
return bytes
}
func (certificate Certificate) Cert() []byte {
var ret []byte
ret = append(ret, certificate.CertType.Bytes()...)
l, _ := certificate.Length()
//if err != nil && err.Error() != "certificate parsing warning: certificate data is shorter than specified by length" {
//}
data, _ := certificate.Data()
if l != 0 && len(data) != 0 {
ret = append(ret, certificate.CertLen.Bytes()...)
ret = append(ret, data...)
} else {
ret = append(ret, certificate.CertLen.Bytes()...)
}
//log.Println("\n\n CERTIFICATE: ", ret, l+CERT_MIN_SIZE, err)
return ret //[:l+CERT_MIN_SIZE]
func (c *Certificate) ExcessBytes() []byte {
return c.payl[c.leng.Int():]
}
func (c *Certificate) Bytes() []byte {
bytes := c.kind.Bytes()
bytes = append(bytes, c.leng.Bytes()...)
bytes = append(bytes, c.Data()...)
return bytes
}
func (c *Certificate) length() (cert_len int) {
cert_len = len(c.Bytes())
return
}
//
// 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, type_bytes []byte, err error) {
return certificate.CertType.Value(), certificate.CertType.Bytes(), nil
func (c *Certificate) Type() (cert_type int) {
cert_type = c.kind.Int()
return
}
//
@@ -97,124 +90,94 @@ func (certificate Certificate) Type() (cert_type int, type_bytes []byte, err err
// shorter than the minimum certificate size or if the reported length doesn't
// match the provided data.
//
func (certificate Certificate) Length() (length int, err error) {
if certificate.CertLen.Value() < 1 {
log.WithFields(log.Fields{
"at": "(Certificate) Length",
"certificate_bytes_length": certificate.CertLen,
"certificate_min_size": CERT_MIN_SIZE - 1,
"reason": "certificate is too short",
}).Warn("certificate format warning")
err = errors.New("error parsing certificate length: certificate is too short")
}
if certificate.CertLen.Value() > 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")
err = errors.New("certificate parsing warning: certificate data is shorter than specified by length")
length = certificate.CertLen.Value()
}
if certificate.CertLen.Value() < len(certificate.CertBytes) {
log.WithFields(log.Fields{
"at": "(Certificate) Length",
"certificate_bytes_length": certificate.CertLen,
"certificate_actual_length": len(certificate.CertBytes),
"reason": "certificate contains data beyond length",
}).Warn("certificate format warning")
err = errors.New("certificate parsing warning: certificate data is longer than specified by length")
length = certificate.CertLen.Value()
}
if err != nil {
return
}
length = certificate.CertLen.Value()
func (c *Certificate) Length() (length int) {
length = c.leng.Int()
return
}
//
// Return the Certificate data and any errors encountered parsing the Certificate.
//
func (certificate Certificate) Data() (data []byte, err error) {
_, err = certificate.Length()
data = certificate.CertBytes
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":
data = certificate.CertBytes
return
case "certificate parsing warning: certificate data is longer than specified by length":
data = certificate.CertBytes[:certificate.CertLen.Value()]
return
}
func (c *Certificate) Data() (data []byte) {
lastElement := c.Length()
if lastElement > len(c.payl) {
data = c.payl
} else {
data = c.payl[0:lastElement]
}
return
}
func NewCertificate(data []byte) (certificate *Certificate, err error) {
certificate = &Certificate{}
switch len(data) {
case 0:
certificate.kind = NewInteger([]byte{0})
certificate.leng = NewInteger([]byte{0})
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate")
err = fmt.Errorf("error parsing certificate: certificate is too short")
return
case 1:
certificate.kind = NewInteger(data[0:0])
certificate.leng = NewInteger([]byte{0})
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate")
err = fmt.Errorf("error parsing certificate: certificate is too short")
return
case 2:
certificate.kind = NewInteger(data[0:1])
certificate.leng = NewInteger([]byte{0})
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": len(data),
"reason": "too short (len < CERT_MIN_SIZE)" + fmt.Sprintf("%d", certificate.kind.Int()),
}).Error("invalid certificate")
err = fmt.Errorf("error parsing certificate length: certificate is too short")
return
default:
certificate.kind = NewInteger(data[0:1])
certificate.leng = NewInteger(data[1:3])
payleng := len(data) - CERT_MIN_SIZE
certificate.payl = data[CERT_MIN_SIZE:]
if certificate.leng.Int() > len(data)-CERT_MIN_SIZE {
err = fmt.Errorf("certificate parsing warning: certificate data is shorter than specified by length")
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.leng.Int(),
"certificate_payload_length": payleng,
"reason": err.Error(),
}).Error("invalid certificate")
return
} else if certificate.leng.Int() < len(data)-CERT_MIN_SIZE {
err = fmt.Errorf("certificate parsing warning: certificate data is longer than specified by length")
log.WithFields(log.Fields{
"at": "(Certificate) NewCertificate",
"certificate_bytes_length": certificate.leng.Int(),
"certificate_payload_length": payleng,
"reason": err.Error(),
}).Error("invalid certificate")
return
}
return
}
}
//
// 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 *Certificate, remainder []byte, err error) {
certificate = &Certificate{}
certificate.CertType, err = NewInteger(data[0:1])
if err != nil {
log.WithFields(log.Fields{
"at": "(Certificate) ReadCertificate",
"certificate": certificate,
"data": data,
"reason": "error parsing certificate type",
"error": err,
"error_reason": err.Error(),
}).Warn("certificate format warning")
certificate, err = NewCertificate(data)
if err != nil && err.Error() == "certificate parsing warning: certificate data is longer than specified by length" {
remainder = certificate.ExcessBytes()
err = nil
}
certificate.CertLen = &Integer{}
cert_len := len(data)
if cert_len < CERT_MIN_SIZE {
log.WithFields(log.Fields{
"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, err = NewInteger(data[1:CERT_MIN_SIZE])
// _, err = certificate.Type()
//log.Println("Calculated len AT LEN", cert_len, "Stated len AT LEN", certificate.CertLen.Value())
if err != nil {
//return
log.WithFields(log.Fields{
"at": "(Certificate) ReadCertificate",
"certificate_bytes_length": cert_len,
"certificate_min_size": CERT_MIN_SIZE,
"reason": "certificate size is invalid",
}).Warn("certificate format warning")
//err = errors.New("error parsing certificate type: certificate type is invalid")
}
certificate.CertBytes = data[CERT_MIN_SIZE:]
_, err = certificate.Length()
if err != nil {
switch err.Error() {
case "error parsing certificate length: certificate is too short":
certificate.CertLen, err = NewInteger([]byte{00000000})
return
case "certificate parsing warning: certificate data is shorter than specified by length":
return
case "certificate parsing warning: certificate data is longer than specified by length":
certificate.CertBytes = data[CERT_MIN_SIZE:]
l, _ := certificate.Length()
remainder = data[CERT_MIN_SIZE+l:]
return
}
}
}
return
}

View File

@@ -10,11 +10,8 @@ func TestCertificateTypeIsFirstByte(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x00}
certificate, _, err := ReadCertificate(bytes)
if err != nil {
t.Log(err)
}
cert_type, _, err := certificate.Type()
certificate, err := NewCertificate(bytes)
cert_type := certificate.Type()
assert.Equal(cert_type, 3, "certificate.Type() should be the first bytes in a certificate")
assert.Nil(err)
@@ -24,25 +21,19 @@ func TestCertificateLengthCorrect(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
certificate, _, err := ReadCertificate(bytes)
assert.Nil(err, "ReadCertificate() should not return an error with valid data")
cert_len, err := certificate.Length()
assert.Nil(err, "ReadCertificate() should not return an error with valid data")
certificate, err := NewCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 2, "certificate.Length() should return integer from second two bytes")
assert.Nil(err, "ReadCertificate() should not return an error with valid data")
assert.Nil(err)
}
func TestCertificateLengthErrWhenTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x01}
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()
certificate, err := NewCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 0, "certificate.Length() did not return zero length for missing length data")
if assert.NotNil(err) {
@@ -54,15 +45,8 @@ func TestCertificateLengthErrWhenDataTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate, _, err := ReadCertificate(bytes)
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")
}
cert_len, err := certificate.Length()
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")
}
certificate, err := NewCertificate(bytes)
cert_len := certificate.Length()
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was actually missing")
if assert.NotNil(err) {
@@ -74,34 +58,28 @@ func TestCertificateDataWhenCorrectSize(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x01, 0xaa}
certificate, _, err := ReadCertificate(bytes)
assert.Nil(err, "certificate.Data() returned error with valid data")
cert_len, err := certificate.Length()
certificate, err := NewCertificate(bytes)
cert_data := certificate.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")
data, _ := NewInteger(certificate.CertBytes)
assert.Equal(170, data.Value(), "certificate.Data() returned incorrect data")
assert.Equal(170, int(cert_data[0]), "certificate.Data() returned incorrect data")
}
func TestCertificateDataWhenTooLong(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
certificate, _, err := ReadCertificate(bytes)
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is longer than specified by length", err.Error(), "correct error message should be returned")
}
cert_len, err := certificate.Length()
certificate, err := NewCertificate(bytes)
cert_data := certificate.Data()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is longer than specified by length", err.Error(), "correct error message should be returned")
}
cert_len := certificate.Length() //len(cert_data)
assert.Equal(cert_len, 2, "certificate.Length() did not return indicated length when data was too long")
if certificate.CertBytes[0] != 0xff || certificate.CertBytes[1] != 0xff {
if cert_data[0] != 0xff || cert_data[1] != 0xff {
t.Fatal("certificate.Data() returned incorrect data when data was too long")
}
}
@@ -110,11 +88,8 @@ func TestCertificateDataWhenTooShort(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate, _, err := ReadCertificate(bytes)
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")
}
cert_data, err := certificate.Data()
certificate, err := NewCertificate(bytes)
cert_data := certificate.Data()
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")
@@ -130,8 +105,7 @@ func TestReadCertificateWithCorrectData(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff}
cert, remainder, err := ReadCertificate(bytes)
t.Log("CERT IS:", cert.Cert())
assert.Equal(len(cert.Cert()), 5, "ReadCertificate() did not return correct amount of data for valid certificate")
assert.Equal(cert.length(), 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.Nil(err, "ReadCertificate() should not return an error with valid data")
}
@@ -142,7 +116,7 @@ func TestReadCertificateWithDataTooShort(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff}
cert, remainder, err := ReadCertificate(bytes)
assert.Equal(len(cert.Cert()), 4, "ReadCertificate() did not return correct amount of data for certificate with missing data")
assert.Equal(cert.length(), 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")
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")
@@ -155,10 +129,10 @@ func TestReadCertificateWithRemainder(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff, 0x01}
cert, remainder, err := ReadCertificate(bytes)
assert.Equal(len(cert.Cert()), 5, "ReadCertificate() did not return correct amount of data for certificate with extra data")
assert.Equal(cert.length(), 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(1, int(remainder[0]), "ReadCertificate() did not return correct remainder value")
assert.NotNil(err)
// assert.Equal(1, int(remainder[0]), "ReadCertificate() did not return correct remainder value")
assert.Nil(err)
}
func TestReadCertificateWithInvalidLength(t *testing.T) {
@@ -167,7 +141,7 @@ func TestReadCertificateWithInvalidLength(t *testing.T) {
bytes := []byte{0x00, 0x00}
cert, remainder, err := ReadCertificate(bytes)
assert.Equal(len(cert.Cert()), 2, "ReadCertificate() should populate the certificate with the provided data even when invalid")
assert.Equal(cert.length(), 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")
if assert.NotNil(err) {
assert.Equal("error parsing certificate length: certificate is too short", err.Error(), "correct error message should be returned")

View File

@@ -7,39 +7,18 @@ Accurate for version 0.9.24
*/
import (
"errors"
log "github.com/sirupsen/logrus"
"time"
)
type Date [8]byte
const DATE_SIZE = 8
//
// Time takes the value stored in date as an 8 byte big-endian integer representing the
// number of milliseconds since the beginning of unix time and converts it to a Go time.Time
// struct.
//
func (date Date) Time() (date_time time.Time) {
seconds, _ := NewInteger(date[:])
date_time = time.Unix(0, int64(seconds.Value()*1000000))
return
}
func ReadDate(data []byte) (h Date, remainder []byte, err error) {
if len(data) < DATE_SIZE {
log.WithFields(log.Fields{
"at": "(Date) ReadDate",
"data_len": len(data),
"required_len": "8",
"reason": "date missing data",
}).Error("date error")
err = errors.New("error reading date, insufficient length")
copy(h[:], data[0:len(data)-1])
} else {
copy(h[:], data[0:DATE_SIZE-1])
copy(remainder, data[DATE_SIZE-1:])
}
seconds := NewInteger(date[:])
date_time = time.Unix(0, int64(seconds.Int()*1000000))
return
}

View File

@@ -9,37 +9,42 @@ Identical to KeysAndCert
*/
import (
"strings"
"github.com/go-i2p/go-i2p/lib/common/base32"
"github.com/go-i2p/go-i2p/lib/common/base64"
"github.com/go-i2p/go-i2p/lib/crypto"
"strings"
)
//
// A Destination is a KeysAndCert with functionallity
// for generating base32 and base64 addresses.
//
type Destination struct {
KeysAndCert
}
type Destination []byte
func (destination Destination) PublicKey() (crypto.PublicKey, error) {
return destination.KeysAndCert.GetPublicKey()
return KeysAndCert(destination).PublicKey()
}
func (destination Destination) SigningPublicKey() (crypto.SigningPublicKey, error) {
return destination.KeysAndCert.GetSigningPublicKey()
return KeysAndCert(destination).SigningPublicKey()
}
func (destination Destination) Certificate() (CertificateInterface, error) {
return destination.KeysAndCert.GetCertificate()
func (destination Destination) Certificate() (*Certificate, error) {
return KeysAndCert(destination).Certificate()
}
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.
//
func (destination Destination) Base32Address() (str string) {
hash := crypto.SHA256(destination.Cert())
hash := crypto.SHA256(destination)
str = strings.Trim(base32.EncodeToString(hash[:]), "=")
str = str + ".b32.i2p"
return
@@ -49,14 +54,5 @@ func (destination Destination) Base32Address() (str string) {
// Generate the I2P base64 address for this Destination.
//
func (destination Destination) Base64() string {
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
return base64.EncodeToString(destination)
}

View File

@@ -1,8 +1,7 @@
FROM golang
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install libsodium-dev -y
apt-get upgrade -y
RUN go get github.com/dvyukov/go-fuzz/go-fuzz
RUN go get github.com/dvyukov/go-fuzz/go-fuzz-build

View File

@@ -2,13 +2,9 @@ package common
import (
"crypto/sha256"
"errors"
log "github.com/sirupsen/logrus"
"io"
)
const HASH_SIZE = 32
// sha256 hash of some data
type Hash [32]byte
@@ -29,20 +25,3 @@ func HashReader(r io.Reader) (h Hash, err error) {
}
return
}
func ReadHash(data []byte) (h Hash, remainder []byte, err error) {
if len(data) < HASH_SIZE {
log.WithFields(log.Fields{
"at": "(Hash) ReadHash",
"data_len": len(data),
"required_len": "32",
"reason": "hash missing data",
}).Error("hash error")
err = errors.New("error reading hash, insufficient length")
copy(h[:], data[0:len(data)-1])
} else {
copy(h[:], data[0:HASH_SIZE-1])
copy(remainder, data[HASH_SIZE-1:])
}
return
}

View File

@@ -1,33 +0,0 @@
package common
/*
I2P Tunnel Identity Helpers
https://geti2p.net/spec/common-structures#ident
Accurate for version 0.9.24
*/
import (
"errors"
log "github.com/sirupsen/logrus"
)
type Ident [4]byte
const IDENT_SIZE = 4
func ReadIdent(data []byte) (h Ident, remainder []byte, err error) {
if len(data) < IDENT_SIZE {
log.WithFields(log.Fields{
"at": "(Ident) ReadIdent",
"data_len": len(data),
"required_len": "8",
"reason": "ident missing data",
}).Error("ident error")
err = errors.New("error reading ident, insufficient length")
copy(h[:], data[0:len(data)-1])
} else {
copy(h[:], data[0:IDENT_SIZE-1])
copy(remainder, data[IDENT_SIZE-1:])
}
return
}

View File

@@ -8,8 +8,6 @@ Accurate for version 0.9.24
import (
"encoding/binary"
// log "github.com/sirupsen/logrus"
// "errors"
)
// Total byte length of an I2P integer
@@ -19,65 +17,31 @@ const (
type Integer []byte
func (i *Integer) longBytes() (value [INTEGER_SIZE]byte) {
value = [INTEGER_SIZE]byte{0, 0, 0, 0, 0, 0, 0, 0}
pad := INTEGER_SIZE - len([]byte(*i))
for index, element := range []byte(*i) {
value[pad+index] = element
}
return value
func (i Integer) Bytes() []byte {
return i[:]
}
func (i *Integer) Value() int {
if i == nil {
return 0
}
r := i.longBytes()
// log.Println("LONG BYTES", r)
return int(binary.BigEndian.Uint64(r[:]))
// return int(binary.BigEndian.Int64(r[:]))
func (i Integer) Int() int {
return intFromBytes(i.Bytes())
}
func (i *Integer) Bytes() []byte {
if i == nil {
return []byte{}
}
if len([]byte(*i)) == 0 {
return []byte{0}
}
r := []byte(*i)
return r
func NewInteger(bytes []byte) Integer {
i := Integer(bytes)
return i
}
//
// Interpret a slice of bytes from length 0 to length 8 as a big-endian
// integer and return an int representation.
//
func NewInteger(number []byte) (value *Integer, err error) {
var integer Integer = number
value = &integer //[INTEGER_SIZE]byte(number)
// for index, element := range number {
// value[INTEGER_SIZE-1-index] = element
// }
/*length := len(number)
if length < INTEGER_SIZE {
log.WithFields(log.Fields{
"at": "(Integer) NewInteger",
"length": length,
"required_len": INTEGER_SIZE,
"reason": "not enough data",
}).Error("error parsing Integer")
err = errors.New("error parsing Integer, not enough data")
}else if length > INTEGER_SIZE{
log.WithFields(log.Fields{
"at": "(Integer) NewInteger",
"length": length,
"required_len": INTEGER_SIZE,
"reason": "too much data",
}).Error("error parsing Integer")
err = errors.New("error parsing Integer, too much data")
}else{
err = nil
}*/
func intFromBytes(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
}

View File

@@ -1,34 +1,32 @@
package common
import (
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestIntegerBigEndian(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
integer, err := NewInteger(bytes)
assert.Nil(err)
integer := NewInteger(bytes)
assert.Equal(integer.Value(), 1, "Integer() did not parse bytes big endian")
checkbytes := integer.Bytes()
assert.Equal(bytes, checkbytes, "IntegerBytes() did not match original bytes")
assert.Equal(integer.Int(), 1, "NewInteger() did not parse bytes big endian")
}
func TestWorksWithOneByte(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x00}
integer, err := NewInteger(bytes)
assert.Nil(err)
integer := NewInteger([]byte{0x01})
assert.Equal(integer.Value(), 0, "Integer() did not correctly parse single byte slice")
checkbytes := integer.Bytes()
assert.Equal(bytes, checkbytes, "IntegerBytes() did not match original bytes")
assert.Equal(integer.Int(), 1, "NewInteger() did not correctly parse single byte slice")
}
func TestIsZeroWithNoData(t *testing.T) {
assert := assert.New(t)
integer := NewInteger([]byte{})
assert.Equal(integer.Int(), 0, "NewInteger() did not correctly parse zero length byte slice")
}

View File

@@ -49,10 +49,10 @@ const (
// Key Certificate Public Key Types
const (
KEYCERT_CRYPTO_ELG = iota
KEYCERT_CRYPTO_P256
KEYCERT_CRYPTO_P384
KEYCERT_CRYPTO_P521
KEYCERT_CRYPTO_X25519
)
const (
KEYCERT_MIN_SIZE = 7
)
// SigningPublicKey sizes for Signing Key Types
@@ -79,67 +79,34 @@ const (
KEYCERT_SPK_SIZE = 128
)
const (
KEYCERT_MIN_SIZE = 7
)
//type KeyCertificate []byte
type KeyCertificate struct {
CertificateInterface
PKType *Integer
PKExtra []byte
SPKType *Integer
SPKExtra []byte
} //[]byte
*Certificate
spkType Integer
cpkType Integer
}
//
// The data contained in the Key Certificate.
//
func (key_certificate KeyCertificate) Data() ([]byte, error) {
var r []byte
r = append(r, key_certificate.CertificateInterface.Cert()...)
r = append(r, key_certificate.PKType.Bytes()...)
r = append(r, key_certificate.SPKType.Bytes()...)
return r, nil
return key_certificate.Certificate.RawBytes(), nil
}
//
// The SigningPublicKey type this Key Certificate describes and any errors encountered
// parsing the KeyCertificate.
//
func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int, err error) {
// signing_key_type := key_certificate.SPKType
// data_len := len(key_certificate.CertificateInterface.CertBytes)
if len(key_certificate.SPKType.Bytes()) < 2 {
log.WithFields(log.Fields{
"at": "(KeyCertificate) SigningPublicKeyType",
"data_len": len(key_certificate.SPKType.Bytes()),
"required_len": 2,
"reason": "not enough data",
}).Error("error retrieving Signing Public Key type")
err = errors.New("error retrieving signing public key type: not enough data")
return
}
log.Println("Signing Public Key Type", key_certificate.SPKType) //.Value())
return key_certificate.SPKType.Value(), nil
func (key_certificate KeyCertificate) SigningPublicKeyType() (signing_pubkey_type int) {
return key_certificate.spkType.Int()
}
//
// The PublicKey type this Key Certificate describes and any errors encountered parsing
// this KeyCertificate.
//
func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int, err error) {
if len(key_certificate.PKType.Bytes()) < 2 {
log.WithFields(log.Fields{
"at": "(KeyCertificate) SingingPublicKeyType",
"data_len": len(key_certificate.PKType.Bytes()),
"required_len": 2,
"reason": "not enough data",
}).Error("error retrieving Singning Public Key type")
err = errors.New("error retrieving signing public key type: not enough data")
return
}
log.Println("Public Key Type", key_certificate.PKType)
return key_certificate.PKType.Value(), nil
func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int) {
return key_certificate.cpkType.Int()
}
//
@@ -147,7 +114,7 @@ func (key_certificate KeyCertificate) PublicKeyType() (pubkey_type int, err erro
// it along with any errors encountered constructing the PublicKey.
//
func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_key crypto.PublicKey, err error) {
key_type, err := key_certificate.SigningPublicKeyType()
key_type := key_certificate.PublicKeyType()
if err != nil {
return
}
@@ -176,7 +143,7 @@ func (key_certificate KeyCertificate) ConstructPublicKey(data []byte) (public_ke
// it along with any errors encountered constructing the SigningPublicKey.
//
func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (signing_public_key crypto.SigningPublicKey, err error) {
signing_key_type, err := key_certificate.PublicKeyType()
signing_key_type := key_certificate.PublicKeyType()
if err != nil {
return
}
@@ -208,8 +175,7 @@ func (key_certificate KeyCertificate) ConstructSigningPublicKey(data []byte) (si
var ec_key crypto.ECP521PublicKey
extra := KEYCERT_SIGN_P521_SIZE - KEYCERT_SPK_SIZE
copy(ec_key[:], data)
d, _ := key_certificate.Data()
copy(ec_key[KEYCERT_SPK_SIZE:], d[4:4+extra])
copy(ec_key[KEYCERT_SPK_SIZE:], key_certificate.Certificate.RawBytes()[4:4+extra])
signing_public_key = ec_key
case KEYCERT_SIGN_RSA2048:
//var rsa_key crypto.RSA2048PublicKey
@@ -241,63 +207,59 @@ func (key_certificate KeyCertificate) SignatureSize() (size int) {
KEYCERT_SIGN_ED25519: 64,
KEYCERT_SIGN_ED25519PH: 64,
}
key_type, err := key_certificate.SigningPublicKeyType()
if err != nil {
key_type := key_certificate.SigningPublicKeyType()
/*if err != nil {
log.WithFields(log.Fields{
"at": "(KeyCertificate) SignatureSize",
"key_type": key_type,
"reason": "failed to read signing public key type",
}).Error("error getting signature size")
return 0
}
}*/
return sizes[int(key_type)]
}
//
// Read a KeyCertificate from a slice of bytes
//
func ReadKeyCertificate(data []byte) (key_certificate KeyCertificate, err error) {
key_certificate.SPKType = &Integer{}
key_certificate.PKType = &Integer{}
cert, remainder, err := ReadCertificate(data)
if err != nil {
return
func NewKeyCertificate(bytes []byte) (key_certificate *KeyCertificate, err error) {
var certificate *Certificate
certificate, _, err = ReadCertificate(bytes)
//if err != nil {
// return nil, err
//}
if len(bytes) < KEYCERT_MIN_SIZE {
err = errors.New("error parsing key certificate: not enough data")
}
cert_type, _, err := cert.Type()
if err != nil {
return
}
log.Println("KEYSANDCERT CERT TYPE=", cert_type, cert.CertBytes, remainder)
key_certificate.CertificateInterface = cert
data = cert.Cert()
data_len := len(data)
if data_len < KEYCERT_MIN_SIZE {
log.WithFields(log.Fields{
"at": "(KeyCertificate) PublicKeyType",
"data_len": data_len,
"required_len": KEYCERT_MIN_SIZE,
"reason": "not enough data",
}).Error("error parsing key certificate public key")
err = errors.New("error parsing key certificate public key: not enough data")
return
}
log.Println("KEYSANDCERT=", data, "| len=", data_len, "| 0=", data[0], "| 1=", data[1])
key_certificate.SPKType, err = NewInteger(data[len(data)-2 : len(data)])
if err != nil {
log.WithFields(log.Fields{
"at": "(KeyCertificate) SigningPublicKeyType",
"key_type": key_certificate.PKType,
"reason": "failed to read signing public key type",
}).Error("error parsing key certificate signing public key")
}
key_certificate.PKType, err = NewInteger(data[len(data)-4 : len(data)-2])
if err != nil {
log.WithFields(log.Fields{
"at": "(KeyCertificate) PublicKeyType",
"key_type": key_certificate.PKType,
"reason": "failed to read public key type",
}).Error("error parsing key certificate public key")
err = errors.New("error parsing key certificate public key: not enough data")
switch len(bytes) {
case 4:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:]),
cpkType: Integer([]byte{0}),
}
case 5:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer([]byte{0}),
}
case 6:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer(bytes[6:]),
}
default:
key_certificate = &KeyCertificate{
Certificate: certificate,
spkType: Integer(bytes[4:5]),
cpkType: Integer(bytes[6:7]),
}
}
//key_certificate.PublicKey = NewPublicKey(bytes)
return
}
func KeyCertificateFromCertificate(certificate *Certificate) *KeyCertificate {
k, _ := NewKeyCertificate(certificate.RawBytes())
return k
}

View File

@@ -9,60 +9,52 @@ import (
func TestSingingPublicKeyTypeReturnsCorrectInteger(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00})
assert.Nil(err, "ReadKeyCertificate() returned error with valid data")
spk_type, err := key_cert.SigningPublicKeyType()
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00})
pk_type := key_cert.SigningPublicKeyType()
assert.Nil(err, "SigningPublicKeyType() returned error with valid data")
assert.Equal(spk_type, KEYCERT_SIGN_DSA_SHA1, "SigningPublicKeyType() did not return correct type")
assert.Equal(pk_type, KEYCERT_SIGN_P521, "SigningPublicKeyType() did not return correct typec")
}
func TestPublicKeyTypeReportsWhenDataTooSmall(t *testing.T) {
func TestSingingPublicKeyTypeReportsWhenDataTooSmall(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x01, 0x00})
if assert.NotNil(err) {
assert.Equal("error parsing key certificate public key: not enough data", err.Error(), "correct error message should be returned")
}
// assert.NotNil(err, "ReadKeyCertificate() returned error with valid data")
_, err = key_cert.PublicKeyType()
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x01, 0x00})
sk_type := key_cert.SigningPublicKeyType()
assert.Equal(sk_type, 0, "SigningPublicKeyType() did not return correct typec")
if assert.NotNil(err) {
assert.Equal("error retrieving signing public key type: not enough data", err.Error(), "correct error message should be returned")
assert.Equal("error parsing key certificate: not enough data", err.Error(), "correct error message should be returned")
}
}
func TestPublicKeyTypeReturnsCorrectInteger(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x03, 0x00, 0x00})
assert.Nil(err, "ReadKeyCertificate() returned error with valid data")
pk_type, err := key_cert.PublicKeyType()
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x03})
pk_type := key_cert.PublicKeyType()
assert.Nil(err, "PublicKeyType() returned error with valid data")
assert.Equal(pk_type, KEYCERT_CRYPTO_P521, "PublicKeyType() did not return correct type")
assert.Nil(err, "PublicKey() returned error with valid data")
assert.Equal(pk_type, KEYCERT_SIGN_P521, "PublicKeyType() did not return correct typec")
}
func TestSigningPublicKeyTypeReportsWhenDataTooSmall(t *testing.T) {
func TestPublicKeyTypeReportsWhenDataTooSmall(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x02, 0x00, 0x00})
if assert.NotNil(err) {
assert.Equal("error parsing key certificate public key: not enough data", err.Error(), "correct error message should be returned")
}
_, err = key_cert.SigningPublicKeyType()
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x02, 0x00, 0x00})
pk_type := key_cert.PublicKeyType()
if assert.NotNil(err) {
assert.Equal("error retrieving signing public key type: not enough data", err.Error(), "correct error message should be returned")
assert.Equal("error parsing key certificate: not enough data", err.Error(), "correct error message should be returned")
}
assert.Equal(pk_type, 0, "PublicKeyType() did not return correct typec")
}
/*
func TestConstructPublicKeyReportsWhenDataTooSmall(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
assert.Nil(err, "ReadKeyCertificate() returned error with valid data")
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
data := make([]byte, 255)
_, err = key_cert.ConstructPublicKey(data)
@@ -70,25 +62,22 @@ func TestConstructPublicKeyReportsWhenDataTooSmall(t *testing.T) {
assert.Equal("error constructing public key: not enough data", err.Error(), "correct error message should be returned")
}
}
*/
/*
func TestConstructPublicKeyReturnsCorrectDataWithElg(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
assert.Nil(err, "ReadKeyCertificate() returned error with valid data")
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
data := make([]byte, 256)
pk, err := key_cert.ConstructPublicKey(data)
assert.Nil(err, "ConstructPublicKey() returned error with valid data")
assert.Equal(pk.Len(), 256, "ConstructPublicKey() did not return public key with correct length")
}
*/
/*
func TestConstructSigningPublicKeyReportsWhenDataTooSmall(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
data := make([]byte, 127)
_, err = key_cert.ConstructSigningPublicKey(data)
@@ -100,7 +89,7 @@ func TestConstructSigningPublicKeyReportsWhenDataTooSmall(t *testing.T) {
func TestConstructSigningPublicKeyWithDSASHA1(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00})
data := make([]byte, 128)
spk, err := key_cert.ConstructSigningPublicKey(data)
@@ -111,7 +100,7 @@ func TestConstructSigningPublicKeyWithDSASHA1(t *testing.T) {
func TestConstructSigningPublicKeyWithP256(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01})
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x01})
data := make([]byte, 128)
spk, err := key_cert.ConstructSigningPublicKey(data)
@@ -122,7 +111,7 @@ func TestConstructSigningPublicKeyWithP256(t *testing.T) {
func TestConstructSigningPublicKeyWithP384(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02})
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x02})
data := make([]byte, 128)
spk, err := key_cert.ConstructSigningPublicKey(data)
@@ -133,11 +122,10 @@ func TestConstructSigningPublicKeyWithP384(t *testing.T) {
func TestConstructSigningPublicKeyWithP521(t *testing.T) {
assert := assert.New(t)
key_cert, err := ReadKeyCertificate([]byte{0x05, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00})
key_cert, err := NewKeyCertificate([]byte{0x05, 0x00, 0x08, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00})
data := make([]byte, 128)
spk, err := key_cert.ConstructSigningPublicKey(data)
assert.Nil(err, "ConstructSigningPublicKey() with P521 returned err on valid data")
assert.Equal(spk.Len(), KEYCERT_SIGN_P521_SIZE, "ConstructSigningPublicKey() with P521 returned incorrect SigningPublicKey length")
}
*/

View File

@@ -60,53 +60,51 @@ const (
KEYS_AND_CERT_DATA_SIZE = 384
)
type KeysAndCertInterface interface {
GetPublicKey() (key crypto.PublicKey, err error)
GetSigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error)
GetCertificate() (cert Certificate, err error)
Bytes() (bytes []byte)
}
type KeysAndCert struct {
crypto.SigningPublicKey
crypto.PublicKey
CertificateInterface
}
func (keys_and_cert KeysAndCert) Bytes() (bytes []byte) { //, err error) {
pubkey, _ := keys_and_cert.GetPublicKey()
signpubkey, _ := keys_and_cert.GetSigningPublicKey()
elg_key := pubkey.(crypto.ElgPublicKey)
dsa_key := signpubkey.(crypto.DSAPublicKey)
bytes = append(bytes, dsa_key[:]...)
bytes = append(bytes, elg_key[:]...)
bytes = append(bytes, keys_and_cert.CertificateInterface.Cert()...)
return
}
type KeysAndCert []byte
//
// Return the PublicKey for this KeysAndCert, reading from the Key Certificate if it is present to
// determine correct lengths.
//
func (keys_and_cert KeysAndCert) GetPublicKey() (key crypto.PublicKey, err error) {
data := make([]byte, KEYS_AND_CERT_PUBKEY_SIZE)
if keys_and_cert.PublicKey == nil {
epk := crypto.ElgPublicKey{}
copy(data[:KEYS_AND_CERT_PUBKEY_SIZE], epk[:])
keys_and_cert.PublicKey = epk
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
}
/*cert, err := keys_and_cert.GetCertificate()
func (keys_and_cert KeysAndCert) PublicKey() (key crypto.PublicKey, err error) {
cert, err := keys_and_cert.Certificate()
if err != nil {
return
}
cert_len, err := cert.Length()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len != 0 {*/
key = keys_and_cert.PublicKey
/*}*/
if cert_len == 0 {
// No Certificate is present, return the KEYS_AND_CERT_PUBKEY_SIZE byte
// 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 = KeyCertificateFromCertificate(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
}
@@ -114,22 +112,41 @@ func (keys_and_cert KeysAndCert) GetPublicKey() (key crypto.PublicKey, err error
// Return the SigningPublicKey for this KeysAndCert, reading from the Key Certificate if it is present to
// determine correct lengths.
//
func (keys_and_cert KeysAndCert) GetSigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) {
if keys_and_cert.SigningPublicKey == nil {
keys_and_cert.SigningPublicKey = crypto.DSAPublicKey{}
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
}
/*cert, err := keys_and_cert.GetCertificate()
func (keys_and_cert KeysAndCert) SigningPublicKey() (signing_public_key crypto.SigningPublicKey, err error) {
cert, err := keys_and_cert.Certificate()
if err != nil {
return
}
cert_len, err := cert.Length()
cert_len := cert.Length()
if err != nil {
return
}
if cert_len != 0 {*/
signing_public_key = keys_and_cert.SigningPublicKey
/*}*/
if cert_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[:], 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 = KeyCertificateFromCertificate(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
}
@@ -137,111 +154,20 @@ func (keys_and_cert KeysAndCert) GetSigningPublicKey() (signing_public_key crypt
// Return the Certificate contained in the KeysAndCert and any errors encountered while parsing the
// KeysAndCert or Certificate.
//
func (keys_and_cert KeysAndCert) GetCertificate() (cert CertificateInterface, err error) {
data_len := len(keys_and_cert.Bytes())
log.Println("LEN IS", data_len, "KEYS_AND_CERT_MIN_SIZE", KEYS_AND_CERT_MIN_SIZE)
if data_len < KEYS_AND_CERT_MIN_SIZE {
func (keys_and_cert KeysAndCert) Certificate() (cert *Certificate, err error) {
keys_cert_len := len(keys_and_cert)
if keys_cert_len < KEYS_AND_CERT_MIN_SIZE {
log.WithFields(log.Fields{
"at": "GetCertificate",
"data_len": data_len,
"required_len": KEYS_AND_CERT_MIN_SIZE,
"reason": "not enough data",
}).Error("error parsing keys and cert")
err = errors.New("certificate parsing warning: certificate data is shorter than specified by length")
}
/*if data_len > CERT_MIN_SIZE {
log.WithFields(log.Fields{
"at": "ReadKeysAndCert",
"data_len": data_len,
"required_len": KEYS_AND_CERT_MIN_SIZE,
"reason": "too much data",
}).Error("error parsing keys and cert")
err = errors.New("certificate parsing warning: certificate data is longer than specified by length")
}*/
cert = keys_and_cert.CertificateInterface
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": "ReadKeys",
"data_len": data_len,
"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
}
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_bytes, e := cert.Type()
err = e
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.
cert_integer, _ := NewInteger(cert_bytes)
pk, err = KeyCertificate{PKType: cert_integer}.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_bytes, e := cert.Type()
err = e
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.
cert_integer, _ := NewInteger(cert_bytes)
spk, err = KeyCertificate{SPKType: cert_integer}.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, e := cert.Length()
err = e
if cert_len == 0 {
remainder = data[KEYS_AND_CERT_MIN_SIZE:]
return
}
remainder = data[KEYS_AND_CERT_PUBKEY_SIZE+KEYS_AND_CERT_SPK_SIZE:]
}
cert, _, err = ReadCertificate(keys_and_cert[KEYS_AND_CERT_DATA_SIZE:])
return
}
//
@@ -250,7 +176,6 @@ func ReadKeys(data []byte, cert CertificateInterface) (spk crypto.SigningPublicK
//
func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte, err error) {
data_len := len(data)
keys_and_cert.CertificateInterface = &Certificate{}
if data_len < KEYS_AND_CERT_MIN_SIZE {
log.WithFields(log.Fields{
"at": "ReadKeysAndCert",
@@ -261,20 +186,19 @@ func ReadKeysAndCert(data []byte) (keys_and_cert KeysAndCert, remainder []byte,
err = errors.New("error parsing KeysAndCert: data is smaller than minimum valid size")
return
}
cert, remainder, err := ReadCertificate(data[KEYS_AND_CERT_DATA_SIZE:])
if err != nil {
log.WithFields(log.Fields{
"at": "ReadKeysAndCert",
"data_len": data_len,
"required_len": KEYS_AND_CERT_MIN_SIZE,
"reason": "error parsing certificate",
}).Error("error parsing keys and cert")
err = errors.New("error parsing KeysAndCert: error parsing certificate")
keys_and_cert = KeysAndCert(data[:KEYS_AND_CERT_MIN_SIZE])
cert, _ := keys_and_cert.Certificate()
cert_len := cert.Length()
if cert_len == 0 {
remainder = data[KEYS_AND_CERT_MIN_SIZE:]
return
}
keys_and_cert.CertificateInterface = cert
spk, pk, remainder, err := ReadKeys(data, cert)
keys_and_cert.SigningPublicKey = spk
keys_and_cert.PublicKey = pk
if data_len < KEYS_AND_CERT_MIN_SIZE+cert_len {
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
}

View File

@@ -9,25 +9,19 @@ import (
func TestCertificateWithMissingData(t *testing.T) {
assert := assert.New(t)
//cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01}
cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01}
data := make([]byte, 128+256)
//data = append(data, cert_data...)
keys_and_cert, remainder, err := ReadKeysAndCert(data)
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
t.Log("\n\nREMAINDER", remainder, "\n\n")
cert, err := keys_and_cert.GetCertificate()
t.Log("\n\nSTART\n\n")
data = append(data, cert_data...)
keys_and_cert := KeysAndCert(data)
cert, err := keys_and_cert.Certificate()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
} else {
t.Log("\n\nEND\n\n", cert.Cert())
}
// cert_bytes := []byte(cert.Cert())
// if assert.Equal(len(cert_data), len(cert_bytes)) {
// assert.Equal(cert_bytes, cert_data, "keys_and_cert.GetCertificate() did not return available data when cert was missing some data")
// }
cert_bytes := cert.Bytes()
if assert.Equal(len(cert_data), len(cert_bytes)) {
assert.Equal(cert_bytes, cert_data, "keys_and_cert.Certificate() did not return available data when cert was missing some data")
}
}
func TestCertificateWithValidData(t *testing.T) {
@@ -36,13 +30,13 @@ func TestCertificateWithValidData(t *testing.T) {
cert_data := []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}
data := make([]byte, 128+256)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
cert, err := keys_and_cert.GetCertificate()
cert, err := keys_and_cert.Certificate()
assert.Nil(err)
cert_bytes := []byte(cert.Cert())
cert_bytes := cert.Bytes()
if assert.Equal(len(cert_data), len(cert_bytes)) {
assert.Equal(cert_bytes, cert_data, "keys_and_cert.GetCertificate() did not return correct data with valid cert")
assert.Equal(cert_bytes, cert_data, "keys_and_cert.Certificate() did not return correct data with valid cert")
}
}
@@ -54,15 +48,13 @@ func TestPublicKeyWithBadData(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
//pub_key
_, err = keys_and_cert.GetPublicKey()
pub_key, err := keys_and_cert.PublicKey()
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
//TODO: pub_key in this instance is a null key(all zeros). This test should be changed to check for this.
//assert.Nil(pub_key)
assert.Nil(pub_key)
}
func TestPublicKeyWithBadCertificate(t *testing.T) {
@@ -73,15 +65,13 @@ func TestPublicKeyWithBadCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
//pub_key
_, err = keys_and_cert.GetPublicKey()
pub_key, err := keys_and_cert.PublicKey()
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
}
//TODO: pub_key in this instance is a null key(all zeros). This test should be changed to check for this.
//assert.Nil(pub_key)
assert.Nil(pub_key)
}
func TestPublicKeyWithNullCertificate(t *testing.T) {
@@ -92,9 +82,9 @@ func TestPublicKeyWithNullCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
pub_key, err := keys_and_cert.GetPublicKey()
pub_key, err := keys_and_cert.PublicKey()
assert.Nil(err)
assert.Equal(len(pub_key_data), pub_key.Len())
}
@@ -107,10 +97,9 @@ func TestPublicKeyWithKeyCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
assert.Nil(err)
keys_and_cert := KeysAndCert(data)
pub_key, err := keys_and_cert.GetPublicKey()
pub_key, err := keys_and_cert.PublicKey()
assert.Nil(err)
assert.Equal(len(pub_key_data), pub_key.Len())
}
@@ -123,9 +112,9 @@ func TestSigningPublicKeyWithBadData(t *testing.T) {
data := make([]byte, 93)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
signing_pub_key, err := keys_and_cert.GetSigningPublicKey()
signing_pub_key, err := keys_and_cert.SigningPublicKey()
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
@@ -140,9 +129,9 @@ func TestSigningPublicKeyWithBadCertificate(t *testing.T) {
data := make([]byte, 128)
data = append(data, pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
signing_pub_key, err := keys_and_cert.GetSigningPublicKey()
signing_pub_key, err := keys_and_cert.SigningPublicKey()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
}
@@ -157,9 +146,9 @@ func TestSigningPublicKeyWithNullCertificate(t *testing.T) {
signing_pub_key_data := make([]byte, 128)
data := append(pub_key_data, signing_pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
signing_pub_key, err := keys_and_cert.GetSigningPublicKey()
signing_pub_key, err := keys_and_cert.SigningPublicKey()
assert.Nil(err)
assert.Equal(len(signing_pub_key_data), signing_pub_key.Len())
}
@@ -172,9 +161,9 @@ func TestSigningPublicKeyWithKeyCertificate(t *testing.T) {
signing_pub_key_data := make([]byte, 128)
data := append(pub_key_data, signing_pub_key_data...)
data = append(data, cert_data...)
keys_and_cert, _, err := ReadKeysAndCert(data)
keys_and_cert := KeysAndCert(data)
signing_pub_key, err := keys_and_cert.GetSigningPublicKey()
signing_pub_key, err := keys_and_cert.SigningPublicKey()
assert.Nil(err)
assert.Equal(len(signing_pub_key_data), signing_pub_key.Len())
}
@@ -189,15 +178,15 @@ func TestReadKeysAndCertWithMissingData(t *testing.T) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
_, err = keys_and_cert.GetPublicKey()
_, err = keys_and_cert.PublicKey()
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
_, err = keys_and_cert.GetSigningPublicKey()
_, err = keys_and_cert.SigningPublicKey()
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
_, err = keys_and_cert.GetCertificate()
_, err = keys_and_cert.Certificate()
if assert.NotNil(err) {
assert.Equal("error parsing KeysAndCert: data is smaller than minimum valid size", err.Error())
}
@@ -214,15 +203,15 @@ func TestReadKeysAndCertWithMissingCertData(t *testing.T) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
}
_, err = keys_and_cert.GetPublicKey()
_, err = keys_and_cert.PublicKey()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
}
_, err = keys_and_cert.GetSigningPublicKey()
_, err = keys_and_cert.SigningPublicKey()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
}
_, err = keys_and_cert.GetCertificate()
_, err = keys_and_cert.Certificate()
if assert.NotNil(err) {
assert.Equal("certificate parsing warning: certificate data is shorter than specified by length", err.Error())
}
@@ -237,12 +226,12 @@ func TestReadKeysAndCertWithValidDataWithCertificate(t *testing.T) {
assert.Equal(0, len(remainder))
assert.Nil(err)
_, err = keys_and_cert.GetPublicKey()
assert.Nil(err, "keys_and_cert.GetPublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.GetSigningPublicKey()
assert.Nil(err, "keys_and_cert.GetSigningPublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.GetCertificate()
assert.Nil(err, "keys_and_cert.GetCertificate() returned error with valid data containing certificate")
_, err = keys_and_cert.PublicKey()
assert.Nil(err, "keys_and_cert.PublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.SigningPublicKey()
assert.Nil(err, "keys_and_cert.SigningPublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.Certificate()
assert.Nil(err, "keys_and_cert.Certificate() returned error with valid data containing certificate")
}
func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
@@ -254,12 +243,12 @@ func TestReadKeysAndCertWithValidDataWithoutCertificate(t *testing.T) {
assert.Equal(0, len(remainder))
assert.Nil(err)
_, err = keys_and_cert.GetPublicKey()
assert.Nil(err, "keys_and_cert.GetPublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.GetSigningPublicKey()
assert.Nil(err, "keys_and_cert.GetSigningPublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.GetCertificate()
assert.Nil(err, "keys_and_cert.GetCertificate() returned error with valid data not containing certificate")
_, err = keys_and_cert.PublicKey()
assert.Nil(err, "keys_and_cert.PublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.SigningPublicKey()
assert.Nil(err, "keys_and_cert.SigningPublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.Certificate()
assert.Nil(err, "keys_and_cert.Certificate() returned error with valid data not containing certificate")
}
func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
@@ -273,12 +262,12 @@ func TestReadKeysAndCertWithValidDataWithCertificateAndRemainder(t *testing.T) {
}
assert.Nil(err)
_, err = keys_and_cert.GetPublicKey()
assert.Nil(err, "keys_and_cert.GetPublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.GetSigningPublicKey()
assert.Nil(err, "keys_and_cert.GetSigningPublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.GetCertificate()
assert.Nil(err, "keys_and_cert.GetCertificate() returned error with valid data containing certificate")
_, err = keys_and_cert.PublicKey()
assert.Nil(err, "keys_and_cert.PublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.SigningPublicKey()
assert.Nil(err, "keys_and_cert.SigningPublicKey() returned error with valid data containing certificate")
_, err = keys_and_cert.Certificate()
assert.Nil(err, "keys_and_cert.Certificate() returned error with valid data containing certificate")
}
func TestReadKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T) {
@@ -292,10 +281,10 @@ func TestReadKeysAndCertWithValidDataWithoutCertificateAndRemainder(t *testing.T
}
assert.Nil(err)
_, err = keys_and_cert.GetPublicKey()
assert.Nil(err, "keys_and_cert.GetPublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.GetSigningPublicKey()
assert.Nil(err, "keys_and_cert.GetSigningPublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.GetCertificate()
assert.Nil(err, "keys_and_cert.GetCertificate() returned error with valid data not containing certificate")
_, err = keys_and_cert.PublicKey()
assert.Nil(err, "keys_and_cert.PublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.SigningPublicKey()
assert.Nil(err, "keys_and_cert.SigningPublicKey() returned error with valid data not containing certificate")
_, err = keys_and_cert.Certificate()
assert.Nil(err, "keys_and_cert.Certificate() returned error with valid data not containing certificate")
}

View File

@@ -1,10 +1,5 @@
package common
import (
"errors"
log "github.com/sirupsen/logrus"
)
/*
I2P Lease
https://geti2p.net/spec/common-structures#lease
@@ -36,73 +31,35 @@ end_date :: Date
// Sizes or various components of a Lease
const (
LEASE_SIZE = 44
LEASE_HASH_SIZE = 32
LEASE_TUNNEL_ID_SIZE = 4
LEASE_TUNNEL_DATE_SIZE = 8
LEASE_SIZE = 44
LEASE_HASH_SIZE = 32
LEASE_TUNNEL_ID_SIZE = 4
)
type LeaseInterface interface {
TunnelGateway() (hash Hash)
TunnelID() uint32
Date() (date Date)
}
type Lease struct {
LeaseHash Hash
TunnelIdent *Integer
TunnelDate Date
} //[LEASE_SIZE]byte
var li LeaseInterface = &Lease{}
type Lease [LEASE_SIZE]byte
//
// Return the first 32 bytes of the Lease as a Hash.
//
func (lease Lease) TunnelGateway() (hash Hash) {
copy(hash[:], lease.LeaseHash[:])
copy(hash[:], lease[:LEASE_HASH_SIZE])
return
}
//
// Return the TunnelID Integer in the Lease.
// Parse the TunnelID Integer in the Lease.
//
func (lease Lease) TunnelID() uint32 {
return uint32(lease.TunnelIdent.Value())
i := NewInteger(lease[LEASE_HASH_SIZE : LEASE_HASH_SIZE+LEASE_TUNNEL_ID_SIZE])
return uint32(
i.Int(),
)
}
//
// Return the Date inside the Lease.
//
func (lease Lease) Date() (date Date) {
copy(date[:], lease.TunnelDate[:])
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, lease.TunnelIdent.Bytes()...)
r = append(r, lease.TunnelDate[:]...)
return r
}
func ReadLease(data []byte) (lease Lease, remainder []byte, err error) {
if len(data) < LEASE_SIZE {
log.WithFields(log.Fields{
"at": "(Lease) ReadLease",
"data_len": len(data),
"required_len": "44",
"reason": "lease missing data",
}).Error("error parsnig lease")
err = errors.New("error parsing lease: lease missing data")
}
lease.LeaseHash, remainder, err = ReadHash(data)
identbytes, remainder, err := ReadIdent(remainder)
lease.TunnelIdent, err = NewInteger(identbytes[:])
lease.TunnelDate, remainder, err = ReadDate(remainder)
copy(date[:], lease[LEASE_HASH_SIZE+LEASE_TUNNEL_ID_SIZE:])
return
}

View File

@@ -1,40 +0,0 @@
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

@@ -82,6 +82,7 @@ signature :: Signature
import (
"errors"
"github.com/go-i2p/go-i2p/lib/crypto"
log "github.com/sirupsen/logrus"
)
@@ -93,44 +94,35 @@ const (
LEASE_SET_SIG_SIZE = 40
)
type LeaseSetInterface interface {
GetPublicKey() (public_key crypto.ElgPublicKey, err error)
GetSigningKey() (signing_public_key crypto.SigningPublicKey, err error)
Leases() (leases []Lease, err error)
/* LeaseCount() (count int, err error)*/
GetSignature() (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{}
type LeaseSet []byte
//
// Read a Destination from the LeaseSet.
//
func (lease_set LeaseSet) GetDestination() (destination Destination, err error) {
if &lease_set.Destination != nil {
destination = lease_set.Destination
} else {
err = errors.New("Error leaseset does not contain a destination")
}
func (lease_set LeaseSet) Destination() (destination Destination, err error) {
keys_and_cert, _, err := ReadKeysAndCert(lease_set)
destination = Destination(keys_and_cert)
return
}
//
// Return the PublicKey in this LeaseSet and any errors ancountered parsing the LeaseSet.
//
func (lease_set LeaseSet) GetPublicKey() (public_key crypto.ElgPublicKey, err error) {
public_key = lease_set.ElgPublicKey
func (lease_set LeaseSet) PublicKey() (public_key crypto.ElgPublicKey, err error) {
_, remainder, err := ReadKeysAndCert(lease_set)
remainder_len := len(remainder)
if remainder_len < LEASE_SET_PUBKEY_SIZE {
log.WithFields(log.Fields{
"at": "(LeaseSet) PublicKey",
"data_len": remainder_len,
"required_len": LEASE_SET_PUBKEY_SIZE,
"reason": "not enough data",
}).Error("error parsing public key")
err = errors.New("error parsing public key: not enough data")
copy(public_key[:], remainder)
return
}
copy(public_key[:], remainder[:LEASE_SET_PUBKEY_SIZE])
return
}
@@ -138,22 +130,56 @@ func (lease_set LeaseSet) GetPublicKey() (public_key crypto.ElgPublicKey, err er
// Return the SigningPublicKey, as specified in the LeaseSet's Destination's Key Certificate if
// present, or a legacy DSA key.
//
func (lease_set LeaseSet) GetSigningKey() (signing_public_key crypto.SigningPublicKey, err error) {
if lease_set.SigningPublicKey == nil {
func (lease_set LeaseSet) SigningKey() (signing_public_key crypto.SigningPublicKey, err error) {
destination, err := lease_set.Destination()
if err != nil {
return
}
offset := len(destination) + LEASE_SET_PUBKEY_SIZE
cert, err := destination.Certificate()
if err != nil {
return
}
cert_len := 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{
"at": "(LeaseSet) SigningKey",
"public": lease_set.SigningPublicKey,
"reason": "not enough data",
"at": "(LeaseSet) SigningKey",
"data_len": lease_set_len,
"required_len": offset + LEASE_SET_SPK_SIZE,
"reason": "not enough data",
}).Error("error parsing signing public key")
err = errors.New("error parsing signing public key: not enough data")
return
}
signing_public_key = lease_set.SigningPublicKey
return
}
if cert_len == 0 {
// 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 = KeyCertificateFromCertificate(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
}
func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
leases = lease_set.LeaseList
}
return
}
@@ -161,7 +187,65 @@ func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
// Return the number of Leases specified by the LeaseCount value in this LeaseSet.
//
func (lease_set LeaseSet) LeaseCount() (count int, err error) {
count = len(lease_set.LeaseList)
_, remainder, err := ReadKeysAndCert(lease_set)
if err != nil {
return
}
remainder_len := len(remainder)
if remainder_len < LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE+1 {
log.WithFields(log.Fields{
"at": "(LeaseSet) LeaseCount",
"data_len": remainder_len,
"required_len": LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1,
"reason": "not enough data",
}).Error("error parsing lease count")
err = errors.New("error parsing lease count: not enough data")
return
}
c := NewInteger([]byte{remainder[LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE]})
count = c.Int()
if count > 16 {
log.WithFields(log.Fields{
"at": "(LeaseSet) LeaseCount",
"lease_count": count,
"reason": "more than 16 leases",
}).Warn("invalid lease set")
err = errors.New("invalid lease set: more than 16 leases")
}
return
}
//
// Read the Leases in this LeaseSet, returning a partial set if there is insufficient data.
//
func (lease_set LeaseSet) Leases() (leases []Lease, err error) {
destination, err := lease_set.Destination()
if err != nil {
return
}
offset := len(destination) + LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1
count, err := lease_set.LeaseCount()
if err != nil {
return
}
for i := 0; i < count; i++ {
start := offset + (i * LEASE_SIZE)
end := start + LEASE_SIZE
lease_set_len := len(lease_set)
if lease_set_len < end {
log.WithFields(log.Fields{
"at": "(LeaseSet) Leases",
"data_len": lease_set_len,
"required_len": end,
"reason": "some leases missing",
}).Error("error parsnig lease set")
err = errors.New("error parsing lease set: some leases missing")
return
}
var lease Lease
copy(lease[:], lease_set[start:end])
leases = append(leases, lease)
}
return
}
@@ -169,14 +253,49 @@ func (lease_set LeaseSet) LeaseCount() (count int, err error) {
// Return the Signature data for the LeaseSet, as specified in the Destination's
// Key Certificate if present or the 40 bytes following the Leases.
//
func (lease_set LeaseSet) GetSignature() (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) +
LEASE_SET_PUBKEY_SIZE +
LEASE_SET_SPK_SIZE +
1 +
(LEASE_SIZE * lease_count)
cert, err := destination.Certificate()
if err != nil {
return
}
cert_type := cert.Type()
var end int
if cert_type == CERT_KEY {
end = start + KeyCertificateFromCertificate(cert).SignatureSize()
} else {
end = start + LEASE_SET_SIG_SIZE
}
lease_set_len := len(lease_set)
if lease_set_len < end {
log.WithFields(log.Fields{
"at": "(LeaseSet) Signature",
"data_len": lease_set_len,
"required_len": end,
"reason": "not enough data",
}).Error("error parsing signatre")
err = errors.New("error parsing signature: not enough data")
return
}
signature = []byte(lease_set[start:end])
return
}
//
//
//
/*
func (lease_set LeaseSet) Verify() error {
//data_end := len(destination) +
// LEASE_SET_PUBKEY_SIZE +
@@ -193,7 +312,7 @@ func (lease_set LeaseSet) Verify() error {
//}
return nil // verifier.Verify(data, lease_set.Signature())
}
*/
//
// Return the oldest date from all the Leases in the LeaseSet.
//
@@ -229,108 +348,3 @@ func (lease_set LeaseSet) OldestExpiration() (earliest Date, err error) {
}
return
}
func ReadLeaseSetSignature(bytes []byte, cert CertificateInterface) (signature Signature, remainder []byte, err error) {
start := 0
cert_type, _, _ := cert.Type()
var end int
if cert_type == CERT_KEY {
end = start + cert.SignatureSize()
} else {
end = start + LEASE_SET_SIG_SIZE
}
bytes_len := len(bytes)
if bytes_len < end {
log.WithFields(log.Fields{
"at": "(LeaseSet) Signature",
"data_len": bytes_len,
"required_len": end,
"reason": "not enough data",
}).Error("error parsing signatre")
err = errors.New("error parsing signature: not enough data")
signature = []byte(bytes[start:bytes_len])
return
}
signature = []byte(bytes[start:end])
return
}
func ReadLeaseCount(bytes []byte) (count *Integer, err error) {
remainder_len := len(bytes)
if remainder_len < LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE+1 {
log.WithFields(log.Fields{
"at": "(LeaseSet) LeaseCount",
"data_len": remainder_len,
"required_len": LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1,
"reason": "not enough data",
}).Error("error parsing lease count")
err = errors.New("error parsing lease count: not enough data")
return
}
count, err = NewInteger([]byte{bytes[LEASE_SET_PUBKEY_SIZE+LEASE_SET_SPK_SIZE]})
if count.Value() > 16 {
log.WithFields(log.Fields{
"at": "(LeaseSet) LeaseCount",
"lease_count": count,
"reason": "more than 16 leases",
}).Warn("invalid lease set")
err = errors.New("invalid lease set: more than 16 leases")
}
return
}
//
// Read the Leases in this LeaseSet, returning a partial set if there is insufficient data.
//
func ReadLeases(bytes []byte) (leases []Lease, remainder []byte, err error) {
count, err := ReadLeaseCount(bytes)
if err != nil {
return
}
for i := 0; i < count.Value(); i++ {
start := 0 //offset + (i * LEASE_SIZE)
end := start + LEASE_SIZE
lease_set_len := len(bytes)
if lease_set_len < end {
log.WithFields(log.Fields{
"at": "(LeaseSet) Leases",
"data_len": lease_set_len,
"required_len": end,
"reason": "some leases missing",
}).Error("error parsnig lease set")
err = errors.New("error parsing lease set: some leases missing")
return
}
var lease Lease
lease, remainder, err = ReadLease(bytes[start:end])
leases = append(leases, lease)
if err != nil {
return
}
}
return
}
func ReadLeaseSetKeys(data []byte, cert CertificateInterface) (spk crypto.SigningPublicKey, pk crypto.ElgPublicKey, remainder []byte, err error) {
spk, ppk, remainder, err := ReadKeys(data, cert)
switch ppk.(type) {
case crypto.ElgPublicKey:
pk = ppk.(crypto.ElgPublicKey)
default:
err = errors.New("LeaseSet1 uses Elgamal public keys.")
}
return
}
func ReadLeaseSet(data []byte) (lease_set LeaseSet, remainder []byte, err error) {
destination, remainder, err := ReadDestination(data)
lease_set.Destination = destination
//offset := len(destination.Bytes()) + LEASE_SET_PUBKEY_SIZE + LEASE_SET_SPK_SIZE + 1
spk, pk, remainder, err := ReadLeaseSetKeys(remainder, nil)
lease_set.SigningPublicKey = spk
lease_set.ElgPublicKey = pk
leases, remainder, err := ReadLeases(data)
lease_set.LeaseList = leases
return
}

View File

@@ -1,105 +0,0 @@
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
*/

View File

@@ -2,15 +2,15 @@ package common
import (
"bytes"
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func buildDestination() RouterIdentity {
router_ident_data := make([]byte, 128+256)
router_ident_data = append(router_ident_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}...)
rri, _, _ := ReadRouterIdentity(router_ident_data)
return rri
return RouterIdentity(router_ident_data)
}
func buildPublicKey() []byte {
@@ -55,34 +55,33 @@ func buildSignature(size int) []byte {
func buildFullLeaseSet(n int) LeaseSet {
lease_set_data := make([]byte, 0)
lease_set_data = append(lease_set_data, buildDestination().Bytes()...)
lease_set_data = append(lease_set_data, buildDestination()...)
lease_set_data = append(lease_set_data, buildPublicKey()...)
lease_set_data = append(lease_set_data, buildSigningKey()...)
lease_set_data = append(lease_set_data, byte(n))
lease_set_data = append(lease_set_data, buildLease(n)...)
lease_set_data = append(lease_set_data, buildSignature(64)...)
leaseSet, _, _ := ReadLeaseSet(lease_set_data)
return leaseSet
return LeaseSet(lease_set_data)
}
func TestDestinationIsCorrect(t *testing.T) {
assert := assert.New(t)
lease_set := buildFullLeaseSet(1)
dest, err := lease_set.GetDestination()
dest, err := lease_set.Destination()
assert.Nil(err)
dest_cert, err := dest.Certificate()
assert.Nil(err)
_, cert_bytes, err := dest_cert.Type()
cert_type := dest_cert.Type()
assert.Nil(err)
assert.Equal(CERT_KEY, cert_bytes)
assert.Equal(CERT_KEY, cert_type)
}
func TestPublicKeyIsCorrect(t *testing.T) {
assert := assert.New(t)
lease_set := buildFullLeaseSet(1)
pk, err := lease_set.GetPublicKey()
pk, err := lease_set.PublicKey()
if assert.Nil(err) {
assert.Equal(
0,
@@ -98,7 +97,7 @@ func TestSigningKeyIsCorrect(t *testing.T) {
assert := assert.New(t)
lease_set := buildFullLeaseSet(1)
sk, err := lease_set.GetSigningKey()
sk, err := lease_set.SigningKey()
if assert.Nil(err) {
assert.Equal(128, sk.Len())
}
@@ -156,7 +155,7 @@ func TestLeasesHaveCorrectData(t *testing.T) {
0,
bytes.Compare(
lease,
leases[i].Bytes()[:],
leases[i][:],
),
)
}
@@ -168,7 +167,7 @@ func TestSignatureIsCorrect(t *testing.T) {
assert := assert.New(t)
lease_set := buildFullLeaseSet(1)
sig, err := lease_set.GetSignature()
sig, err := lease_set.Signature()
if assert.Nil(err) {
assert.Equal(
0,

View File

@@ -28,25 +28,27 @@ val_string :: String
import (
"encoding/binary"
"errors"
log "github.com/sirupsen/logrus"
"sort"
log "github.com/sirupsen/logrus"
)
type Mapping []byte
// Parsed key-values pairs inside a Mapping.
type MappingValues [][2]String
type MappingValues [][2]I2PString
//
// Returns the values contained in a Mapping in the form of a MappingValues.
//
func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
var str String
var str I2PString
var remainder = mapping
var err error
length, err := NewInteger(remainder[:2])
inferred_length := length.Value() + 2
l := NewInteger(remainder[:2])
length := l.Int()
inferred_length := length + 2
remainder = remainder[2:]
mapping_len := len(mapping)
if mapping_len > inferred_length {
@@ -72,7 +74,7 @@ func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
for {
// Read a key, breaking on fatal errors
// and appending warnings
str, remainder, err = ReadString(remainder)
str, remainder, err = ReadI2PString(remainder)
key_str := str
if err != nil {
if stopValueRead(err) {
@@ -92,7 +94,7 @@ func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
// Read a value, breaking on fatal errors
// and appending warnings
str, remainder, err = ReadString(remainder)
str, remainder, err = ReadI2PString(remainder)
val_str := str
if err != nil {
if stopValueRead(err) {
@@ -111,7 +113,7 @@ func (mapping Mapping) Values() (map_values MappingValues, errs []error) {
remainder = remainder[1:]
// Append the key-value pair and break if there is no more data to read
map_values = append(map_values, [2]String{key_str, val_str})
map_values = append(map_values, [2]I2PString{key_str, val_str})
if len(remainder) == 0 {
break
}
@@ -174,7 +176,7 @@ func GoMapToMapping(gomap map[string]string) (mapping Mapping, err error) {
}
map_vals = append(
map_vals,
[2]String{key_str, val_str},
[2]I2PString{key_str, val_str},
)
}
mapping = ValuesToMapping(map_vals)

View File

@@ -3,8 +3,9 @@ package common
import (
"bytes"
"errors"
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestValuesExclusesPairWithBadData(t *testing.T) {
@@ -116,10 +117,10 @@ func TestMappingOrderSortsValuesThenKeys(t *testing.T) {
a, _ := ToI2PString("a")
b, _ := ToI2PString("b")
values := MappingValues{
[2]String{b, b},
[2]String{b, a},
[2]String{a, b},
[2]String{a, a},
[2]I2PString{b, b},
[2]I2PString{b, a},
[2]I2PString{a, b},
[2]I2PString{a, a},
}
mappingOrder(values)
for i, pair := range values {

View File

@@ -37,6 +37,7 @@ options :: Mapping
import (
"errors"
log "github.com/sirupsen/logrus"
)
@@ -51,12 +52,13 @@ type RouterAddress []byte
// Return the cost integer for this RouterAddress and any errors encountered
// parsing the RouterAddress.
//
func (router_address RouterAddress) Cost() (cost *Integer, err error) {
func (router_address RouterAddress) Cost() (cost int, err error) {
err, exit := router_address.checkValid()
if exit {
return
}
cost, err = NewInteger([]byte{router_address[0]})
c := NewInteger([]byte{router_address[0]})
cost = c.Int()
return
}
@@ -77,12 +79,12 @@ func (router_address RouterAddress) Expiration() (date Date, err error) {
// Return the Transport type for this RouterAddress and any errors encountered
// parsing the RouterAddress.
//
func (router_address RouterAddress) TransportStyle() (str String, err error) {
func (router_address RouterAddress) TransportStyle() (str I2PString, err error) {
err, exit := router_address.checkValid()
if exit {
return
}
str, _, err = ReadString(router_address[ROUTER_ADDRESS_MIN_SIZE:])
str, _, err = ReadI2PString(router_address[ROUTER_ADDRESS_MIN_SIZE:])
return
}
@@ -95,7 +97,7 @@ func (router_address RouterAddress) Options() (mapping Mapping, err error) {
if exit {
return
}
_, remainder, err := ReadString(router_address[ROUTER_ADDRESS_MIN_SIZE:])
_, remainder, err := ReadI2PString(router_address[ROUTER_ADDRESS_MIN_SIZE:])
if len(remainder) == 0 {
return
}
@@ -137,22 +139,23 @@ func ReadRouterAddress(data []byte) (router_address RouterAddress, remainder []b
return
}
router_address = append(router_address, data[:ROUTER_ADDRESS_MIN_SIZE]...)
str, remainder, err := ReadString(data[ROUTER_ADDRESS_MIN_SIZE:])
str, remainder, err := ReadI2PString(data[ROUTER_ADDRESS_MIN_SIZE:])
if err != nil {
return
}
router_address = append(router_address, str...)
map_size := &Integer{}
map_size := 0
mapping := make([]byte, 0)
if len(remainder) >= 2 {
map_size, err = NewInteger(remainder[:2])
if len(remainder) < map_size.Value()+2 {
ms := NewInteger(remainder[:2])
map_size = ms.Int()
if len(remainder) < map_size+2 {
err = errors.New("not enough data for map inside router address")
router_address = RouterAddress([]byte{})
remainder = []byte{}
return
}
mapping = remainder[:map_size.Value()+2]
mapping = remainder[:map_size+2]
router_address = append(router_address, mapping...)
}

View File

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

View File

@@ -75,6 +75,7 @@ signature :: Signature
import (
"errors"
log "github.com/sirupsen/logrus"
)
@@ -97,7 +98,7 @@ func (router_info RouterInfo) IdentHash() (h Hash, err error) {
var ri RouterIdentity
ri, err = router_info.RouterIdentity()
if err == nil {
h = HashData(ri.Bytes())
h = HashData(ri)
}
return
}
@@ -128,7 +129,7 @@ func (router_info RouterInfo) Published() (date Date, err error) {
//
// Return the Integer representing the number of RouterAddresses that are contained in this RouterInfo.
//
func (router_info RouterInfo) RouterAddressCount() (count *Integer, err error) {
func (router_info RouterInfo) RouterAddressCount() (count int, err error) {
_, remainder, err := ReadRouterIdentity(router_info)
if err != nil {
return
@@ -144,7 +145,8 @@ func (router_info RouterInfo) RouterAddressCount() (count *Integer, err error) {
err = errors.New("error parsing router addresses: not enough data")
return
}
count, err = NewInteger([]byte{remainder[8]})
c := NewInteger([]byte{remainder[8]})
count = c.Int()
return
}
@@ -175,7 +177,7 @@ func (router_info RouterInfo) RouterAddresses() (router_addresses []RouterAddres
err = cerr
return
}
for i := 0; i < addr_count.Value(); i++ {
for i := 0; i < addr_count; i++ {
router_address, remaining, err = ReadRouterAddress(remaining)
if err == nil {
router_addresses = append(router_addresses, router_address)
@@ -198,7 +200,7 @@ func (router_info RouterInfo) PeerSize() int {
//
func (router_info RouterInfo) Options() (mapping Mapping) {
head := router_info.optionsLocation()
size := head + router_info.optionsSize().Value()
size := head + router_info.optionsSize()
mapping = Mapping(router_info[head:size])
return
}
@@ -208,9 +210,9 @@ func (router_info RouterInfo) Options() (mapping Mapping) {
//
func (router_info RouterInfo) Signature() (signature Signature) {
head := router_info.optionsLocation()
size := head + router_info.optionsSize().Value()
size := head + router_info.optionsSize()
ident, _ := router_info.RouterIdentity()
keyCert := ident.CertificateInterface //KeyCertificate(ident)
keyCert, _ := NewKeyCertificate(ident)
sigSize := keyCert.SignatureSize()
signature = Signature(router_info[size : size+sigSize])
return
@@ -224,7 +226,7 @@ func (router_info RouterInfo) optionsLocation() (location int) {
if err != nil {
return
}
location += len(data.Bytes())
location += len(data)
remainder_len := len(remainder)
if remainder_len < 9 {
@@ -247,7 +249,7 @@ func (router_info RouterInfo) optionsLocation() (location int) {
err = cerr
return
}
for i := 0; i < addr_count.Value(); i++ {
for i := 0; i < addr_count; i++ {
router_address, remaining, err = ReadRouterAddress(remaining)
if err == nil {
location += len(router_address)
@@ -261,8 +263,9 @@ func (router_info RouterInfo) optionsLocation() (location int) {
//
// Used during parsing to determine the size of the options in the RouterInfo.
//
func (router_info RouterInfo) optionsSize() (size *Integer) {
func (router_info RouterInfo) optionsSize() (size int) {
head := router_info.optionsLocation()
size, _ = NewInteger(router_info[head : head+2]) //+ 2
s := NewInteger(router_info[head : head+2])
size = s.Int() + 2
return
}

View File

@@ -10,11 +10,7 @@ import (
func buildRouterIdentity() RouterIdentity {
router_ident_data := make([]byte, 128+256)
router_ident_data = append(router_ident_data, []byte{0x05, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00}...)
b, _, err := ReadRouterIdentity(router_ident_data)
if err != nil {
panic(err)
}
return b
return RouterIdentity(router_ident_data)
}
func buildDate() []byte {
@@ -37,7 +33,7 @@ func buildRouterAddress(transport string) RouterAddress {
func buildFullRouterInfo() RouterInfo {
router_info_data := make([]byte, 0)
router_info_data = append(router_info_data, buildRouterIdentity().Bytes()...)
router_info_data = append(router_info_data, buildRouterIdentity()...)
router_info_data = append(router_info_data, buildDate()...)
router_info_data = append(router_info_data, 0x01)
router_info_data = append(router_info_data, buildRouterAddress("foo")...)
@@ -120,7 +116,7 @@ func TestRouterAddressesReturnsAddressesWithMultiple(t *testing.T) {
assert := assert.New(t)
router_info_data := make([]byte, 0)
router_info_data = append(router_info_data, buildRouterIdentity().Bytes()...)
router_info_data = append(router_info_data, buildRouterIdentity()...)
router_info_data = append(router_info_data, buildDate()...)
router_info_data = append(router_info_data, 0x03)
router_info_data = append(router_info_data, buildRouterAddress("foo0")...)
@@ -188,8 +184,8 @@ func TestRouterIdentityIsCorrect(t *testing.T) {
assert.Equal(
0,
bytes.Compare(
[]byte(buildRouterIdentity().Bytes()),
[]byte(router_identity.Bytes()),
[]byte(buildRouterIdentity()),
[]byte(router_identity),
),
)
}

View File

@@ -1,13 +1,14 @@
package common
/*
I2P String
I2P I2PString
https://geti2p.net/spec/common-structures#string
Accurate for version 0.9.24
*/
import (
"errors"
log "github.com/sirupsen/logrus"
)
@@ -16,27 +17,28 @@ const (
STRING_MAX_SIZE = 255
)
type String []byte
type I2PString []byte
//
// Look up the length of the string, reporting errors if the string is
// invalid or the specified length does not match the provided data.
//
func (str String) Length() (length *Integer, err error) {
func (str I2PString) Length() (length int, err error) {
if len(str) == 0 {
log.WithFields(log.Fields{
"at": "(String) Length",
"at": "(I2PString) Length",
"reason": "no data",
}).Error("error parsing string")
err = errors.New("error parsing string: zero length")
return
}
length, err = NewInteger([]byte{byte(str[0])})
inferred_len := length.Value() + 1
l := NewInteger([]byte{byte(str[0])})
length = l.Int()
inferred_len := length + 1
str_len := len(str)
if inferred_len > str_len {
log.WithFields(log.Fields{
"at": "(String) Length",
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
@@ -45,7 +47,7 @@ func (str String) Length() (length *Integer, err error) {
err = errors.New("string parsing warning: string data is shorter than specified by length")
} else if str_len > inferred_len {
log.WithFields(log.Fields{
"at": "(String) Length",
"at": "(I2PString) Length",
"string_bytes_length": str_len,
"string_length_field": length,
"expected_bytes_length": inferred_len,
@@ -59,7 +61,7 @@ func (str String) Length() (length *Integer, err error) {
//
// Return the string data and any errors encountered by Length.
//
func (str String) Data() (data string, err error) {
func (str I2PString) Data() (data string, err error) {
length, err := str.Length()
if err != nil {
switch err.Error() {
@@ -69,7 +71,7 @@ func (str String) Data() (data string, err error) {
data = string(str[1:])
return
case "string parsing warning: string contains data beyond length":
data = string(str[1 : length.Value()+1])
data = string(str[1 : length+1])
return
}
}
@@ -78,14 +80,14 @@ func (str String) Data() (data string, err error) {
}
//
// This function takes an unformatted Go string and returns a String
// This function takes an unformatted Go string and returns a I2PString
// and any errors encountered during the encoding.
//
func ToI2PString(data string) (str String, err error) {
func ToI2PString(data string) (str I2PString, err error) {
data_len := len(data)
if data_len > STRING_MAX_SIZE {
log.WithFields(log.Fields{
"at": "ToI2PString",
"at": "ToI2PI2PString",
"string_len": data_len,
"max_len": STRING_MAX_SIZE,
"reason": "too much data",
@@ -95,20 +97,20 @@ func ToI2PString(data string) (str String, err error) {
}
i2p_string := []byte{byte(data_len)}
i2p_string = append(i2p_string, []byte(data)...)
str = String(i2p_string)
str = I2PString(i2p_string)
return
}
//
// Read a string from a slice of bytes, returning any extra data on the end
// of the slice and any errors encountered parsing the String.
// of the slice and any errors encountered parsing the I2PString.
//
func ReadString(data []byte) (str String, remainder []byte, err error) {
str = String(data)
length, err := String(data).Length()
func ReadI2PString(data []byte) (str I2PString, remainder []byte, err error) {
str = I2PString(data)
length, err := I2PString(data).Length()
if err != nil && err.Error() == "string parsing warning: string contains data beyond length" {
str = String(data[:length.Value()+1])
remainder = data[length.Value()+1:]
str = I2PString(data[:length+1])
remainder = data[length+1:]
err = nil
}
return

View File

@@ -1,23 +1,24 @@
package common
import (
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestStringReportsCorrectLength(t *testing.T) {
assert := assert.New(t)
str_len, err := String([]byte{0x02, 0x00, 0x00}).Length()
str_len, err := I2PString([]byte{0x02, 0x00, 0x00}).Length()
assert.Equal(str_len, 2, "Length() did not report correct length")
assert.Nil(err, "Length() reported an error on valid string")
}
func TestStringReportsLengthZeroError(t *testing.T) {
func TestI2PStringReportsLengthZeroError(t *testing.T) {
assert := assert.New(t)
str_len, err := String(make([]byte, 0)).Length()
str_len, err := I2PString(make([]byte, 0)).Length()
assert.Equal(str_len, 0, "Length() reported non-zero length on empty slice")
if assert.NotNil(err) {
@@ -25,10 +26,10 @@ func TestStringReportsLengthZeroError(t *testing.T) {
}
}
func TestStringReportsExtraDataError(t *testing.T) {
func TestI2PStringReportsExtraDataError(t *testing.T) {
assert := assert.New(t)
str_len, err := String([]byte{0x01, 0x00, 0x00}).Length()
str_len, err := I2PString([]byte{0x01, 0x00, 0x00}).Length()
assert.Equal(str_len, 1, "Length() reported wrong size when extra data present")
if assert.NotNil(err) {
@@ -36,10 +37,10 @@ func TestStringReportsExtraDataError(t *testing.T) {
}
}
func TestStringDataReportsLengthZeroError(t *testing.T) {
func TestI2PStringDataReportsLengthZeroError(t *testing.T) {
assert := assert.New(t)
str_len, err := String([]byte{0x01}).Length()
str_len, err := I2PString([]byte{0x01}).Length()
assert.Equal(str_len, 1, "Length() reported wrong size with missing data")
if assert.NotNil(err) {
@@ -47,10 +48,10 @@ func TestStringDataReportsLengthZeroError(t *testing.T) {
}
}
func TestStringDataReportsExtraDataError(t *testing.T) {
func TestI2PStringDataReportsExtraDataError(t *testing.T) {
assert := assert.New(t)
data, err := String([]byte{0x01, 0x00, 0x01}).Data()
data, err := I2PString([]byte{0x01, 0x00, 0x01}).Data()
data_len := len(data)
assert.Equal(data_len, 1, "Data() reported wrong size on string with extra data")
@@ -59,10 +60,10 @@ func TestStringDataReportsExtraDataError(t *testing.T) {
}
}
func TestStringDataEmptyWhenZeroLength(t *testing.T) {
func TestI2PStringDataEmptyWhenZeroLength(t *testing.T) {
assert := assert.New(t)
data, err := String(make([]byte, 0)).Data()
data, err := I2PString(make([]byte, 0)).Data()
assert.Equal(len(data), 0, "Data() returned data when none was present:")
if assert.NotNil(err) {
@@ -70,10 +71,10 @@ func TestStringDataEmptyWhenZeroLength(t *testing.T) {
}
}
func TestStringDataErrorWhenNonZeroLengthOnly(t *testing.T) {
func TestI2PStringDataErrorWhenNonZeroLengthOnly(t *testing.T) {
assert := assert.New(t)
data, err := String([]byte{0x01}).Data()
data, err := I2PString([]byte{0x01}).Data()
assert.Equal(len(data), 0, "Data() returned data when only length was present")
if assert.NotNil(err) {
@@ -81,7 +82,7 @@ func TestStringDataErrorWhenNonZeroLengthOnly(t *testing.T) {
}
}
func TestToI2PStringFormatsCorrectly(t *testing.T) {
func TestToI2PI2PStringFormatsCorrectly(t *testing.T) {
assert := assert.New(t)
i2p_string, err := ToI2PString(string([]byte{0x08, 0x09}))
@@ -111,38 +112,38 @@ func TestReadStringReadsLength(t *testing.T) {
assert := assert.New(t)
bytes := []byte{0x01, 0x04, 0x06}
str, remainder, err := ReadString(bytes)
str, remainder, err := ReadI2PString(bytes)
assert.Nil(err, "ReadString() returned error reading string with extra data")
assert.Equal(len(str), 2, "ReadString() did not return correct string length")
assert.Equal(1, int(str[0]), "ReadString() did not return correct string")
assert.Equal(4, int(str[1]), "ReadString() did not return correct string")
assert.Equal(len(remainder), 1, "ReadString() did not return correct remainder length")
assert.Equal(6, int(remainder[0]), "ReadString() did not return correct remainder")
assert.Nil(err, "ReadI2PString() returned error reading string with extra data")
assert.Equal(len(str), 2, "ReadI2PString() did not return correct string length")
assert.Equal(1, int(str[0]), "ReadI2PString() did not return correct string")
assert.Equal(4, int(str[1]), "ReadI2PString() did not return correct string")
assert.Equal(len(remainder), 1, "ReadI2PString() did not return correct remainder length")
assert.Equal(6, int(remainder[0]), "ReadI2PString() did not return correct remainder")
}
func TestReadStringErrWhenEmptySlice(t *testing.T) {
func TestReadI2PStringErrWhenEmptySlice(t *testing.T) {
assert := assert.New(t)
bytes := make([]byte, 0)
_, _, err := ReadString(bytes)
_, _, err := ReadI2PString(bytes)
if assert.NotNil(err) {
assert.Equal(err.Error(), "error parsing string: zero length", "correct error message should be returned")
}
}
func TestReadStringErrWhenDataTooShort(t *testing.T) {
func TestReadI2PStringErrWhenDataTooShort(t *testing.T) {
assert := assert.New(t)
short_str := []byte{0x03, 0x01}
str, remainder, err := ReadString(short_str)
str, remainder, err := ReadI2PString(short_str)
if assert.NotNil(err) {
assert.Equal(err.Error(), "string parsing warning: string data is shorter than specified by length", "correct error message should be returned")
}
assert.Equal(len(str), 2, "ReadString() did not return the slice as string when too long")
assert.Equal(3, int(str[0]), "ReadString() did not return the correct partial string")
assert.Equal(1, int(str[1]), "ReadString() did not return the correct partial string")
assert.Equal(len(remainder), 0, "ReadString() returned a remainder when the string data was too short")
assert.Equal(len(str), 2, "ReadI2PString() did not return the slice as string when too long")
assert.Equal(3, int(str[0]), "ReadI2PString() did not return the correct partial string")
assert.Equal(1, int(str[1]), "ReadI2PString() did not return the correct partial string")
assert.Equal(len(remainder), 0, "ReadI2PString() returned a remainder when the string data was too short")
}

View File

@@ -1,54 +1,37 @@
package crypto
/*
#cgo pkg-config: libsodium
#include <sodium.h>
#include <stdint.h>
*/
import "C"
import (
"crypto/ed25519"
"crypto/sha512"
"errors"
"fmt"
)
type Ed25519PublicKey [32]byte
type Ed25519PublicKey []byte
type Ed25519Verifier struct {
k [32]C.uchar
k []byte
}
func (k Ed25519PublicKey) NewVerifier() (v Verifier, err error) {
ev := new(Ed25519Verifier)
for i, b := range k {
ev.k[i] = C.uchar(b)
}
v = ev
return
temp := new(Ed25519Verifier)
temp.k = k
v = temp
return temp, nil
}
func (v *Ed25519Verifier) VerifyHash(h, sig []byte) (err error) {
if len(sig) == C.crypto_sign_BYTES {
// valid size of sig
// copy signature and hash
var csig, ch [32]C.uchar
for i, b := range h {
ch[i] = C.uchar(b)
}
for i, b := range sig {
csig[i] = C.uchar(b)
}
// verify
if C.crypto_sign_verify_detached(&csig[0], &ch[0], C.ulonglong(32), &v.k[0]) == 0 {
// valid signature
} else {
// bad signature
err = ErrInvalidSignature
}
} else {
// bad size of sig
if len(sig) != ed25519.SignatureSize {
err = ErrBadSignatureSize
return
}
if len(v.k) != ed25519.PublicKeySize {
err = errors.New("failed to verify: invalid ed25519 public key size")
return
}
ok := ed25519.Verify(v.k, h, sig)
if !ok {
err = errors.New("failed to verify: invalid signature")
}
return
}
@@ -59,35 +42,23 @@ func (v *Ed25519Verifier) Verify(data, sig []byte) (err error) {
return
}
type Ed25519PrivateKey [32]byte
type Ed25519PrivateKey ed25519.PrivateKey
type Ed25519Signer struct {
k [32]C.uchar
k []byte
}
func (s *Ed25519Signer) Sign(data []byte) (sig []byte, err error) {
if len(s.k) != ed25519.PrivateKeySize {
err = errors.New("failed to sign: invalid ed25519 private key size")
return
}
h := sha512.Sum512(data)
sig, err = s.SignHash(h[:])
return
}
func (s *Ed25519Signer) SignHash(h []byte) (sig []byte, err error) {
var ch [32]C.uchar
for i, b := range h {
ch[i] = C.uchar(b)
}
var csig [32]C.uchar
var smlen_p C.ulonglong
res := C.crypto_sign_detached(&csig[0], &smlen_p, &ch[0], C.ulonglong(32), &s.k[0])
if res == 0 {
// success signing
sig = make([]byte, 32)
for i, b := range csig {
sig[i] = byte(b)
}
} else {
// failed signing
err = errors.New(fmt.Sprintf("failed to sign: crypto_sign_detached exit code %d", int(res)))
}
sig = ed25519.Sign(s.k, h)
return
}

View File

@@ -1,9 +1,42 @@
package crypto
import (
"crypto/ed25519"
"crypto/rand"
"io"
"testing"
)
func TestEd25519(t *testing.T) {
var pubKey Ed25519PublicKey
signer := new(Ed25519Signer)
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Log("Failed to generate ed25519 test key")
t.Fail()
}
pubKey = []byte(pub)
signer.k = []byte(priv)
message := make([]byte, 123)
io.ReadFull(rand.Reader, message)
sig, err := signer.Sign(message)
if err != nil {
t.Log("Failed to sign message")
t.Fail()
}
verifier, err := pubKey.NewVerifier()
if err != nil {
t.Logf("Error from verifier: %s", err)
t.Fail()
}
err = verifier.Verify(message, sig)
if err != nil {
t.Log("Failed to verify message")
t.Fail()
}
}