Skip to content

Commit 269a5c5

Browse files
TristanCacquerayblackheaven
authored andcommitted
Use the cvss library in hsec-tools
1 parent 5684643 commit 269a5c5

File tree

9 files changed

+45
-24
lines changed

9 files changed

+45
-24
lines changed

code/cvss/src/Security/CVSS.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ data CVSSVersion
4242
CVSS30
4343
| -- | Version 2.0: https://www.first.org/cvss/v2/
4444
CVSS20
45+
deriving (Eq)
4546

4647
-- | Parsed CVSS string obtained with 'parseCVSS'.
4748
data CVSS = CVSS

code/hsec-tools/cabal.project

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
packages: *.cabal
1+
packages: *.cabal ../cvss/cvss.cabal
22

33
package hsec-tools

code/hsec-tools/hsec-tools.cabal

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ library
4949
, commonmark ^>=0.2.2
5050
, commonmark-pandoc >=0.2 && <0.3
5151
, containers >=0.6 && <0.7
52+
, cvss
5253
, directory <2
5354
, extra ^>=1.7.5
5455
, filepath >=1.4 && <1.5
@@ -104,6 +105,7 @@ test-suite spec
104105
build-depends:
105106
, base <5
106107
, Cabal-syntax
108+
, cvss
107109
, directory
108110
, hsec-tools
109111
, pretty-simple <5

code/hsec-tools/src/Security/Advisories/Convert/OSV.hs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ mkAffected aff =
3333
OSV.Affected
3434
{ OSV.affectedPackage = mkPackage (affectedPackage aff)
3535
, OSV.affectedRanges = pure $ mkRange (affectedVersions aff)
36-
, OSV.affectedSeverity = mkSeverity (affectedCVSS aff)
36+
, OSV.affectedSeverity = [OSV.Severity (affectedCVSS aff)]
3737
, OSV.affectedEcosystemSpecific = Nothing
3838
, OSV.affectedDatabaseSpecific = Nothing
3939
}
@@ -45,15 +45,6 @@ mkPackage name = OSV.Package
4545
, OSV.packagePurl = Nothing
4646
}
4747

48-
-- NOTE: This is unpleasant. But we will eventually switch to a
49-
-- proper CVSS type and the unpleasantness will go away.
50-
--
51-
mkSeverity :: T.Text -> [OSV.Severity]
52-
mkSeverity s = case T.take 6 s of
53-
"CVSS:2" -> [OSV.SeverityCvss2 s]
54-
"CVSS:3" -> [OSV.SeverityCvss3 s]
55-
_ -> [] -- unexpected; don't include severity
56-
5748
mkRange :: [AffectedVersionRange] -> OSV.Range Void
5849
mkRange ranges =
5950
OSV.RangeEcosystem (foldMap mkEvs ranges) Nothing

code/hsec-tools/src/Security/Advisories/Definition.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import Distribution.Types.VersionRange (VersionRange)
2020
import Text.Pandoc.Definition (Pandoc)
2121

2222
import Security.Advisories.HsecId
23+
import qualified Security.CVSS as CVSS
2324
import Security.OSV (Reference)
2425

