-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* security: Add ed25519 signer Fix: #91
- Loading branch information
Showing
5 changed files
with
213 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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:]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)) | ||
} |