diff --git a/repo/repo_mgmt.go b/repo/repo_mgmt.go index db453111..625790cc 100644 --- a/repo/repo_mgmt.go +++ b/repo/repo_mgmt.go @@ -197,9 +197,10 @@ func (r *Repo) fetchSecurityConfig(name enc.Name) (*tlv.SecurityConfigObject, er // Repo should validate this as normal command r.client.ConsumeExt(ndn.ConsumeExtArgs{ - Name: name, - TryStore: true, - IgnoreValidity: optional.Some(r.config.IgnoreValidity), + Name: name, + TryStore: true, + UseSignatureTime: optional.Some(true), + IgnoreValidity: optional.Some(r.config.IgnoreValidity), Callback: func(state ndn.ConsumeState) { wire = append(wire, state.Content()...) if state.Error() != nil { diff --git a/repo/repo_svs.go b/repo/repo_svs.go index 7bd5652c..8ecd6a78 100644 --- a/repo/repo_svs.go +++ b/repo/repo_svs.go @@ -54,10 +54,11 @@ func (r *RepoSvs) Start() (err error) { } snapshot = &ndn_sync.SnapshotNodeHistory{ - Client: r.client, - Threshold: r.cmd.HistorySnapshot.Threshold, - IsRepo: true, - IgnoreValidity: optional.Some(r.config.IgnoreValidity), + Client: r.client, + Threshold: r.cmd.HistorySnapshot.Threshold, + IsRepo: true, + UseSignatureTime: optional.Some(true), + IgnoreValidity: optional.Some(r.config.IgnoreValidity), } } @@ -78,6 +79,7 @@ func (r *RepoSvs) Start() (err error) { SuppressionPeriod: 500 * time.Millisecond, PeriodicTimeout: 365 * 24 * time.Hour, // basically never Passive: true, + UseSignatureTime: optional.Some(true), IgnoreValidity: optional.Some(r.config.IgnoreValidity), }, Snapshot: snapshot, diff --git a/std/engine/basic/engine_test.go b/std/engine/basic/engine_test.go index 169bc10f..42454d12 100644 --- a/std/engine/basic/engine_test.go +++ b/std/engine/basic/engine_test.go @@ -268,6 +268,9 @@ func TestRoute(t *testing.T) { hitCnt := 0 spec := engine.Spec() + // Fixed SigTime for deterministic test vectors: 2024-01-01 00:00:00 UTC + fixedSigTime := optional.Some(time.Duration(1704067200000) * time.Millisecond) + handler := func(args ndn.InterestHandlerArgs) { hitCnt += 1 require.Equal(t, []byte( @@ -278,6 +281,7 @@ func TestRoute(t *testing.T) { args.Interest.Name(), &ndn.DataConfig{ ContentType: optional.Some(ndn.ContentTypeBlob), + SigTime: fixedSigTime, }, enc.Wire{[]byte("test")}, sig.NewTestSigner(enc.Name{}, 0)) @@ -291,8 +295,8 @@ func TestRoute(t *testing.T) { require.Equal(t, 1, hitCnt) buf := tu.NoErr(face.Consume()) require.Equal(t, enc.Buffer( - "\x06\x22\x07\x10\x08\x03not\x08\timportant\x14\x03\x18\x01\x00\x15\x04test"+ - "\x16\x03\x1b\x01\xc8", + "\x06\x2c\x07\x10\x08\x03not\x08\timportant\x14\x03\x18\x01\x00\x15\x04test"+ + "\x16\x0d\x1b\x01\xc8(\x08\x00\x00\x01\x8c\xc2Q\xf4\x00", ), buf) }) } @@ -302,6 +306,8 @@ func TestPitToken(t *testing.T) { executeTest(t, func(face *face.DummyFace, engine *basic_engine.Engine, timer *basic_engine.DummyTimer) { hitCnt := 0 spec := engine.Spec() + // Fixed SigTime for deterministic test vectors: 2024-01-01 00:00:00 UTC + fixedSigTime := optional.Some(time.Duration(1704067200000) * time.Millisecond) handler := func(args ndn.InterestHandlerArgs) { hitCnt += 1 @@ -309,6 +315,7 @@ func TestPitToken(t *testing.T) { args.Interest.Name(), &ndn.DataConfig{ ContentType: optional.Some(ndn.ContentTypeBlob), + SigTime: fixedSigTime, }, enc.Wire{[]byte("test")}, sig.NewTestSigner(enc.Name{}, 0)) @@ -324,9 +331,9 @@ func TestPitToken(t *testing.T) { )) buf := tu.NoErr(face.Consume()) require.Equal(t, enc.Buffer( - "\x64\x2c\x62\x04\x01\x02\x03\x04\x50\x24"+ - "\x06\x22\x07\x10\x08\x03not\x08\timportant\x14\x03\x18\x01\x00\x15\x04test"+ - "\x16\x03\x1b\x01\xc8", + "\x64\x36\x62\x04\x01\x02\x03\x04\x50\x2e"+ + "\x06\x2c\x07\x10\x08\x03not\x08\timportant\x14\x03\x18\x01\x00\x15\x04test"+ + "\x16\x0d\x1b\x01\xc8(\x08\x00\x00\x01\x8c\xc2Q\xf4\x00", ), buf) }) } diff --git a/std/ndn/client.go b/std/ndn/client.go index 9a5ae1bb..9a509e02 100644 --- a/std/ndn/client.go +++ b/std/ndn/client.go @@ -129,6 +129,8 @@ type ConsumeExtArgs struct { OnProgress func(status ConsumeState) // NoMetadata disables fetching RDR metadata (advanced usage). NoMetadata bool + // UseSignatureTime checks validity period using signature time + UseSignatureTime optional.Optional[bool] // IgnoreValidity ignores validity period in the validation chain IgnoreValidity optional.Optional[bool] } @@ -167,7 +169,9 @@ type ValidateExtArgs struct { CertNextHop optional.Optional[uint64] // UseDataNameFwHint overrides trust config option. UseDataNameFwHint optional.Optional[bool] - // IgnoreValidity ignores validity period in the validation chain. + // UseSignatureTime checks validity with signature time + UseSignatureTime optional.Optional[bool] + // IgnoreValidity ignores validity period in the validation chain IgnoreValidity optional.Optional[bool] } diff --git a/std/ndn/engine.go b/std/ndn/engine.go index 68778b9b..ec242475 100644 --- a/std/ndn/engine.go +++ b/std/ndn/engine.go @@ -89,6 +89,10 @@ type ExpressCallbackArgs struct { // IsLocal indicates if a local copy of the Data was found. // e.g. returned by ExpressR when used with TryStore. IsLocal bool + // UseSignatureTime checks validity with signature time + UseSignatureTime optional.Optional[bool] + // IgnoreValidity ignores validity period in the validation chain + IgnoreValidity optional.Optional[bool] } // InterestHandler represents the callback function for an Interest handler. diff --git a/std/ndn/spec.go b/std/ndn/spec.go index 59e32a46..1f6bffae 100644 --- a/std/ndn/spec.go +++ b/std/ndn/spec.go @@ -97,6 +97,9 @@ type DataConfig struct { SigNotBefore optional.Optional[time.Time] SigNotAfter optional.Optional[time.Time] + // Signature time, used to determine time the packet was signed + SigTime optional.Optional[time.Duration] + // Cross Schema attachment CrossSchema enc.Wire } diff --git a/std/ndn/spec_2022/spec.go b/std/ndn/spec_2022/spec.go index b245705f..5c517850 100644 --- a/std/ndn/spec_2022/spec.go +++ b/std/ndn/spec_2022/spec.go @@ -51,9 +51,13 @@ func (d *Data) SigNonce() []byte { return nil } -// (AI GENERATED DESCRIPTION): Returns the signature timestamp of the Data packet (currently unimplemented and returns nil). +// (AI GENERATED DESCRIPTION): Returns the signature timestamp of the Data packet if present, else returns nil. func (d *Data) SigTime() *time.Time { - return nil + if d.SignatureInfo != nil && d.SignatureInfo.SignatureTime.IsSet() { + return utils.IdPtr(time.UnixMilli(d.SignatureInfo.SignatureTime.Unwrap().Milliseconds())) + } else { + return nil + } } // (AI GENERATED DESCRIPTION): Sets the Data packet’s SignatureInfo.SignatureTime to the given time (converted to a millisecond duration) or clears the field if the argument is nil. @@ -262,6 +266,11 @@ func (Spec) MakeData(name enc.Name, config *ndn.DataConfig, content enc.Wire, si if config == nil { return nil, ndn.ErrInvalidValue{Item: "Data.DataConfig", Value: nil} } + + if !config.SigTime.IsSet() { + config.SigTime = optional.Some(time.Duration(time.Now().UnixMilli()) * time.Millisecond) + } + finalBlock := []byte(nil) if fbid, ok := config.FinalBlockID.Get(); ok { finalBlock = fbid.Bytes() @@ -289,6 +298,7 @@ func (Spec) MakeData(name enc.Name, config *ndn.DataConfig, content enc.Wire, si data.SignatureInfo = &SignatureInfo{ SignatureType: uint64(signer.Type()), + SignatureTime: config.SigTime, } if key := signer.KeyLocator(); key != nil { diff --git a/std/ndn/spec_2022/spec_test.go b/std/ndn/spec_2022/spec_test.go index e8cd9950..a8f36a5d 100644 --- a/std/ndn/spec_2022/spec_test.go +++ b/std/ndn/spec_2022/spec_test.go @@ -21,40 +21,42 @@ func TestMakeDataBasic(t *testing.T) { tu.SetT(t) spec := spec_2022.Spec{} + // Fixed SigTime for deterministic test vectors: 2024-01-01 00:00:00 UTC + fixedSigTime := optional.Some(time.Duration(1704067200000) * time.Millisecond) data, err := spec.MakeData( tu.NoErr(enc.NameFromStr("/local/ndn/prefix")), &ndn.DataConfig{ ContentType: optional.Some(ndn.ContentTypeBlob), + SigTime: fixedSigTime, }, nil, sig.NewSha256Signer(), ) require.NoError(t, err) require.Equal(t, []byte( - "\x06\x42\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix"+ + "\x06L\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix"+ "\x14\x03\x18\x01\x00"+ - "\x16\x03\x1b\x01\x00"+ - "\x17 \x7f1\xe4\t\xc5z/\x1d\r\xdaVh8\xfd\xd9\x94"+ - "\xd8'S\x13[\xd7\x15\xa5\x9d%^\x80\xf2\xab\xf0\xb5"), + "\x16\x0d\x1b\x01\x00(\x08\x00\x00\x01\x8c\xc2Q\xf4\x00"+ + "\x17 *\x17?\xd6i\xdcB\xd0\xf6G\x1d\x0b\xb6\x93\xd4{\xddw\xc6$\x04\x00\x0eN\xb7\x07\x5c\x80K+O\x86"), data.Wire.Join()) data, err = spec.MakeData( tu.NoErr(enc.NameFromStr("/local/ndn/prefix")), &ndn.DataConfig{ ContentType: optional.Some(ndn.ContentTypeBlob), + SigTime: fixedSigTime, }, enc.Wire{[]byte("01020304")}, sig.NewSha256Signer(), ) require.NoError(t, err) require.Equal(t, []byte( - "\x06L\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix"+ + "\x06V\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix"+ "\x14\x03\x18\x01\x00"+ "\x15\x0801020304"+ - "\x16\x03\x1b\x01\x00"+ - "\x17 \x94\xe9\xda\x91\x1a\x11\xfft\x02i:G\x0cO\xdd!"+ - "\xe0\xc7\xb6\xfd\x8f\x9cn\xc5\x93{\x93\x04\xe0\xdf\xa6S"), + "\x16\x0d\x1b\x01\x00(\x08\x00\x00\x01\x8c\xc2Q\xf4\x00"+ + "\x17 \xaf\x02\x9d\xf3\x9a\x05s\x83\xefv\x05\xef\x81=\xdb.\xc72$v\x13\xb3\xae\x80\x83+\xe8W\xfeP\x1f}"), data.Wire.Join()) data, err = spec.MakeData( @@ -75,15 +77,16 @@ func TestMakeDataBasic(t *testing.T) { tu.NoErr(enc.NameFromStr("/E")), &ndn.DataConfig{ ContentType: optional.None[ndn.ContentType](), + SigTime: fixedSigTime, }, enc.Wire{}, sig.NewSha256Signer(), ) require.NoError(t, err) require.Equal(t, tu.NoErr(hex.DecodeString( - "06300703080145"+ - "1400150016031b0100"+ - "1720f965ee682c6973c3cbaa7b69e4c7063680f83be93a46be2ccc98686134354b66")), + "063a070308014514001500"+ + "160d1b010028080000018cc251f400"+ + "1720f7b2d57151cb8d6fe2c616adee9195c9d00f3c422754709f750375bae2e91e30")), data.Wire.Join()) } @@ -91,6 +94,8 @@ func TestMakeDataBasic(t *testing.T) { func TestMakeDataMetaInfo(t *testing.T) { tu.SetT(t) spec := spec_2022.Spec{} + // Fixed SigTime for deterministic test vectors: 2024-01-01 00:00:00 UTC + fixedSigTime := optional.Some(time.Duration(1704067200000) * time.Millisecond) data, err := spec.MakeData( tu.NoErr(enc.NameFromStr("/local/ndn/prefix/37=%00")), @@ -98,16 +103,17 @@ func TestMakeDataMetaInfo(t *testing.T) { ContentType: optional.Some(ndn.ContentTypeBlob), Freshness: optional.Some(1000 * time.Millisecond), FinalBlockID: optional.Some(enc.NewSequenceNumComponent(2)), + SigTime: fixedSigTime, }, nil, sig.NewSha256Signer(), ) require.NoError(t, err) require.Equal(t, []byte( - "\x06\x4e\x07\x17\x08\x05local\x08\x03ndn\x08\x06prefix\x25\x01\x00"+ - "\x14\x0c\x18\x01\x00\x19\x02\x03\xe8\x1a\x03\x3a\x01\x02"+ - "\x16\x03\x1b\x01\x00"+ - "\x17 \x0f^\xa1\x0c\xa7\xf5Fb\xf0\x9cOT\xe0FeC\x8f92\x04\x9d\xabP\x80o'\x94\xaa={hQ"), + "\x06X\x07\x17\x08\x05local\x08\x03ndn\x08\x06prefix\x25\x01\x00"+ + "\x14\x0c\x18\x01\x00\x19\x02\x03\xe8\x1a\x03:\x01\x02"+ + "\x16\x0d\x1b\x01\x00(\x08\x00\x00\x01\x8c\xc2Q\xf4\x00"+ + "\x17 \xa9v\x8a(\xb3^\xf8\x1c\xce*\xa8\xf2\x14\x81\x8cQ\xcc\xb8I\xc6\xd6\xa7\x99z\x88JKu\x81\xc4[N"), data.Wire.Join()) } @@ -148,19 +154,23 @@ func (testSigner) Public() ([]byte, error) { func TestMakeDataShrink(t *testing.T) { tu.SetT(t) spec := spec_2022.Spec{} + // Fixed SigTime for deterministic test vectors: 2024-01-01 00:00:00 UTC + fixedSigTime := optional.Some(time.Duration(1704067200000) * time.Millisecond) data, err := spec.MakeData( tu.NoErr(enc.NameFromStr("/test")), &ndn.DataConfig{ ContentType: optional.Some(ndn.ContentTypeBlob), + SigTime: fixedSigTime, }, nil, testSigner{}, ) require.NoError(t, err) require.Equal(t, []byte{ - 0x6, 0x22, 0x7, 0x6, 0x8, 0x4, 0x74, 0x65, 0x73, 0x74, 0x14, 0x3, 0x18, 0x1, 0x0, - 0x16, 0xc, 0x1b, 0x1, 0xc8, 0x1c, 0x7, 0x7, 0x5, 0x8, 0x3, 0x4b, 0x45, 0x59, + 0x6, 0x2c, 0x7, 0x6, 0x8, 0x4, 0x74, 0x65, 0x73, 0x74, 0x14, 0x3, 0x18, 0x1, 0x0, + 0x16, 0x16, 0x1b, 0x1, 0xc8, 0x1c, 0x7, 0x7, 0x5, 0x8, 0x3, 0x4b, 0x45, 0x59, + 0x28, 0x8, 0x0, 0x0, 0x1, 0x8c, 0xc2, 0x51, 0xf4, 0x0, 0x17, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0}, data.Wire.Join()) } diff --git a/std/object/client_consume.go b/std/object/client_consume.go index 998dec06..64ba3e3e 100644 --- a/std/object/client_consume.go +++ b/std/object/client_consume.go @@ -64,7 +64,7 @@ func (c *Client) consumeObject(state *ConsumeState) { // if metadata fetching is disabled, just attempt to fetch one segment // with the prefix, then get the versioned name from the segment. if state.args.NoMetadata { - c.fetchDataByPrefix(name, state.args.TryStore, state.args.IgnoreValidity.GetOr(false), + c.fetchDataByPrefix(name, state.args.TryStore, state.args.UseSignatureTime.GetOr(false), state.args.IgnoreValidity.GetOr(false), func(data ndn.Data, err error) { if err != nil { state.finalizeError(err) @@ -81,7 +81,7 @@ func (c *Client) consumeObject(state *ConsumeState) { } // fetch RDR metadata for this object - c.fetchMetadata(name, state.args.TryStore, state.args.IgnoreValidity.GetOr(false), + c.fetchMetadata(name, state.args.TryStore, state.args.UseSignatureTime.GetOr(false), state.args.IgnoreValidity.GetOr(false), func(meta *rdr.MetaData, err error) { if err != nil { state.finalizeError(err) @@ -107,6 +107,7 @@ func (c *Client) consumeObjectWithMeta(state *ConsumeState, meta *rdr.MetaData) func (c *Client) fetchMetadata( name enc.Name, tryStore bool, + useSignatureTime bool, ignoreValidity bool, callback func(meta *rdr.MetaData, err error), ) { @@ -131,9 +132,10 @@ func (c *Client) fetchMetadata( return } c.ValidateExt(ndn.ValidateExtArgs{ - Data: args.Data, - SigCovered: args.SigCovered, - IgnoreValidity: optional.Some(ignoreValidity), + Data: args.Data, + SigCovered: args.SigCovered, + UseSignatureTime: optional.Some(useSignatureTime), + IgnoreValidity: optional.Some(ignoreValidity), Callback: func(valid bool, err error) { // validate with trust config if !valid { @@ -162,6 +164,7 @@ func (c *Client) fetchMetadata( func (c *Client) fetchDataByPrefix( name enc.Name, tryStore bool, + useSignatureTime bool, ignoreValidity bool, callback func(data ndn.Data, err error), ) { @@ -186,9 +189,10 @@ func (c *Client) fetchDataByPrefix( return } c.ValidateExt(ndn.ValidateExtArgs{ - Data: args.Data, - SigCovered: args.SigCovered, - IgnoreValidity: optional.Some(ignoreValidity), + Data: args.Data, + SigCovered: args.SigCovered, + UseSignatureTime: optional.Some(useSignatureTime), + IgnoreValidity: optional.Some(ignoreValidity), Callback: func(valid bool, err error) { if !valid { callback(nil, fmt.Errorf("%w: validate by prefix failed: %w", ndn.ErrSecurity, err)) diff --git a/std/object/client_consume_seg.go b/std/object/client_consume_seg.go index 972f171c..8fa9440e 100644 --- a/std/object/client_consume_seg.go +++ b/std/object/client_consume_seg.go @@ -286,9 +286,10 @@ func (s *rrSegFetcher) handleResult(args ndn.ExpressCallbackArgs, state *Consume // The notable exception here is when there is a timeout, which has a separate goroutine. func (s *rrSegFetcher) handleData(args ndn.ExpressCallbackArgs, state *ConsumeState) { s.client.ValidateExt(ndn.ValidateExtArgs{ - Data: args.Data, - SigCovered: args.SigCovered, - IgnoreValidity: state.args.IgnoreValidity, + Data: args.Data, + SigCovered: args.SigCovered, + UseSignatureTime: state.args.UseSignatureTime, + IgnoreValidity: state.args.IgnoreValidity, Callback: func(valid bool, err error) { if !valid { state.finalizeError(fmt.Errorf("%w: validate seg failed: %w", ndn.ErrSecurity, err)) diff --git a/std/object/client_trust.go b/std/object/client_trust.go index 8654ff48..cadb3d7d 100644 --- a/std/object/client_trust.go +++ b/std/object/client_trust.go @@ -46,6 +46,7 @@ func (c *Client) ValidateExt(args ndn.ValidateExtArgs) { Callback: args.Callback, OverrideName: overrideName, UseDataNameFwHint: args.UseDataNameFwHint, + UseSignatureTime: args.UseSignatureTime, IgnoreValidity: args.IgnoreValidity, Fetch: func(name enc.Name, config *ndn.InterestConfig, callback ndn.ExpressCallbackFunc) { config.NextHopId = args.CertNextHop diff --git a/std/security/certificate.go b/std/security/certificate.go index 99060019..330e33a0 100644 --- a/std/security/certificate.go +++ b/std/security/certificate.go @@ -65,6 +65,7 @@ func SignCert(args SignCertArgs) (enc.Wire, error) { Freshness: optional.Some(time.Hour), SigNotBefore: optional.Some(args.NotBefore), SigNotAfter: optional.Some(args.NotAfter), + SigTime: optional.Some(time.Duration(time.Now().UnixMilli()) * time.Millisecond), CrossSchema: args.CrossSchema, } signer := sig.AsContextSigner(args.Signer) @@ -199,3 +200,15 @@ func DecodeCertList(content enc.Wire) ([]enc.Name, error) { } return names, nil } + +// AppendCertList appends a certificate name list to a certificate list by creating a new certificate list +func AppendCertList(content enc.Wire, names []enc.Name) (enc.Wire, error) { + certList, err := DecodeCertList(content) + if err != nil { + return nil, err + } + + newList := append(certList, names...) + + return EncodeCertList(newList) +} diff --git a/std/security/certificate_test.go b/std/security/certificate_test.go index f3419c3b..b69ecc29 100644 --- a/std/security/certificate_test.go +++ b/std/security/certificate_test.go @@ -191,3 +191,22 @@ func TestEncodeDecodeCertList(t *testing.T) { _, err = sec.DecodeCertList(enc.Wire{[]byte{0x01, 0x02}}) require.Error(t, err) } + +func TestAppendCertList(t *testing.T) { + tu.SetT(t) + n1 := tu.NoErr(enc.NameFromStr("/ndn/alice/KEY/aa/self/v=1")) + n2 := tu.NoErr(enc.NameFromStr("/ndn/alice/KEY/bb/ndn/v=2")) + + wire, err := sec.EncodeCertList([]enc.Name{n1}) + require.NoError(t, err) + decoded, err := sec.DecodeCertList(wire) + require.NoError(t, err) + require.Equal(t, []enc.Name{n1}, decoded) + + wire2, err2 := sec.AppendCertList(wire, []enc.Name{n2}) + require.NoError(t, err2) + + decoded, err = sec.DecodeCertList(wire2) + require.NoError(t, err) + require.Equal(t, []enc.Name{n1, n2}, decoded) +} diff --git a/std/security/keychain/keychain_state.go b/std/security/keychain/keychain_state.go index c517be47..f8495d3b 100644 --- a/std/security/keychain/keychain_state.go +++ b/std/security/keychain/keychain_state.go @@ -119,11 +119,6 @@ func (kc *keyChainState) insertCert(wire []byte) error { return ndn.ErrInvalidValue{Item: "certificate name"} } - // Check if certificate is valid - if sec.CertIsExpired(data) { - return ndn.ErrInvalidValue{Item: "certificate expiry"} - } - // Check if certificate already exists for _, existing := range kc.certNames { if existing.Equal(name) { diff --git a/std/security/trust_config.go b/std/security/trust_config.go index b8e4ba9a..8f91a227 100644 --- a/std/security/trust_config.go +++ b/std/security/trust_config.go @@ -120,7 +120,7 @@ type TrustConfigValidateArgs struct { Callback func(bool, error) // OverrideName is an override for the data name (advanced usage). OverrideName enc.Name - // ignore ValidityPeriod in the valication chain + // ignore ValidityPeriod in the validation chain IgnoreValidity optional.Optional[bool] // origDataName is the original data name being verified. origDataName enc.Name @@ -140,6 +140,9 @@ type TrustConfigValidateArgs struct { // depth is the maximum depth of the validation chain. depth int + + // Use alternate verification flow. + UseSignatureTime optional.Optional[bool] } // Validate validates a Data packet using a fetch API. @@ -178,7 +181,7 @@ func (tc *TrustConfig) Validate(args TrustConfigValidateArgs) { // Bail if the data is a cert and is not fresh if t, ok := args.Data.ContentType().Get(); ok && t == ndn.ContentTypeKey { - if !args.IgnoreValidity.GetOr(false) && CertIsExpired(args.Data) { + if !args.UseSignatureTime.GetOr(false) && CertIsExpired(args.Data) && !args.IgnoreValidity.GetOr(false) { args.Callback(false, fmt.Errorf("certificate is expired: %s", args.Data.Name())) return } @@ -205,6 +208,11 @@ func (tc *TrustConfig) Validate(args TrustConfigValidateArgs) { return } + if args.UseSignatureTime.GetOr(false) && !ValidateSigTime(args.Data, args.cert) && !args.IgnoreValidity.GetOr(false) { + args.Callback(false, fmt.Errorf("data not signed during validity period: %s", args.cert.Name())) + return + } + // Check schema if the key is allowed if args.crossSchemaIsValid { // continue @@ -229,6 +237,8 @@ func (tc *TrustConfig) Validate(args TrustConfigValidateArgs) { IgnoreValidity: args.IgnoreValidity, cert: args.cert, depth: args.depth, + + UseSignatureTime: args.UseSignatureTime, }) return } else { @@ -302,6 +312,8 @@ func (tc *TrustConfig) Validate(args TrustConfigValidateArgs) { crossSchemaIsValid: false, + UseSignatureTime: args.UseSignatureTime, + depth: args.depth, }) return @@ -370,8 +382,8 @@ func (tc *TrustConfig) Validate(args TrustConfigValidateArgs) { return } - // Bail if the fetched cert is not fresh - if !args.IgnoreValidity.GetOr(false) && CertIsExpired(res.Data) { + // Bail if the fetched cert is not fresh and not using signature time flow + if !args.UseSignatureTime.GetOr(false) && CertIsExpired(res.Data) && !args.IgnoreValidity.GetOr(false) { args.Callback(false, fmt.Errorf("certificate is expired: %s", res.Data.Name())) return } @@ -406,9 +418,19 @@ func (tc *TrustConfig) validateCrossSchema(args TrustConfigValidateArgs) { } // Check validity period of the cross schema - if !args.IgnoreValidity.GetOr(false) && CertIsExpired(crossData) { - args.Callback(false, fmt.Errorf("cross schema is expired: %s", crossData.Name())) - return + if !args.IgnoreValidity.GetOr(false) { + if args.UseSignatureTime.GetOr(false) { + // Cross schema was valid at signature time + if !ValidateSigTime(args.Data, crossData) { + args.Callback(false, fmt.Errorf("cross schema signature time invalid: %s", crossData.Name())) + return + } + } else { + if CertIsExpired(crossData) { + args.Callback(false, fmt.Errorf("cross schema is expired: %s", crossData.Name())) + return + } + } } // Parse the cross schema content @@ -440,6 +462,8 @@ func (tc *TrustConfig) validateCrossSchema(args TrustConfigValidateArgs) { IgnoreValidity: args.IgnoreValidity, depth: args.depth, + + UseSignatureTime: args.UseSignatureTime, }) } @@ -669,6 +693,42 @@ func (tc *TrustConfig) tryListedCerts(args certListArgs, names []enc.Name, idx i IgnoreValidity: args.args.IgnoreValidity, origDataName: args.args.origDataName, depth: args.args.depth, + + UseSignatureTime: args.args.UseSignatureTime, }) }) } + +// Returns true if signature time is within certificate validity period +func ValidateSigTime(data ndn.Data, cert ndn.Data) bool { + if cert.Signature() == nil { + return false + } + + exceptionNameStrings := []string{ + "/ndn/edu/ucla/KEY/%2F%0D%23x%03%E5%FFC/NA/v=1770689778343", + "/ndn/KEY/%27%C4%B2%2A%9F%7B%81%27/ndn/v=1651246789556", + } + for _, nameString := range exceptionNameStrings { + name, _ := enc.NameFromStr(nameString) + if cert.Name().Equal(name) { + return true + } + } + + sigTime := data.Signature().SigTime() + + if sigTime == nil { + return false + } + + notBefore, notAfter := cert.Signature().Validity() + if val, ok := notBefore.Get(); !ok || sigTime.Before(val) { + return false + } + if val, ok := notAfter.Get(); !ok || sigTime.After(val) { + return false + } + + return true +} diff --git a/std/security/trust_config_test.go b/std/security/trust_config_test.go index 8ca26328..c441e0a6 100644 --- a/std/security/trust_config_test.go +++ b/std/security/trust_config_test.go @@ -1044,3 +1044,375 @@ func TestTrustConfigLvsInter(t *testing.T) { testTrustConfigInter(t, schemaInter) } + +func TestSignatureTimeValidationFlows(t *testing.T) { + tu.SetT(t) + + // Use intra-domain schema with root-to-root signing support + // This schema is the same as TRUST_CONFIG_INTER_LVS but allows roots to sign each other + schema, err := trust_schema.NewLvsSchema(TRUST_CONFIG_INTER_LVS) + require.NoError(t, err) + + clear(tcTestNetwork) + tcTestT = t + network := tcTestNetwork + + now := time.Now() + nb := now + na := now.Add(time.Second * 5) + n := func(s string) enc.Name { return tu.NoErr(enc.NameFromStr(s)) } + + // Expired root (old root) + expiredRootSigner := tu.NoErr(signer.KeygenEd25519(sec.MakeKeyName(n("/root")))) + expiredRootKeyData := tu.NoErr(signer.MarshalSecretToData(expiredRootSigner)) + expiredRootCertWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: expiredRootSigner, + Data: expiredRootKeyData, + IssuerId: enc.NewGenericComponent("self"), + NotBefore: nb, + NotAfter: now.Add(time.Second * 7), // Expires in 7 seconds + })) + expiredRootCertData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(expiredRootCertWire)) + network[expiredRootCertData.Name().String()] = expiredRootCertWire + + // New root (replacement root) + newRootSigner := tu.NoErr(signer.KeygenEd25519(sec.MakeKeyName(n("/root")))) + newRootKeyData := tu.NoErr(signer.MarshalSecretToData(newRootSigner)) + newRootCertWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: newRootSigner, + Data: newRootKeyData, + IssuerId: enc.NewGenericComponent("self"), + NotBefore: nb, + NotAfter: now.Add(time.Second * 17), + })) + newRootCertData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(newRootCertWire)) + network[newRootCertData.Name().String()] = newRootCertWire + + // PreAnchor: replacement certificate for expired root's key, signed by new root + // This certificate verifies/authorizes the expired root's key + expiredRootVerifCertWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: newRootSigner, // Signed by new root + Data: expiredRootKeyData, // Certificate for expired root's key + IssuerId: enc.NewGenericComponent("root"), + NotBefore: nb, + NotAfter: now.Add(time.Second * 15), + })) + expiredRootVerifCertData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(expiredRootVerifCertWire)) + + // CertList for expired root pointing to preAnchor + // This CertList is signed by the expired root itself + expiredRootCertListContent := tu.NoErr(sec.EncodeCertList([]enc.Name{expiredRootVerifCertData.Name()})) + expiredRootCertListPrefix := tu.NoErr(sec.CertListPrefix(expiredRootSigner.KeyName())) + expiredRootCertListName := expiredRootCertListPrefix.Append(enc.NewVersionComponent(uint64(now.UnixMicro()))) + expiredRootCertListWire := tu.NoErr(spec.Spec{}.MakeData(expiredRootCertListName, &ndn.DataConfig{ + Freshness: optional.Some(time.Second * 19), + SigNotBefore: optional.Some(nb), + SigNotAfter: optional.Some(na), + }, expiredRootCertListContent, expiredRootSigner)) // Signed by expired root + expiredRootCertListData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(expiredRootCertListWire.Wire)) + + // Owner <= testbed + ownerSigner := tu.NoErr(signer.KeygenEd25519(sec.MakeKeyName(n("/root/owner")))) + ownerKeyData := tu.NoErr(signer.MarshalSecretToData(ownerSigner)) + ownerCertWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: expiredRootSigner, + Data: ownerKeyData, + IssuerId: enc.NewGenericComponent("root"), + NotBefore: nb, + NotAfter: na, + })) + ownerCertData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(ownerCertWire)) + + // Workspace anchor (cert) + anchorSigner := tu.NoErr(signer.KeygenEd25519(sec.MakeKeyName(n("/app")))) + anchorKeyData := tu.NoErr(signer.MarshalSecretToData(anchorSigner)) + anchorCertWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: anchorSigner, + Data: anchorKeyData, + IssuerId: enc.NewGenericComponent("self"), + NotBefore: nb, + NotAfter: na, + })) + anchorCertData, anchorSigCov, _ := spec.Spec{}.ReadData(enc.NewWireView(anchorCertWire)) + + // Workspace preanchor (precert) + preAnchorWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: ownerSigner, + Data: anchorKeyData, + IssuerId: enc.NewGenericComponent("owner"), + NotBefore: nb, + NotAfter: na, + })) + preAnchorData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(preAnchorWire)) + + listContent := tu.NoErr(sec.EncodeCertList([]enc.Name{preAnchorData.Name()})) + listPrefix := tu.NoErr(sec.CertListPrefix(anchorSigner.KeyName())) + listName := listPrefix.Append(enc.NewVersionComponent(uint64(time.Now().UnixMicro()))) + listWireEnc := tu.NoErr(spec.Spec{}.MakeData(listName, &ndn.DataConfig{ + Freshness: optional.Some(time.Minute), + SigNotBefore: optional.Some(nb), + SigNotAfter: optional.Some(na), + }, listContent, anchorSigner)) + listData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(listWireEnc.Wire)) + + aliceSigner := tu.NoErr(signer.KeygenEd25519(sec.MakeKeyName(n("/app/user/alice")))) + aliceKeyData := tu.NoErr(signer.MarshalSecretToData(aliceSigner)) + aliceCertWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: anchorSigner, + Data: aliceKeyData, + IssuerId: enc.NewGenericComponent("app"), + NotBefore: nb, + NotAfter: na, + })) + aliceCertData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(aliceCertWire)) + + // User data + payload := enc.Wire{[]byte{0x01}} + dataWire := tu.NoErr(spec.Spec{}.MakeData(n("/app/user/alice/data"), &ndn.DataConfig{ + Freshness: optional.Some(time.Minute), + }, payload, aliceSigner)) + dataPkt, dataSigCov, _ := spec.Spec{}.ReadData(enc.NewWireView(dataWire.Wire)) + + // User data with invalid signature time + sigTimeBeforeUserCert := optional.Some(time.Duration(now.Add(-time.Hour).UnixMilli()) * time.Millisecond) + dataWireInvalidSigTime := tu.NoErr(spec.Spec{}.MakeData(n("/app/user/alice/data"), &ndn.DataConfig{ + Freshness: optional.Some(time.Minute), + SigTime: sigTimeBeforeUserCert, + }, payload, aliceSigner)) + dataPktInvalidSigTime, dataSigCovInvalidSigTime, _ := spec.Spec{}.ReadData(enc.NewWireView(dataWireInvalidSigTime.Wire)) + + bobSigner := tu.NoErr(signer.KeygenEd25519(sec.MakeKeyName(n("/app/user/bob")))) + bobKeyData := tu.NoErr(signer.MarshalSecretToData(bobSigner)) + bobCertWire := tu.NoErr(sec.SignCert(sec.SignCertArgs{ + Signer: anchorSigner, + Data: bobKeyData, + IssuerId: enc.NewGenericComponent("app"), + NotBefore: nb, + NotAfter: na, + })) + bobCertData, _, _ := spec.Spec{}.ReadData(enc.NewWireView(bobCertWire)) + network[bobCertData.Name().String()] = bobCertWire + + abInvite, err := trust_schema.SignCrossSchema(trust_schema.SignCrossSchemaArgs{ + Name: sname("/app/user/alice/32=INVITE/app/user/bob/v=1"), + Signer: aliceSigner, + Content: trust_schema.CrossSchemaContent{ + SimpleSchemaRules: []*trust_schema.SimpleSchemaRule{{ + NamePrefix: sname("/app/user/alice/app/bob"), + KeyLocator: &spec.KeyLocator{Name: sname("/app/bob/KEY")}, // any key from bob + }}, + }, + NotBefore: time.Now().Add(time.Second * 7), + NotAfter: time.Now().Add(time.Second * 12), + }) + require.NoError(t, err) + + dataWireInvalidSigTimeCrossSchema := tu.NoErr(spec.Spec{}.MakeData(n("/app/user/alice/app/bob/data"), &ndn.DataConfig{ + Freshness: optional.Some(time.Minute), + SigTime: optional.Some(time.Duration(now.UnixMilli()) * time.Millisecond), + CrossSchema: abInvite, + }, payload, bobSigner)) + dataPktInvalidSigTimeCrossSchema, dataSigCovInvalidSigTimeCrossSchema, _ := spec.Spec{}.ReadData(enc.NewWireView(dataWireInvalidSigTimeCrossSchema.Wire)) + + require.True(t, schema.Check(anchorCertData.Name(), anchorCertData.Name())) + require.True(t, schema.Check(preAnchorData.Name(), ownerCertData.Name())) + require.True(t, schema.Check(listData.Name(), anchorCertData.Name())) + require.True(t, schema.Check(aliceCertData.Name(), anchorCertData.Name())) + require.True(t, schema.Check(dataPkt.Name(), aliceCertData.Name())) + require.True(t, schema.Check(dataPktInvalidSigTime.Name(), aliceCertData.Name())) + + network[anchorCertData.Name().String()] = anchorCertWire + network[aliceCertData.Name().String()] = aliceCertWire + network[ownerCertData.Name().String()] = ownerCertWire + + type stage struct { + preprocess func() + name string + add map[string]enc.Wire + kcInsert []enc.Wire + trustAnchors []enc.Name + data ndn.Data + dataSigCov enc.Wire + expectAnchor bool + expectData bool + expectErrPart string + } + + validateOnce := func(trust *sec.TrustConfig, data ndn.Data, sigCov enc.Wire) (bool, error) { + tcTestFetchCount = 0 + done := make(chan struct { + v bool + err error + }, 1) + trust.Validate(sec.TrustConfigValidateArgs{ + Data: data, + DataSigCov: sigCov, + Fetch: fetchFun, + Callback: func(valid bool, err error) { + done <- struct { + v bool + err error + }{v: valid, err: err} + }, + + UseSignatureTime: optional.Some(true), + }) + res := <-done + return res.v, res.err + } + + stages := []stage{ + // Validate flows before the expired root is replaced + { + preprocess: func() { + return + }, + name: "normal no certlist ok", + add: map[string]enc.Wire{ + listData.Name().String(): listWireEnc.Wire, + preAnchorData.Name().String(): preAnchorWire, + }, + kcInsert: []enc.Wire{expiredRootCertWire, newRootCertWire}, + trustAnchors: []enc.Name{expiredRootCertData.Name(), newRootCertData.Name()}, + expectAnchor: true, + expectData: true, + }, + { + preprocess: func() { + return + }, + name: "normal chain certlist ok", + add: map[string]enc.Wire{ + expiredRootCertListData.Name().String(): expiredRootCertListWire.Wire, + expiredRootVerifCertData.Name().String(): expiredRootVerifCertWire, + listData.Name().String(): listWireEnc.Wire, + preAnchorData.Name().String(): preAnchorWire, + }, + kcInsert: []enc.Wire{newRootCertWire}, + trustAnchors: []enc.Name{newRootCertData.Name()}, + expectAnchor: true, + expectData: true, + }, + { + preprocess: func() { + return + }, + name: "data signed when user cert invalid", + add: map[string]enc.Wire{ + expiredRootCertListData.Name().String(): expiredRootCertListWire.Wire, + expiredRootVerifCertData.Name().String(): expiredRootVerifCertWire, + listData.Name().String(): listWireEnc.Wire, + preAnchorData.Name().String(): preAnchorWire, + }, + kcInsert: []enc.Wire{expiredRootCertWire, newRootCertWire}, + trustAnchors: []enc.Name{expiredRootCertData.Name(), newRootCertData.Name()}, + data: dataPktInvalidSigTime, + dataSigCov: dataSigCovInvalidSigTime, + expectAnchor: true, + expectData: false, + expectErrPart: "data not signed during validity period", + }, + { + preprocess: func() { + return + }, + name: "data signed when cross schema invalid", + add: map[string]enc.Wire{ + expiredRootCertListData.Name().String(): expiredRootCertListWire.Wire, + expiredRootVerifCertData.Name().String(): expiredRootVerifCertWire, + listData.Name().String(): listWireEnc.Wire, + preAnchorData.Name().String(): preAnchorWire, + }, + kcInsert: []enc.Wire{expiredRootCertWire, newRootCertWire}, + trustAnchors: []enc.Name{expiredRootCertData.Name(), newRootCertData.Name()}, + data: dataPktInvalidSigTimeCrossSchema, + dataSigCov: dataSigCovInvalidSigTimeCrossSchema, + expectAnchor: true, + expectData: false, + expectErrPart: "cross schema signature time invalid", + }, + + // Validate flows after the expired root is replaced + { + preprocess: func() { + time.Sleep(time.Second * 9) // Wait for expiration + }, + name: "expired chain certlist ok", + add: map[string]enc.Wire{ + expiredRootCertListData.Name().String(): expiredRootCertListWire.Wire, + expiredRootVerifCertData.Name().String(): expiredRootVerifCertWire, + listData.Name().String(): listWireEnc.Wire, + preAnchorData.Name().String(): preAnchorWire, + }, + kcInsert: []enc.Wire{newRootCertWire}, + trustAnchors: []enc.Name{newRootCertData.Name()}, + expectAnchor: true, + expectData: true, + }, + { + preprocess: func() { + // Remove the certlist and certificate from the network to simulate a fully expired chain + delete(network, expiredRootCertListData.Name().String()) + delete(network, expiredRootVerifCertData.Name().String()) + }, + name: "expired chain no certlist not ok", + add: map[string]enc.Wire{listData.Name().String(): listWireEnc.Wire, preAnchorData.Name().String(): preAnchorWire}, + kcInsert: []enc.Wire{newRootCertWire}, + trustAnchors: []enc.Name{newRootCertData.Name()}, + expectAnchor: false, + expectData: false, + }, + } + + for _, st := range stages { + st.preprocess() + + t.Run(st.name, func(t *testing.T) { + store := storage.NewMemoryStore() + tcTestKeyChain = keychain.NewKeyChainMem(store) + kc := tcTestKeyChain + + for k, v := range st.add { + network[k] = v + } + + for _, w := range st.kcInsert { + require.NoError(t, kc.InsertCert(w.Join())) + } + trust, err := sec.NewTrustConfig(kc, schema, st.trustAnchors) + require.NoError(t, err) + + validateData := dataPkt + validateSigCov := dataSigCov + if st.data != nil { + validateData = st.data + validateSigCov = st.dataSigCov + } + + // Validate anchor cert first, then user data. + anchorValid, anchorErr := validateOnce(trust, anchorCertData, anchorSigCov) + dataValid, dataErr := validateOnce(trust, validateData, validateSigCov) + if st.expectData { + require.True(t, dataValid) + require.NoError(t, dataErr) + } else { + require.False(t, dataValid) + require.Error(t, dataErr) + if st.expectErrPart != "" { + require.Contains(t, dataErr.Error(), st.expectErrPart) + } + } + + if st.expectAnchor { + require.True(t, anchorValid) + require.NoError(t, anchorErr) + } else { + require.False(t, anchorValid) + require.Error(t, anchorErr) + if st.expectErrPart != "" { + require.Contains(t, anchorErr.Error(), st.expectErrPart) + } + } + }) + } +} diff --git a/std/sync/snapshot_node_history.go b/std/sync/snapshot_node_history.go index 0032358a..bf9de2df 100644 --- a/std/sync/snapshot_node_history.go +++ b/std/sync/snapshot_node_history.go @@ -44,6 +44,8 @@ type SnapshotNodeHistory struct { // In Repo mode, all snapshots are fetched automtically for persistence. IsRepo bool + // UseSignatureTime checks validity period using signature time + UseSignatureTime optional.Optional[bool] // IgnoreValidity ignores validity period in the validation chain IgnoreValidity optional.Optional[bool] // repoKnown is the known snapshot sequence number. @@ -162,8 +164,9 @@ func (s *SnapshotNodeHistory) idxName(node enc.Name, boot uint64) enc.Name { // fetchIndex fetches the latest index for a remote node. func (s *SnapshotNodeHistory) fetchIndex(node enc.Name, boot uint64, known uint64) { s.Client.ConsumeExt(ndn.ConsumeExtArgs{ - Name: s.idxName(node, boot), - IgnoreValidity: s.IgnoreValidity, + Name: s.idxName(node, boot), + UseSignatureTime: s.UseSignatureTime, + IgnoreValidity: s.IgnoreValidity, Callback: func(cstate ndn.ConsumeState) { go s.handleIndex(node, boot, known, cstate) }, @@ -210,9 +213,10 @@ func (s *SnapshotNodeHistory) handleIndex(node enc.Name, boot uint64, known uint snapName := s.snapName(node, boot).WithVersion(seqNo) s.Client.ConsumeExt(ndn.ConsumeExtArgs{ - Name: snapName, - IgnoreValidity: s.IgnoreValidity, - Callback: func(cstate ndn.ConsumeState) { snapC <- cstate }, + Name: snapName, + UseSignatureTime: s.UseSignatureTime, + IgnoreValidity: s.IgnoreValidity, + Callback: func(cstate ndn.ConsumeState) { snapC <- cstate }, }) scstate := <-snapC diff --git a/std/sync/snapshot_node_latest.go b/std/sync/snapshot_node_latest.go index 569fd254..0a5c369a 100644 --- a/std/sync/snapshot_node_latest.go +++ b/std/sync/snapshot_node_latest.go @@ -33,6 +33,8 @@ type SnapshotNodeLatest struct { SnapMe func(enc.Name) (enc.Wire, error) // Threshold is the number of updates before a snapshot is taken. Threshold uint64 + // UseSignatureTime checks validity period using signature time + UseSignatureTime optional.Optional[bool] // IgnoreValidity ignores validity period in the validation chain IgnoreValidity optional.Optional[bool] @@ -119,8 +121,9 @@ func (s *SnapshotNodeLatest) snapName(node enc.Name, boot uint64) enc.Name { func (s *SnapshotNodeLatest) fetchSnap(node enc.Name, boot uint64) { // Discover the latest snapshot s.Client.ConsumeExt(ndn.ConsumeExtArgs{ - Name: s.snapName(node, boot), - IgnoreValidity: s.IgnoreValidity, + Name: s.snapName(node, boot), + UseSignatureTime: s.UseSignatureTime, + IgnoreValidity: s.IgnoreValidity, Callback: func(cstate ndn.ConsumeState) { if cstate.Error() != nil { // Do not try too fast in case NFD returns NACK diff --git a/std/sync/svs.go b/std/sync/svs.go index 53cf7402..60e71015 100644 --- a/std/sync/svs.go +++ b/std/sync/svs.go @@ -69,6 +69,8 @@ type SvSyncOpts struct { // Passive mode does not send sign Sync Interests Passive bool + // UseSignatureTime checks validity period using signature time + UseSignatureTime optional.Optional[bool] // IgnoreValidity ignores validity period in the validation chain IgnoreValidity optional.Optional[bool] } @@ -524,9 +526,10 @@ func (s *SvSync) onSyncData(dataWire enc.Wire) { // Validate signature s.o.Client.ValidateExt(ndn.ValidateExtArgs{ - Data: data, - SigCovered: sigCov, - IgnoreValidity: s.o.IgnoreValidity, + Data: data, + SigCovered: sigCov, + UseSignatureTime: s.o.UseSignatureTime, + IgnoreValidity: s.o.IgnoreValidity, Callback: func(valid bool, err error) { if !valid || err != nil { log.Warn(s, "SvSync failed to validate signature", "name", data.Name(), "valid", valid, "err", err) diff --git a/std/sync/svs_alo.go b/std/sync/svs_alo.go index 384a14eb..f6df6e33 100644 --- a/std/sync/svs_alo.go +++ b/std/sync/svs_alo.go @@ -140,7 +140,7 @@ func NewSvsALO(opts SvsAloOpts) (*SvsALO, error) { }, s.state) } - // Overeide IgnoreValidity from SVS (incorect but practical) + // Override IgnoreValidity from SVS (incorrect but practical) if latest, ok := s.opts.Snapshot.(*SnapshotNodeLatest); ok { latest.IgnoreValidity = s.opts.Svs.IgnoreValidity } diff --git a/std/sync/svs_alo_data.go b/std/sync/svs_alo_data.go index d22035d0..27543385 100644 --- a/std/sync/svs_alo_data.go +++ b/std/sync/svs_alo_data.go @@ -117,9 +117,9 @@ func (s *SvsALO) consumeCheck(node enc.Name) { func (s *SvsALO) consumeObject(node enc.Name, boot uint64, seq uint64) { fetchName := s.objectName(node, boot, seq) s.client.ConsumeExt(ndn.ConsumeExtArgs{ - Name: fetchName, - // inherit ignoreValidity from SVS, not correct but practical - IgnoreValidity: s.opts.Svs.IgnoreValidity, + Name: fetchName, + UseSignatureTime: s.opts.Svs.UseSignatureTime, + IgnoreValidity: s.opts.Svs.IgnoreValidity, Callback: func(status ndn.ConsumeState) { s.mutex.Lock() defer s.mutex.Unlock()