Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/nightly-fuzz.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ jobs:
- name: identity-idemixnym-audit-info-deserializer
pkg: ./token/services/identity/idemixnym/nym
func: FuzzDeserializeAuditInfoNoPanic
- name: identity-boolpolicy-audit-info-deserializer
pkg: ./token/services/identity/boolpolicy
func: FuzzDeserializeAuditInfoNoPanic
- name: common-request-limits
pkg: ./token/core/common
func: FuzzRequestResourceLimits
Expand Down
1 change: 1 addition & 0 deletions docs/services/identity.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ Located in `token/services/identity/boolpolicy`.
- `identities` (SEQUENCE OF OCTET STRING): ordered list of raw component identity bytes; `$N` indexes into this list.
* **Audit Info**: JSON-encoded `AuditInfo` structure.
- `IdentityAuditInfos` (array of `IdentityAuditInfo`): per-component audit info blobs in the same order as `identities`.
* **Enrollment ID**: When the audit-info deserializer is built with the parent multiplex deserializer (`NewAuditInfoDeserializer`), the policy identity reports the enrollment ID shared by all component identities. Components with no enrollment ID of their own (e.g. a nested composite spanning enrollments), components whose audit info is missing (e.g. an identity not registered locally), or disagreeing components yield an empty enrollment ID; a missing component audit info takes precedence over subtype resolution, so an unknown component identity type carrying no audit info also yields an empty enrollment ID. A non-empty component audit info that cannot be resolved, an invalid component identity, or a component count mismatch is an error.
* **Encoding**:
- `TypedIdentity` payload: ASN.1 DER.
- Audit Info: JSON.
Expand Down
2 changes: 1 addition & 1 deletion token/core/fabtoken/v1/driver/deserializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func NewEIDRHDeserializer() *EIDRHDeserializer {
d.AddDeserializer(x509.IdentityType, &x509.AuditInfoDeserializer{})
d.AddDeserializer(htlc2.ScriptType, htlc.NewAuditDeserializer(d))
d.AddDeserializer(multisig.Multisig, &multisig.AuditInfoDeserializer{})
d.AddDeserializer(boolpolicy.Policy, &boolpolicy.AuditInfoDeserializer{})
d.AddDeserializer(boolpolicy.Policy, boolpolicy.NewAuditInfoDeserializer(d))

return d
}
Expand Down
2 changes: 1 addition & 1 deletion token/core/zkatdlog/nogh/v1/driver/deserializer.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func NewEIDRHDeserializer() *EIDRHDeserializer {
d.AddDeserializer(x509.IdentityType, &x509.AuditInfoDeserializer{})
d.AddDeserializer(htlc2.ScriptType, htlc.NewAuditDeserializer(d))
d.AddDeserializer(multisig.Multisig, &multisig.AuditInfoDeserializer{})
d.AddDeserializer(boolpolicy.Policy, &boolpolicy.AuditInfoDeserializer{})
d.AddDeserializer(boolpolicy.Policy, boolpolicy.NewAuditInfoDeserializer(d))

return d
}
Expand Down
86 changes: 86 additions & 0 deletions token/services/identity/boolpolicy/audit_fuzz_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
Copyright IBM Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/

package boolpolicy

import (
"testing"

"github.com/LFDT-Panurus/panurus/token/services/identity"
"github.com/LFDT-Panurus/panurus/token/services/identity/x509"
"github.com/stretchr/testify/require"
)

const maxFuzzAuditInfoBytes = 64 << 10

// fuzzMember returns a typed x509 member identity and its audit info bytes.
func fuzzMember(f *testing.F, name, eid string) ([]byte, []byte) {
f.Helper()
member, err := identity.WrapWithType(x509.IdentityType, []byte(name))
require.NoError(f, err)
auditInfo, err := (&x509.AuditInfo{EID: eid, RH: []byte("rh-" + eid)}).Bytes()
require.NoError(f, err)

return member, auditInfo
}

// fuzzPolicy wraps members into a policy identity (inner DER and typed
// envelope) and the matching composite audit info blob.
func fuzzPolicy(f *testing.F, policy string, members, auditInfos [][]byte) (inner, envelope, wrapped []byte) {
f.Helper()
inner, err := (&PolicyIdentity{Policy: policy, Identities: members}).Serialize()
require.NoError(f, err)
envelope, err = identity.WrapWithType(Policy, inner)
require.NoError(f, err)
wrapped, err = WrapAuditInfo(auditInfos)
require.NoError(f, err)

return inner, envelope, wrapped
}

func FuzzDeserializeAuditInfoNoPanic(f *testing.F) {
m0, ai0 := fuzzMember(f, "cert-zero", "wallet-42")
m1, ai1 := fuzzMember(f, "cert-one", "wallet-43")

// valid single- and two-member policies, both identity encodings
inner1, envelope1, wrapped1 := fuzzPolicy(f, "$0", [][]byte{m0}, [][]byte{ai0})
f.Add(inner1, wrapped1)
f.Add(envelope1, wrapped1)
inner2, _, wrapped2 := fuzzPolicy(f, "$0 OR $1", [][]byte{m0, m1}, [][]byte{ai0, ai1})
f.Add(inner2, wrapped2)
// empty and truncated inputs
f.Add([]byte{}, []byte{})
f.Add(inner2[:len(inner2)/2], wrapped2[:len(wrapped2)/2])
f.Add(inner2, []byte(`{"IdentityAuditInfos":`))
f.Add(inner1, []byte(`{}`))
// member count mismatch
innerMismatch, _, wrappedOne := fuzzPolicy(f, "$0 OR $1", [][]byte{m0, m1}, [][]byte{ai0})
f.Add(innerMismatch, wrappedOne)
// missing component audit info
innerMissing, _, wrappedMissing := fuzzPolicy(f, "$0 OR $1", [][]byte{m0, m1}, [][]byte{ai0, nil})
f.Add(innerMissing, wrappedMissing)
// unknown member identity type
unknown, err := identity.WrapWithType(identity.Type(99), []byte("cert-x"))
require.NoError(f, err)
innerUnknown, _, wrappedUnknown := fuzzPolicy(f, "$0", [][]byte{unknown}, [][]byte{ai0})
f.Add(innerUnknown, wrappedUnknown)
// nested and deeply nested policies
nestedID, nestedInfo := m0, ai0
for range 5 {
_, nestedID, nestedInfo = fuzzPolicy(f, "$0", [][]byte{nestedID}, [][]byte{nestedInfo})
}
innerDeep, _, wrappedDeep := fuzzPolicy(f, "$0", [][]byte{nestedID}, [][]byte{nestedInfo})
f.Add(innerDeep, wrappedDeep)

f.Fuzz(func(t *testing.T, rawID, rawInfo []byte) {
if len(rawID) > maxFuzzAuditInfoBytes || len(rawInfo) > maxFuzzAuditInfoBytes {
t.Skip()
}
require.NotPanics(t, func() {
_, _ = NewAuditInfoDeserializer(newEIDRHDeserializer()).DeserializeAuditInfo(t.Context(), rawID, rawInfo)
})
})
}
Loading
Loading