Skip to content

Commit

Permalink
security: Add ed25519 signer (#92)
Browse files Browse the repository at this point in the history
* security: Add ed25519 signer

Fix: #91
  • Loading branch information
zjkmxy authored Jan 2, 2025
1 parent be1788d commit e6a1870
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 66 deletions.
38 changes: 38 additions & 0 deletions std/security/asym-signer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package security

import (
"time"

enc "github.com/named-data/ndnd/std/encoding"
"github.com/named-data/ndnd/std/ndn"
"github.com/named-data/ndnd/std/utils"
)

// asymSigner is a base class of signer used for asymmetric keys.
type asymSigner struct {
timer ndn.Timer
seq uint64

keyLocatorName enc.Name
forCert bool
forInt bool
certExpireTime time.Duration
}

func (s *asymSigner) genSigInfo(sigType ndn.SigType) (*ndn.SigConfig, error) {
ret := &ndn.SigConfig{
Type: sigType,
KeyName: s.keyLocatorName,
}
if s.forCert {
ret.NotBefore = utils.IdPtr(s.timer.Now())
ret.NotAfter = utils.IdPtr(s.timer.Now().Add(s.certExpireTime))
}
if s.forInt {
s.seq++
ret.Nonce = s.timer.Nonce()
ret.SigTime = utils.IdPtr(s.timer.Now())
ret.SeqNum = utils.IdPtr(s.seq)
}
return ret, nil
}
47 changes: 14 additions & 33 deletions std/security/ecc-signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,17 @@ import (
enc "github.com/named-data/ndnd/std/encoding"
basic_engine "github.com/named-data/ndnd/std/engine/basic"
"github.com/named-data/ndnd/std/ndn"
"github.com/named-data/ndnd/std/utils"
)

// eccSigner is a signer that uses ECC key to sign packets.
type eccSigner struct {
timer ndn.Timer
seq uint64

keyLocatorName enc.Name
key *ecdsa.PrivateKey
keyLen uint
forCert bool
forInt bool
certExpireTime time.Duration
asymSigner
keyLen uint
key *ecdsa.PrivateKey
}

func (s *eccSigner) SigInfo() (*ndn.SigConfig, error) {
ret := &ndn.SigConfig{
Type: ndn.SignatureSha256WithEcdsa,
KeyName: s.keyLocatorName,
}
if s.forCert {
ret.NotBefore = utils.IdPtr(s.timer.Now())
ret.NotAfter = utils.IdPtr(s.timer.Now().Add(s.certExpireTime))
}
if s.forInt {
s.seq++
ret.Nonce = s.timer.Nonce()
ret.SigTime = utils.IdPtr(s.timer.Now())
ret.SeqNum = utils.IdPtr(s.seq)
}
return ret, nil
return s.genSigInfo(ndn.SignatureSha256WithEcdsa)
}

func (s *eccSigner) EstimateSize() uint {
Expand All @@ -67,13 +46,15 @@ func NewEccSigner(
keyLen := uint(key.Curve.Params().BitSize*2+7) / 8
keyLen += keyLen%2 + 8
return &eccSigner{
timer: basic_engine.Timer{},
seq: 0,
keyLocatorName: keyLocatorName,
key: key,
keyLen: keyLen,
forCert: forCert,
forInt: forInt,
certExpireTime: expireTime,
asymSigner: asymSigner{
timer: basic_engine.Timer{},
seq: 0,
keyLocatorName: keyLocatorName,
forCert: forCert,
forInt: forInt,
certExpireTime: expireTime,
},
keyLen: keyLen,
key: key,
}
}
51 changes: 51 additions & 0 deletions std/security/ed-signer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package security

import (
"crypto/ed25519"
"time"

enc "github.com/named-data/ndnd/std/encoding"
basic_engine "github.com/named-data/ndnd/std/engine/basic"
"github.com/named-data/ndnd/std/ndn"
)

// edSigner is a signer that uses Ed25519 key to sign packets.
type edSigner struct {
asymSigner
key ed25519.PrivateKey
}

func (s *edSigner) SigInfo() (*ndn.SigConfig, error) {
return s.genSigInfo(ndn.SignatureEd25519)
}

func (s *edSigner) EstimateSize() uint {
return ed25519.SignatureSize
}

func (s *edSigner) ComputeSigValue(covered enc.Wire) ([]byte, error) {
return ed25519.Sign(s.key, covered.Join()), nil
}

// NewEdSigner creates a signer using ed25519 key
func NewEdSigner(
forCert bool, forInt bool, expireTime time.Duration, key ed25519.PrivateKey,
keyLocatorName enc.Name,
) ndn.Signer {
return &edSigner{
asymSigner: asymSigner{
timer: basic_engine.Timer{},
seq: 0,
keyLocatorName: keyLocatorName,
forCert: forCert,
forInt: forInt,
certExpireTime: expireTime,
},
key: key,
}
}

// Ed25519DerivePubKey derives the public key from a private key.
func Ed25519DerivePubKey(privKey ed25519.PrivateKey) ed25519.PublicKey {
return ed25519.PublicKey(privKey[ed25519.PublicKeySize:])
}
48 changes: 15 additions & 33 deletions std/security/rsa-signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,17 @@ import (
enc "github.com/named-data/ndnd/std/encoding"
basic_engine "github.com/named-data/ndnd/std/engine/basic"
"github.com/named-data/ndnd/std/ndn"
"github.com/named-data/ndnd/std/utils"
)

// rsaSigner is a signer that uses ECC key to sign packets.
type rsaSigner struct {
timer ndn.Timer
seq uint64

keyLocatorName enc.Name
key *rsa.PrivateKey
keyLen uint
forCert bool
forInt bool
certExpireTime time.Duration
asymSigner
keyLen uint
key *rsa.PrivateKey
}

func (s *rsaSigner) SigInfo() (*ndn.SigConfig, error) {
ret := &ndn.SigConfig{
Type: ndn.SignatureSha256WithEcdsa,
KeyName: s.keyLocatorName,
}
if s.forCert {
ret.NotBefore = utils.IdPtr(s.timer.Now())
ret.NotAfter = utils.IdPtr(s.timer.Now().Add(s.certExpireTime))
}
if s.forInt {
s.seq++
ret.Nonce = s.timer.Nonce()
ret.SigTime = utils.IdPtr(s.timer.Now())
ret.SeqNum = utils.IdPtr(s.seq)
}
return ret, nil
return s.genSigInfo(ndn.SignatureSha256WithRsa)
}

func (s *rsaSigner) EstimateSize() uint {
Expand All @@ -66,13 +45,16 @@ func NewRsaSigner(
) ndn.Signer {
keyLen := uint(key.Size())
return &rsaSigner{
timer: basic_engine.Timer{},
seq: 0,
keyLocatorName: keyLocatorName,
key: key,
keyLen: keyLen,
forCert: forCert,
forInt: forInt,
certExpireTime: expireTime,
asymSigner: asymSigner{
timer: basic_engine.Timer{},
seq: 0,
keyLocatorName: keyLocatorName,

forCert: forCert,
forInt: forInt,
certExpireTime: expireTime,
},
key: key,
keyLen: keyLen,
}
}
95 changes: 95 additions & 0 deletions std/security/signers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package security_test

import (
"crypto/ed25519"
"crypto/x509"
"encoding/base64"
"testing"
"time"

enc "github.com/named-data/ndnd/std/encoding"
"github.com/named-data/ndnd/std/ndn"
"github.com/named-data/ndnd/std/ndn/spec_2022"
"github.com/named-data/ndnd/std/security"
"github.com/named-data/ndnd/std/utils"
"github.com/stretchr/testify/require"
)

func TestEddsaSignerBasic(t *testing.T) {
utils.SetTestingT(t)

keyLocatorName := utils.WithoutErr(enc.NameFromStr("/test/KEY/1"))
edkeybits := ed25519.NewKeyFromSeed([]byte("01234567890123456789012345678901"))
signer := security.NewEdSigner(
false, false, 0, edkeybits, keyLocatorName,
)

require.Equal(t, uint(ed25519.SignatureSize), signer.EstimateSize())
signInfo := utils.WithoutErr(signer.SigInfo())
require.Equal(t, 0, signInfo.KeyName.Compare(keyLocatorName))
require.Equal(t, ndn.SignatureEd25519, signInfo.Type)

dataVal := enc.Wire{[]byte(
"\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix" +
"\x14\x03\x18\x01\x00")}
sigValue := utils.WithoutErr(signer.ComputeSigValue(dataVal))

// For basic test, we use ed25519.Verify to verify the signature.
require.True(t, ed25519.Verify(security.Ed25519DerivePubKey(edkeybits), dataVal.Join(), sigValue))
}

func TestEddsaSignerCertificate(t *testing.T) {
utils.SetTestingT(t)

spec := spec_2022.Spec{}

keyLocatorName := utils.WithoutErr(enc.NameFromStr("/test/KEY/1"))
certName := utils.WithoutErr(enc.NameFromStr("/test/KEY/1/self/1"))
edkeybits := ed25519.NewKeyFromSeed([]byte("01234567890123456789012345678901"))
signer := security.NewEdSigner(
false, false, 3600*time.Second, edkeybits, keyLocatorName,
)
pubKey := security.Ed25519DerivePubKey(edkeybits)
pubKeyBits := utils.WithoutErr(x509.MarshalPKIXPublicKey(pubKey))

cert := utils.WithoutErr(spec.MakeData(certName, &ndn.DataConfig{
ContentType: utils.IdPtr(ndn.ContentTypeKey),
Freshness: utils.IdPtr(3600 * time.Second),
}, enc.Wire{pubKeyBits}, signer))

data, covered, err := spec.ReadData(enc.NewWireReader(cert.Wire))
require.NoError(t, err)

pubKeyParsedBits := data.Content().Join()
pubKeyParsedUntyped := utils.WithoutErr(x509.ParsePKIXPublicKey(pubKeyParsedBits))
if pubKeyParsed := pubKeyParsedUntyped.(ed25519.PublicKey); pubKeyParsed != nil {
require.True(t, security.EddsaValidate(covered, data.Signature(), pubKeyParsed))
} else {
require.Fail(t, "unexpected public key type")
}
}

// TestEddsaSignerCertificate2 tests the validator using a given certificate for interoperability.
func TestEddsaSignerCertificate2(t *testing.T) {
utils.SetTestingT(t)

const TestCert = `
Bv0BCgc1CAxFZDI1NTE5LWRlbW8IA0tFWQgQNWE2MTVkYjdjZjA2MDNiNQgEc2Vs
ZjYIAAABgQD8AY0UCRgBAhkEADbugBUsMCowBQYDK2VwAyEAQxUZBL+3I3D4oDIJ
tJvuCTguHM7AUbhlhA/wu8ZhrkwWVhsBBRwnByUIDEVkMjU1MTktZGVtbwgDS0VZ
CBA1YTYxNWRiN2NmMDYwM2I1/QD9Jv0A/g8xOTcwMDEwMVQwMDAwMDD9AP8PMjAy
MjA1MjZUMTUyODQ0F0DAAWCZzxQSCAV0tluFDry5aT1b+EgoYgT1JKxbKVb/tINx
M43PFy/2hDe8j61PuYD9tCah0TWapPwfXWi3fygA`
spec := spec_2022.Spec{}

certWire := utils.WithoutErr(base64.RawStdEncoding.DecodeString(TestCert))
certData, covered, err := spec.ReadData(enc.NewBufferReader(certWire))
require.NoError(t, err)

pubKeyBits := utils.WithoutErr(x509.ParsePKIXPublicKey(certData.Content().Join()))
pubKey := pubKeyBits.(ed25519.PublicKey)
if pubKey == nil {
require.Fail(t, "unexpected public key type")
}
require.True(t, security.EddsaValidate(covered, certData.Signature(), pubKey))
}

0 comments on commit e6a1870

Please sign in to comment.