Skip to content

Commit

Permalink
cvss: fix v2 group-wise marshaling behavior
Browse files Browse the repository at this point in the history
Section 2.4 of the standard implies that a vector should have metrics
with not defined values included if a metric in the group has a defined
value.

One might also say that the environmental group implies the temporal
group, but that's quite annoying and the standard should say that if it
wants to say that.

Signed-off-by: Hank Donnay <hdonnay@redhat.com>
  • Loading branch information
hdonnay committed May 10, 2024
1 parent 8a8722c commit 068edb6
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 21 deletions.
45 changes: 31 additions & 14 deletions toolkit/types/cvss/cvss.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,38 @@ func mkRevLookup[M Metric]() map[string]M {
//
// The [Vector.getString] method is used here.
func marshalVector[M Metric, V Vector[M]](prefix string, v V) ([]byte, error) {
text := append(make([]byte, 0, 64), prefix...)
for i := 0; i < M(0).num(); i++ {
m := M(i)
val, err := v.getString(m)
switch {
case errors.Is(err, nil):
case errors.Is(err, errValueUnset):
continue
default:
return nil, errors.New("invalid cvss vector")
text := append(make([]byte, 0, 64), prefix...) // Guess at an initial capacity.
var err error
// This is a rangefunc-style iterator.
v.groups(func(b [2]int) bool {
var set bool
orig := len(text)
for i := b[0]; i < b[1]; i++ {
m := M(i)
val, err := v.getString(m)
switch {
case errors.Is(err, nil):
set = true
case errors.Is(err, errValueUnset) && val == "":
continue
case errors.Is(err, errValueUnset):
default:
err = errors.New("invalid cvss vector")
return false
}

text = append(text, '/')
text = append(text, m.String()...)
text = append(text, ':')
text = append(text, val...)
}
if !set {
text = text[:orig]
}
text = append(text, '/')
text = append(text, m.String()...)
text = append(text, ':')
text = append(text, val...)
return true
})
if err != nil {
return nil, err
}
// v2 hack
if prefix == "" {
Expand Down
5 changes: 4 additions & 1 deletion toolkit/types/cvss/cvss_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ func (v *V2) String() string {
// GetString implements [Vector].
func (v *V2) getString(m V2Metric) (string, error) {
b := v.mv[int(m)]
if b == 0 {
switch {
case b == 0 && m <= V2Availability:
return "", errValueUnset
case b == 0:
return "ND", errValueUnset
}
return v2Unparse(m, b), nil
}
Expand Down
12 changes: 6 additions & 6 deletions toolkit/types/cvss/cvss_v2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ func TestV2(t *testing.T) {
})
t.Run("Roundtrip", func(t *testing.T) {
vecs := []string{
"AV:N/AC:L/Au:N/C:N/I:N/A:C", // CVE-2002-0392
"AV:N/AC:L/Au:N/C:C/I:C/A:C", // CVE-2003-0818
"AV:L/AC:H/Au:N/C:C/I:C/A:C", // CVE-2003-0062
"AV:L/AC:H/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:C/CDP:H/TD:H/CR:M/IR:M/AR:H", // CVE-2002-0392
"AV:L/AC:H/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:UR/CDP:ND/TD:ND", // made up
"AV:L/AC:H/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:UR/CDP:LM/TD:ND", // made up
"AV:N/AC:L/Au:N/C:N/I:N/A:C", // CVE-2002-0392
"AV:N/AC:L/Au:N/C:C/I:C/A:C", // CVE-2003-0818
"AV:L/AC:H/Au:N/C:C/I:C/A:C", // CVE-2003-0062
"AV:L/AC:H/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:C/CDP:H/TD:H/CR:M/IR:M/AR:H", // CVE-2002-0392
"AV:L/AC:H/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:UR/CDP:ND/TD:ND/CR:ND/IR:ND/AR:ND", // made up
"AV:L/AC:H/Au:N/C:C/I:C/A:C/E:F/RL:OF/RC:UR/CDP:LM/TD:ND/CR:ND/IR:ND/AR:ND", // made up
}
Roundtrip[V2, V2Metric, *V2](t, vecs)
})
Expand Down

0 comments on commit 068edb6

Please sign in to comment.