2526
data Advisory = Advisory
@@ -45,7 +46,7 @@ data Advisory = Advisory
4546
-- mention one or more packages.
4647
data Affected = Affected
4748
{ affectedPackage :: Text
48-
, affectedCVSS :: Text -- TODO refine type
49+
, affectedCVSS :: CVSS.CVSS
4950
, affectedVersions :: [AffectedVersionRange]
5051
, affectedArchitectures :: Maybe [Architecture]
5152
, affectedOS :: Maybe [OS]

code/hsec-tools/src/Security/Advisories/Parse.hs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import Text.Parsec.Pos (sourceLine)
4848
import Security.Advisories.HsecId
4949
import Security.Advisories.Definition
5050
import Security.OSV (Reference(..), referenceTypes)
51+
import qualified Security.CVSS as CVSS
5152

5253
-- | A source of attributes supplied out of band from the advisory
5354
-- content. Values provided out of band are treated according to
@@ -499,6 +500,16 @@ instance Toml.FromValue VersionRange where
499500
instance Toml.ToValue VersionRange where
500501
toValue = Toml.toValue . show
501502

503+
instance Toml.FromValue CVSS.CVSS where
504+
fromValue v =
505+
do s <- Toml.fromValue v
506+
case CVSS.parseCVSS s of
507+
Left err -> fail ("parse error in cvss: " ++ show err)
508+
Right cvss -> pure cvss
509+
510+
instance Toml.ToValue CVSS.CVSS where
511+
toValue = Toml.toValue . CVSS.cvssVectorString
512+
502513
mergeOob
503514
:: MonadFail m
504515
=> AttributeOverridePolicy

code/hsec-tools/src/Security/OSV.hs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import Data.Time (UTCTime)
4444
import Data.Time.Format.ISO8601 (iso8601ParseM)
4545
import Data.Tuple (swap)
4646

47+
import qualified Security.CVSS as CVSS
48+
4749
data Affected dbSpecific ecosystemSpecific rangeDbSpecific = Affected
4850
{ affectedRanges :: [Range rangeDbSpecific]
4951
, affectedPackage :: Package
@@ -146,27 +148,36 @@ newModel' = newModel defaultSchemaVersion
146148
-- calculated and compared in a more nuanced way than 'Ord' can provide
147149
-- for.
148150
--
149-
data Severity
150-
= SeverityCvss2 Text {- TODO refine -}
151-
| SeverityCvss3 Text {- TODO refine -}
152-
deriving (Show, Eq)
151+
newtype Severity = Severity CVSS.CVSS
152+
deriving (Show)
153+
154+
instance Eq Severity where
155+
Severity s1 == Severity s2 = CVSS.cvssVectorString s1 == CVSS.cvssVectorString s2
153156

154157
instance FromJSON Severity where
155158
parseJSON = withObject "severity" $ \o -> do
156159
typ <- o .: "type" :: Parser Text
160+
score <- o .: "score" :: Parser Text
161+
cvss <- case CVSS.parseCVSS score of
162+
Right cvss -> pure cvss
163+
Left err ->
164+
prependFailure ("unregognised severity score: " <> show err)
165+
$ typeMismatch "severity" (Object o)
157166
case typ of
158-
"CVSS_V2" -> SeverityCvss2 <$> o .: "score"
159-
"CVSS_V3" -> SeverityCvss3 <$> o .: "score"
167+
"CVSS_V2" | CVSS.cvssVersion cvss == CVSS.CVSS20 -> pure $ Severity cvss
168+
"CVSS_V3" | CVSS.cvssVersion cvss `elem` [CVSS.CVSS30, CVSS.CVSS31] -> pure $ Severity cvss
160169
s ->
161170
prependFailure ("unregognised severity type: " <> show s)
162171
$ typeMismatch "severity" (Object o)
163172

164173
instance ToJSON Severity where
165-
toJSON sev = object $ case sev of
166-
SeverityCvss2 score -> [typ "CVSS_V2", "score" .= score]
167-
SeverityCvss3 score -> [typ "CVSS_V3", "score" .= score]
174+
toJSON (Severity cvss) = object ["type" .= CVSS.cvssVectorString cvss, "score" .= score]
168175
where
169-
typ s = "type" .= (s :: Text)
176+
score :: Text
177+
score = case CVSS.cvssVersion cvss of
178+
CVSS.CVSS31 -> "CVSS_V3"
179+
CVSS.CVSS30 -> "CVSS_V3"
180+
CVSS.CVSS20 -> "CVSS_V2"
170181

171182
data Package = Package
172183
{ packageName :: Text

code/hsec-tools/test/Spec/QueriesSpec.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
module Spec.QueriesSpec (spec) where
55

66
import Data.Bifunctor (first)
7+
import Data.Either (fromRight)
78
import Data.Maybe (fromMaybe)
89
import Data.Text (Text)
910
import qualified Data.Text as T
@@ -13,6 +14,7 @@ import Distribution.Types.VersionRange (VersionRange, VersionRangeF(..), anyVers
1314
import Test.Tasty
1415
import Test.Tasty.HUnit
1516

17+
import Security.CVSS (parseCVSS)
1618
import Security.Advisories.Definition
1719
import Security.Advisories.HsecId
1820
import Security.Advisories.Queries
@@ -113,7 +115,7 @@ mkAdvisory versionRange =
113115
, advisoryAffected =
114116
[ Affected
115117
{ affectedPackage = packageName
116-
, affectedCVSS = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
118+
, affectedCVSS = cvss
117119
, affectedVersions = mkAffectedVersions versionRange
118120
, affectedArchitectures = Nothing
119121
, affectedOS = Nothing
@@ -126,6 +128,8 @@ mkAdvisory versionRange =
126128
, advisorySummary = ""
127129
, advisoryDetails = ""
128130
}
131+
where
132+
cvss = fromRight (error "Cannot parseCVSS") (parseCVSS "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H")
129133

130134
mkAffectedVersions :: VersionRange -> [AffectedVersionRange]
131135
mkAffectedVersions vr =

code/hsec-tools/test/golden/EXAMPLE_ADVISORY.md.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Right
1717
, advisoryAffected =
1818
[ Affected
1919
{ affectedPackage = "package-name"
20-
, affectedCVSS = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
20+
, affectedCVSS = CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
2121
, affectedVersions =
2222
[ AffectedVersionRange
2323
{ affectedVersionRangeIntroduced = mkVersion

0 commit comments

Comments
 (0)