Skip to content

Commit

Permalink
sec: add validation to trust config
Browse files Browse the repository at this point in the history
  • Loading branch information
pulsejet committed Jan 22, 2025
1 parent ec229be commit f375eb1
Show file tree
Hide file tree
Showing 17 changed files with 222 additions and 139 deletions.
4 changes: 2 additions & 2 deletions std/schema/basic_policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func (p *FixedHmacSignerPolicy) onValidateData(event *Event) any {
if sigCovered == nil || signature == nil || signature.SigType() != ndn.SignatureHmacWithSha256 {
return VrSilence
}
if signer.CheckHmacSig(sigCovered, signature.SigValue(), []byte(p.Key)) {
if signer.ValidateHmac(sigCovered, signature, []byte(p.Key)) {
return VrPass
} else {
return VrFail
Expand Down Expand Up @@ -265,7 +265,7 @@ func (p *FixedHmacIntSignerPolicy) onValidateInt(event *Event) any {
if sigCovered == nil || signature == nil || signature.SigType() != ndn.SignatureHmacWithSha256 {
return VrSilence
}
if signer.CheckHmacSig(sigCovered, signature.SigValue(), []byte(p.Key)) {
if signer.ValidateHmac(sigCovered, signature, []byte(p.Key)) {
return VrPass
} else {
return VrFail
Expand Down
2 changes: 1 addition & 1 deletion std/schema/demosec/policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func (p *SignedByPolicy) onValidateData(event *schema.Event) any {
log.Warn(p, "Unable to fetch the key that signed this data.")
return schema.VrFail
}
if signer.CheckHmacSig(sigCovered, signature.SigValue(), result.Content.Join()) {
if signer.ValidateHmac(sigCovered, signature, result.Content.Join()) {
return schema.VrPass
} else {
log.Warn(p, "Failed to verify the signature.")
Expand Down
2 changes: 1 addition & 1 deletion std/schema/demosec/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (store *DemoHmacKeyStore) AddTrustAnchor(cert enc.Buffer) error {
return fmt.Errorf("unable to parse certificate: %+v", err)
}
keyBits := data.Content().Join()
if !sig.CheckHmacSig(sigCovered, data.Signature().SigValue(), keyBits) {
if !sig.ValidateHmac(sigCovered, data.Signature(), keyBits) {
return fmt.Errorf("the certificate is not properly self-signed")
}
return store.SaveKey(data.Name(), keyBits, cert)
Expand Down
17 changes: 17 additions & 0 deletions std/security/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ func SignCert(args SignCertArgs) (enc.Wire, error) {
return cert.Wire, nil
}

func CertIsExpired(cert ndn.Data) bool {
if cert.Signature() == nil {
return true
}

notBefore, notAfter := cert.Signature().Validity()
if notBefore == nil || notAfter == nil {
return true
}

if time.Now().Before(*notBefore) || time.Now().After(*notAfter) {
return true
}

return false
}

// getPubKey gets the public key from an NDN data.
// returns [public key, key name, error].
func getPubKey(data ndn.Data) ([]byte, enc.Name, error) {
Expand Down
19 changes: 15 additions & 4 deletions std/security/certificate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestSignCertSelf(t *testing.T) {
NotAfter: T2,
})
require.NoError(t, err)
cert, certSigCovered, err := spec_2022.Spec{}.ReadData(enc.NewWireReader(aliceCert))
cert, certSigCov, err := spec_2022.Spec{}.ReadData(enc.NewWireReader(aliceCert))
require.NoError(t, err)

// check certificate name
Expand Down Expand Up @@ -68,7 +68,7 @@ func TestSignCertSelf(t *testing.T) {

// check signature
require.Equal(t, 64, len(signature.SigValue())) // ed25519
require.True(t, signer.Ed25519Validate(certSigCovered, signature, alicePub))
require.True(t, utils.WithoutErr(signer.ValidateData(cert, certSigCov, cert)))
}

func TestSignCertOther(t *testing.T) {
Expand All @@ -78,6 +78,18 @@ func TestSignCertOther(t *testing.T) {
aliceKeyData, _, _ := spec_2022.Spec{}.ReadData(enc.NewBufferReader(aliceKey))
aliceSigner := utils.WithoutErr(signer.UnmarshalSecret(aliceKeyData))

// self signed alice's key
aliceCert, err := sec.SignCert(sec.SignCertArgs{
Signer: aliceSigner,
Data: aliceKeyData,
IssuerId: ISSUER,
NotBefore: T1,
NotAfter: T2,
})
require.NoError(t, err)
aliceCertData, _, err := spec_2022.Spec{}.ReadData(enc.NewWireReader(aliceCert))
require.NoError(t, err)

// parse existing certificate
rootCert, _ := base64.StdEncoding.DecodeString(CERT_ROOT)
rootCertData, _, _ := spec_2022.Spec{}.ReadData(enc.NewBufferReader(rootCert))
Expand Down Expand Up @@ -118,7 +130,6 @@ func TestSignCertOther(t *testing.T) {
require.Equal(t, T2, *notAfter)

// check signature
alicePub := utils.WithoutErr(aliceSigner.Public())
require.Equal(t, 64, len(signature.SigValue())) // ed25519
require.True(t, signer.Ed25519Validate(newSigCov, signature, alicePub))
require.True(t, utils.WithoutErr(signer.ValidateData(newCert, newSigCov, aliceCertData)))
}
22 changes: 10 additions & 12 deletions std/security/consts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,20 @@ import (
// Name: /ndn/alice/KEY/cK%1D%A4%E1%5B%91%CF
// SigType: Ed25519
const KEY_ALICE = `
BsoHGwgDbmRuCAVhbGljZQgDS0VZCAhjSx2k4VuRzxQDGAEJFUC64F62YK0/v5z4
fjONZO7Y4PNqy7FiDnar33uVO71FLK6Vp8GrPCkEhuODl6GBv2nUuovtO9KtHW11
8apSS093FiIbAQUcHQcbCANuZG4IBWFsaWNlCANLRVkICGNLHaThW5HPF0Cw3Oh7
I2jmBBxop1bIPXq292TfltVwhdbB3/yUXkKcg3BYbY6vcAhNNqrG2B+G/iHvKGsy
DpvDtnlEN72hIeIP
BroHGwgDbmRuCAVhbGljZQgDS0VZCAhY3Lb6ZymkghQDGAEJFTAwLgIBADAFBgMr
ZXAEIgQgG8Z7YkpBxVDqIFIm6EJlfCujheiW0262kJUj5vkmLDkWIhsBBRwdBxsI
A25kbggFYWxpY2UIA0tFWQgIWNy2+mcppIIXQB19BDvrahM3DR1DV7ESosKW4uzE
Z27QIGFgKR4LEuflvnSZZGFRKFxTUF5S2f/ZO/4B4NoxrF1ZOHD9NCWTkwI=
`

const KEY_ALICE_PEM = `-----BEGIN NDN KEY-----
Name: /ndn/alice/KEY/cK%1D%A4%E1%5B%91%CF
Name: /ndn/alice/KEY/X%DC%B6%FAg%29%A4%82
SigType: Ed25519
BsoHGwgDbmRuCAVhbGljZQgDS0VZCAhjSx2k4VuRzxQDGAEJFUC64F62YK0/v5z4
fjONZO7Y4PNqy7FiDnar33uVO71FLK6Vp8GrPCkEhuODl6GBv2nUuovtO9KtHW11
8apSS093FiIbAQUcHQcbCANuZG4IBWFsaWNlCANLRVkICGNLHaThW5HPF0Cw3Oh7
I2jmBBxop1bIPXq292TfltVwhdbB3/yUXkKcg3BYbY6vcAhNNqrG2B+G/iHvKGsy
DpvDtnlEN72hIeIP
BroHGwgDbmRuCAVhbGljZQgDS0VZCAhY3Lb6ZymkghQDGAEJFTAwLgIBADAFBgMr
ZXAEIgQgG8Z7YkpBxVDqIFIm6EJlfCujheiW0262kJUj5vkmLDkWIhsBBRwdBxsI
A25kbggFYWxpY2UIA0tFWQgIWNy2+mcppIIXQB19BDvrahM3DR1DV7ESosKW4uzE
Z27QIGFgKR4LEuflvnSZZGFRKFxTUF5S2f/ZO/4B4NoxrF1ZOHD9NCWTkwI=
-----END NDN KEY-----
`

Expand Down Expand Up @@ -60,7 +58,7 @@ qoAEsjM9PEUEWbnqAiEApu0rg9GAK1LNExjLYAF6qVgpWQgU+atPn63Gtuubqyg=
`

// Key names for the above keys and certs
var KEY_ALICE_NAME, _ = enc.NameFromStr("/ndn/alice/KEY/cK%1D%A4%E1%5B%91%CF")
var KEY_ALICE_NAME, _ = enc.NameFromStr("/ndn/alice/KEY/X%DC%B6%FAg%29%A4%82")
var KEY_ROOT_NAME, _ = enc.NameFromStr("/ndn/KEY/%27%C4%B2%2A%9F%7B%81%27")

// Issuer name for testing
Expand Down
16 changes: 7 additions & 9 deletions std/security/keychain/keychain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,19 @@ TkROIFRlc3RiZWQgUm9vdCAyMjA0F0gwRgIhAPYUOjNakdfDGh5j9dcCGOz+Ie1M
qoAEsjM9PEUEWbnqAiEApu0rg9GAK1LNExjLYAF6qVgpWQgU+atPn63Gtuubqyg=
`

const KEY_ALICE = `
-----BEGIN NDN KEY-----
Name: /ndn/alice/KEY/cK%1D%A4%E1%5B%91%CF
const KEY_ALICE = `-----BEGIN NDN KEY-----
Name: /ndn/alice/KEY/X%DC%B6%FAg%29%A4%82
SigType: Ed25519
BsoHGwgDbmRuCAVhbGljZQgDS0VZCAhjSx2k4VuRzxQDGAEJFUC64F62YK0/v5z4
fjONZO7Y4PNqy7FiDnar33uVO71FLK6Vp8GrPCkEhuODl6GBv2nUuovtO9KtHW11
8apSS093FiIbAQUcHQcbCANuZG4IBWFsaWNlCANLRVkICGNLHaThW5HPF0Cw3Oh7
I2jmBBxop1bIPXq292TfltVwhdbB3/yUXkKcg3BYbY6vcAhNNqrG2B+G/iHvKGsy
DpvDtnlEN72hIeIP
BroHGwgDbmRuCAVhbGljZQgDS0VZCAhY3Lb6ZymkghQDGAEJFTAwLgIBADAFBgMr
ZXAEIgQgG8Z7YkpBxVDqIFIm6EJlfCujheiW0262kJUj5vkmLDkWIhsBBRwdBxsI
A25kbggFYWxpY2UIA0tFWQgIWNy2+mcppIIXQB19BDvrahM3DR1DV7ESosKW4uzE
Z27QIGFgKR4LEuflvnSZZGFRKFxTUF5S2f/ZO/4B4NoxrF1ZOHD9NCWTkwI=
-----END NDN KEY-----
`

var CERT_ROOT_NAME, _ = enc.NameFromStr("/ndn/KEY/%27%C4%B2%2A%9F%7B%81%27/ndn/v=1651246789556")
var KEY_ALICE_NAME, _ = enc.NameFromStr("/ndn/alice/KEY/cK%1D%A4%E1%5B%91%CF")
var KEY_ALICE_NAME, _ = enc.NameFromStr("/ndn/alice/KEY/X%DC%B6%FAg%29%A4%82")

func signCert(t *testing.T, signer ndn.Signer) []byte {
certData, _, _ := spec.Spec{}.ReadData(enc.NewWireReader(
Expand Down
17 changes: 17 additions & 0 deletions std/security/signer/ecc_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,20 @@ func ParseEcc(name enc.Name, key []byte) (ndn.Signer, error) {
}
return NewEccSigner(name, sk), nil
}

// validateEcdsa verifies the signature with a known ECC public key.
// ndn-cxx's PIB uses secp256r1 key stored in ASN.1 DER format. Use x509.ParsePKIXPublicKey to parse.
func validateEcdsa(sigCovered enc.Wire, sig ndn.Signature, pubKey *ecdsa.PublicKey) bool {
if sig.SigType() != ndn.SignatureSha256WithEcdsa {
return false
}
h := sha256.New()
for _, buf := range sigCovered {
_, err := h.Write(buf)
if err != nil {
return false
}
}
digest := h.Sum(nil)
return ecdsa.VerifyASN1(pubKey, digest, sig.SigValue())
}
26 changes: 21 additions & 5 deletions std/security/signer/ed25519_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package signer
import (
"crypto/ed25519"
"crypto/rand"
"crypto/x509"
"errors"

enc "github.com/named-data/ndnd/std/encoding"
Expand Down Expand Up @@ -36,11 +37,11 @@ func (s *ed25519Signer) Sign(covered enc.Wire) ([]byte, error) {
}

func (s *ed25519Signer) Public() ([]byte, error) {
return s.key[ed25519.PublicKeySize:], nil
return x509.MarshalPKIXPublicKey(s.key.Public())
}

func (s *ed25519Signer) Secret() ([]byte, error) {
return s.key, nil
return x509.MarshalPKCS8PrivateKey(s.key)
}

// NewEd25519Signer creates a signer using ed25519 key
Expand All @@ -59,8 +60,23 @@ func KeygenEd25519(name enc.Name) (ndn.Signer, error) {

// ParseEd25519 parses a signer from a byte slice.
func ParseEd25519(name enc.Name, key []byte) (ndn.Signer, error) {
if len(key) != ed25519.PrivateKeySize {
return nil, errors.New("invalid Ed25519 private key size")
pkey, err := x509.ParsePKCS8PrivateKey(key)
if err != nil {
return nil, err
}
sk, ok := pkey.(ed25519.PrivateKey)
if !ok {
return nil, errors.New("invalid key type")
}
return NewEd25519Signer(name, sk), nil
}

// validateEd25519 verifies the signature with a known ed25519 public key.
// ndn-cxx's PIB does not support this, but a certificate is supposed to use ASN.1 DER format.
// Use x509.ParsePKIXPublicKey to parse. Note: ed25519.PublicKey is defined to be a pointer type without '*'.
func validateEd25519(sigCovered enc.Wire, sig ndn.Signature, pubKey ed25519.PublicKey) bool {
if sig.SigType() != ndn.SignatureEd25519 {
return false
}
return NewEd25519Signer(name, key), nil
return ed25519.Verify(pubKey, sigCovered.Join(), sig.SigValue())
}
18 changes: 7 additions & 11 deletions std/security/signer/ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ func testEd25519Verify(t *testing.T, signer ndn.Signer, verifyKey []byte) bool {
sigValue := utils.WithoutErr(signer.Sign(dataVal))

// For basic test, we use ed25519.Verify to verify the signature.
return ed25519.Verify(verifyKey, dataVal.Join(), sigValue)
verifyKeyBits := utils.WithoutErr(x509.ParsePKIXPublicKey(verifyKey)).(ed25519.PublicKey)
return ed25519.Verify(verifyKeyBits, dataVal.Join(), sigValue)
}

func TestEd25519SignerNew(t *testing.T) {
Expand Down Expand Up @@ -74,8 +75,9 @@ func TestEd25519Parse(t *testing.T) {
require.Error(t, err)
}

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

const TestCert = `
Expand All @@ -87,13 +89,7 @@ MjA1MjZUMTUyODQ0F0DAAWCZzxQSCAV0tluFDry5aT1b+EgoYgT1JKxbKVb/tINx
M43PFy/2hDe8j61PuYD9tCah0TWapPwfXWi3fygA`

certWire := utils.WithoutErr(base64.RawStdEncoding.DecodeString(TestCert))
certData, covered, err := spec.Spec{}.ReadData(enc.NewBufferReader(certWire))
certData, sigCov, err := spec.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, sig.Ed25519Validate(covered, certData.Signature(), pubKey))
require.True(t, utils.WithoutErr(sig.ValidateData(certData, sigCov, certData)))
}
8 changes: 6 additions & 2 deletions std/security/signer/hmac_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,17 @@ func NewHmacSigner(key []byte) ndn.Signer {
return &hmacSigner{key}
}

func CheckHmacSig(sigCovered enc.Wire, sigValue []byte, key []byte) bool {
// ValidateHmac verifies the signature with a known HMAC shared key.
func ValidateHmac(sigCovered enc.Wire, sig ndn.Signature, key []byte) bool {
if sig.SigType() != ndn.SignatureHmacWithSha256 {
return false
}
mac := hmac.New(sha256.New, []byte(key))
for _, buf := range sigCovered {
_, err := mac.Write(buf)
if err != nil {
return false
}
}
return hmac.Equal(mac.Sum(nil), sigValue)
return hmac.Equal(mac.Sum(nil), sig.SigValue())
}
18 changes: 18 additions & 0 deletions std/security/signer/rsa_signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,21 @@ func ParseRsa(name enc.Name, key []byte) (ndn.Signer, error) {
}
return NewRsaSigner(name, sk), nil
}

// validateRsa verifies the signature with a known RSA public key.
// ndn-cxx's PIB uses RSA 2048 key stored in ASN.1 DER format.
// Use x509.ParsePKIXPublicKey to parse.
func validateRsa(sigCovered enc.Wire, sig ndn.Signature, pubKey *rsa.PublicKey) bool {
if sig.SigType() != ndn.SignatureSha256WithRsa {
return false
}
h := sha256.New()
for _, buf := range sigCovered {
_, err := h.Write(buf)
if err != nil {
return false
}
}
digest := h.Sum(nil)
return rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, digest, sig.SigValue()) == nil
}
16 changes: 16 additions & 0 deletions std/security/signer/sha256_signer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package signer

import (
"bytes"
"crypto/sha256"

enc "github.com/named-data/ndnd/std/encoding"
Expand Down Expand Up @@ -45,3 +46,18 @@ func (sha256Signer) Public() ([]byte, error) {
func NewSha256Signer() ndn.Signer {
return sha256Signer{}
}

// ValidateSha256 checks if the signature is valid for the covered data.
func ValidateSha256(sigCovered enc.Wire, sig ndn.Signature) bool {
if sig.SigType() != ndn.SignatureDigestSha256 {
return false
}
h := sha256.New()
for _, buf := range sigCovered {
_, err := h.Write(buf)
if err != nil {
return false
}
}
return bytes.Equal(h.Sum(nil), sig.SigValue())
}
46 changes: 46 additions & 0 deletions std/security/signer/validate_data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package signer

import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/x509"

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

// ValidateData verifies the signature of a Data packet with a certificate.
func ValidateData(data ndn.Data, sigCovered enc.Wire, cert ndn.Data) (bool, error) {
switch data.Signature().SigType() {
case ndn.SignatureSha256WithRsa:
pkey, err := x509.ParsePKIXPublicKey(cert.Content().Join())
if err != nil {
return false, err
}
if pub, ok := pkey.(*rsa.PublicKey); ok {
return validateRsa(sigCovered, data.Signature(), pub), nil
}
case ndn.SignatureSha256WithEcdsa:
pkey, err := x509.ParsePKIXPublicKey(cert.Content().Join())
if err != nil {
return false, err
}
if pub, ok := pkey.(*ecdsa.PublicKey); ok {
return validateEcdsa(sigCovered, data.Signature(), pub), nil
}
case ndn.SignatureEd25519:
pkey, err := x509.ParsePKIXPublicKey(cert.Content().Join())
if err != nil {
return false, err
}
if pub, ok := pkey.(ed25519.PublicKey); ok {
return validateEd25519(sigCovered, data.Signature(), pub), nil
}
}

return false, ndn.ErrInvalidValue{
Item: "Signature.SigType",
Value: data.Signature().SigType(),
}
}
Loading

0 comments on commit f375eb1

Please sign in to comment.