forked from gocsaf/csaf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathadvisory.go
1646 lines (1453 loc) · 57.7 KB
/
advisory.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// This file is Free Software under the MIT License
// without warranty, see README.md and LICENSES/MIT.txt for details.
//
// SPDX-License-Identifier: MIT
//
// SPDX-FileCopyrightText: 2023 German Federal Office for Information Security (BSI) <https://www.bsi.bund.de>
// Software-Engineering: 2023 Intevation GmbH <https://intevation.de>
package csaf
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
)
// Acknowledgement reflects the 'acknowledgement' object in the list of acknowledgements.
// It must at least have one property.
type Acknowledgement struct {
Names []*string `json:"names,omitempty"`
Organization *string `json:"organization,omitempty"`
Summary *string `json:"summary,omitempty"`
URLs []*string `json:"urls,omitempty"`
}
// Acknowledgements is a list of Acknowledgement elements.
type Acknowledgements []*Acknowledgement
// BranchCategory is the category of a branch.
type BranchCategory string
const (
// CSAFBranchCategoryArchitecture is the "architecture" category.
CSAFBranchCategoryArchitecture BranchCategory = "architecture"
// CSAFBranchCategoryHostName is the "host_name" category.
CSAFBranchCategoryHostName BranchCategory = "host_name"
// CSAFBranchCategoryLanguage is the "language" category.
CSAFBranchCategoryLanguage BranchCategory = "language"
// CSAFBranchCategoryLegacy is the "legacy" category.
CSAFBranchCategoryLegacy BranchCategory = "legacy"
// CSAFBranchCategoryPatchLevel is the "patch_level" category.
CSAFBranchCategoryPatchLevel BranchCategory = "patch_level"
// CSAFBranchCategoryProductFamily is the "product_family" category.
CSAFBranchCategoryProductFamily BranchCategory = "product_family"
// CSAFBranchCategoryProductName is the "product_name" category.
CSAFBranchCategoryProductName BranchCategory = "product_name"
// CSAFBranchCategoryProductVersion is the "product_version" category.
CSAFBranchCategoryProductVersion BranchCategory = "product_version"
// CSAFBranchCategoryProductVersionRange is the "product_version_range" category.
CSAFBranchCategoryProductVersionRange BranchCategory = "product_version_range"
// CSAFBranchCategoryServicePack is the "service_pack" category.
CSAFBranchCategoryServicePack BranchCategory = "service_pack"
// CSAFBranchCategorySpecification is the "specification" category.
CSAFBranchCategorySpecification BranchCategory = "specification"
// CSAFBranchCategoryVendor is the "vendor" category.
CSAFBranchCategoryVendor BranchCategory = "vendor"
)
var csafBranchCategoryPattern = alternativesUnmarshal(
string(CSAFBranchCategoryArchitecture),
string(CSAFBranchCategoryHostName),
string(CSAFBranchCategoryLanguage),
string(CSAFBranchCategoryLegacy),
string(CSAFBranchCategoryPatchLevel),
string(CSAFBranchCategoryProductFamily),
string(CSAFBranchCategoryProductName),
string(CSAFBranchCategoryProductVersion),
string(CSAFBranchCategoryProductVersionRange),
string(CSAFBranchCategoryServicePack),
string(CSAFBranchCategorySpecification),
string(CSAFBranchCategoryVendor))
// ProductID is a reference token for product instances. There is no predefined or
// required format for it as long as it uniquely identifies a product in the context
// of the current document.
type ProductID string
// Products is a list of one or more unique ProductID elements.
type Products []*ProductID
// FileHashValue represents the value of a hash.
type FileHashValue string
var fileHashValuePattern = patternUnmarshal(`^[0-9a-fA-F]{32,}$`)
// FileHash is checksum hash.
// Values for 'algorithm' are derived from the currently supported digests OpenSSL. Leading dashes were removed.
type FileHash struct {
Algorithm *string `json:"algorithm"` // required, default: sha256
Value *FileHashValue `json:"value"` // required
}
// Hashes is a list of hashes.
type Hashes struct {
FileHashes []*FileHash `json:"file_hashes"` // required
FileName *string `json:"filename"` // required
}
// CPE represents a Common Platform Enumeration in an advisory.
type CPE string
var cpePattern = patternUnmarshal("^(cpe:2\\.3:[aho\\*\\-](:(((\\?*|\\*?)([a-zA-Z0-9\\-\\._]|(\\\\[\\\\\\*\\?!\"#\\$%&'\\(\\)\\+,/:;<=>@\\[\\]\\^`\\{\\|\\}~]))+(\\?*|\\*?))|[\\*\\-])){5}(:(([a-zA-Z]{2,3}(-([a-zA-Z]{2}|[0-9]{3}))?)|[\\*\\-]))(:(((\\?*|\\*?)([a-zA-Z0-9\\-\\._]|(\\\\[\\\\\\*\\?!\"#\\$%&'\\(\\)\\+,/:;<=>@\\[\\]\\^`\\{\\|\\}~]))+(\\?*|\\*?))|[\\*\\-])){4})|([c][pP][eE]:/[AHOaho]?(:[A-Za-z0-9\\._\\-~%]*){0,6})$")
// PURL represents a package URL in an advisory.
type PURL string
var pURLPattern = patternUnmarshal(`^pkg:[A-Za-z\\.\\-\\+][A-Za-z0-9\\.\\-\\+]*/.+`)
// XGenericURI represents an identifier for a product.
type XGenericURI struct {
Namespace *string `json:"namespace"` // required
URI *string `json:"uri"` // required
}
// XGenericURIs is a list of XGenericURI.
type XGenericURIs []*XGenericURI
// ProductIdentificationHelper bundles product identifier information.
// Supported formats for SBOMs are SPDX, CycloneDX, and SWID
type ProductIdentificationHelper struct {
CPE *CPE `json:"cpe,omitempty"`
Hashes *Hashes `json:"hashes,omitempty"`
ModelNumbers []*string `json:"model_numbers,omitempty"` // unique elements
PURL *PURL `json:"purl,omitempty"`
SBOMURLs []*string `json:"sbom_urls,omitempty"`
SerialNumbers []*string `json:"serial_numbers,omitempty"` // unique elements
SKUs []*string `json:"skus,omitempty"`
XGenericURIs XGenericURIs `json:"x_generic_uris,omitempty"`
}
// FullProductName is the full name of a product.
type FullProductName struct {
Name *string `json:"name"` // required
ProductID *ProductID `json:"product_id"` // required
ProductIdentificationHelper *ProductIdentificationHelper `json:"product_identification_helper,omitempty"`
}
// FullProductNames is a list of FullProductName.
type FullProductNames []*FullProductName
// Branch reflects the 'branch' object in the list of branches.
// It may contain either the property Branches OR Product.
// If the category is 'product_version' the name MUST NOT contain
// version ranges of any kind.
// If the category is 'product_version_range' the name MUST contain
// version ranges.
type Branch struct {
Branches Branches `json:"branches,omitempty"`
Category *BranchCategory `json:"category"` // required
Name *string `json:"name"` // required
Product *FullProductName `json:"product,omitempty"`
}
// NoteCategory is the category of a note.
type NoteCategory string
const (
// CSAFNoteCategoryDescription is the "description" category.
CSAFNoteCategoryDescription NoteCategory = "description"
// CSAFNoteCategoryDetails is the "details" category.
CSAFNoteCategoryDetails NoteCategory = "details"
// CSAFNoteCategoryFaq is the "faq" category.
CSAFNoteCategoryFaq NoteCategory = "faq"
// CSAFNoteCategoryGeneral is the "general" category.
CSAFNoteCategoryGeneral NoteCategory = "general"
// CSAFNoteCategoryLegalDisclaimer is the "legal_disclaimer" category.
CSAFNoteCategoryLegalDisclaimer NoteCategory = "legal_disclaimer"
// CSAFNoteCategoryOther is the "other" category.
CSAFNoteCategoryOther NoteCategory = "other"
// CSAFNoteCategorySummary is the "summary" category.
CSAFNoteCategorySummary NoteCategory = "summary"
)
var csafNoteCategoryPattern = alternativesUnmarshal(
string(CSAFNoteCategoryDescription),
string(CSAFNoteCategoryDetails),
string(CSAFNoteCategoryFaq),
string(CSAFNoteCategoryGeneral),
string(CSAFNoteCategoryLegalDisclaimer),
string(CSAFNoteCategoryOther),
string(CSAFNoteCategorySummary))
// Note reflects the 'Note' object of an advisory.
type Note struct {
Audience *string `json:"audience,omitempty"`
NoteCategory *NoteCategory `json:"category"` // required
Text *string `json:"text"` // required
Title *string `json:"title,omitempty"`
}
// ReferenceCategory is the category of a note.
type ReferenceCategory string
const (
// CSAFReferenceCategoryExternal is the "external" category.
CSAFReferenceCategoryExternal ReferenceCategory = "external"
// CSAFReferenceCategorySelf is the "self" category.
CSAFReferenceCategorySelf ReferenceCategory = "self"
)
var csafReferenceCategoryPattern = alternativesUnmarshal(
string(CSAFReferenceCategoryExternal),
string(CSAFReferenceCategorySelf))
// Reference holding any reference to conferences, papers, advisories, and other
// resources that are related and considered related to either a surrounding part of
// or the entire document and to be of value to the document consumer.
type Reference struct {
ReferenceCategory *string `json:"category"` // optional, default: external
Summary *string `json:"summary"` // required
URL *string `json:"url"` // required
}
// AggregateSeverity stands for the urgency with which the vulnerabilities of an advisory
// (not a specific one) should be addressed.
type AggregateSeverity struct {
Namespace *string `json:"namespace,omitempty"`
Text *string `json:"text"` // required
}
// DocumentCategory represents a category of a document.
type DocumentCategory string
var documentCategoryPattern = patternUnmarshal(`^[^\\s\\-_\\.](.*[^\\s\\-_\\.])?$`)
// Version is the version of a document.
type Version string
// CSAFVersion20 is the current version of CSAF.
const CSAFVersion20 Version = "2.0"
var csafVersionPattern = alternativesUnmarshal(string(CSAFVersion20))
// TLP provides details about the TLP classification of the document.
type TLP struct {
DocumentTLPLabel *TLPLabel `json:"label"` // required
URL *string `json:"url,omitempty"`
}
// DocumentDistribution describes rules for sharing a document.
type DocumentDistribution struct {
Text *string `json:"text,omitempty"`
TLP *TLP `json:"tlp,omitempty"`
}
// DocumentPublisher provides information about the publishing entity.
type DocumentPublisher struct {
Category *Category `json:"category"` // required
ContactDetails *string `json:"contact_details,omitempty"`
IssuingAuthority *string `json:"issuing_authority,omitempty"`
Name *string `json:"name"` // required
Namespace *string `json:"namespace"` // required
}
// RevisionNumber specifies a version string to denote clearly the evolution of the content of the document.
type RevisionNumber string
var versionPattern = patternUnmarshal("^(0|[1-9][0-9]*)$|^((0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?)$")
// Engine contains information about the engine that generated the CSAF document.
type Engine struct {
Name *string `json:"name"` // required
Version *string `json:"version,omitempty"`
}
// Generator holds elements related to the generation of the document.
// These items will reference when the document was actually created,
// including the date it was generated and the entity that generated it.
type Generator struct {
Date *string `json:"date,omitempty"`
Engine *Engine `json:"engine"` // required
}
// TrackingID is a unique identifier for the document.
type TrackingID string
var trackingIDPattern = patternUnmarshal("^[\\S](.*[\\S])?$")
// Revision contains information about one revision of the document.
type Revision struct {
Date *string `json:"date"` // required
LegacyVersion *string `json:"legacy_version,omitempty"`
Number *RevisionNumber `json:"number"` // required
Summary *string `json:"summary"` // required
}
// TrackingStatus is the category of a publisher.
type TrackingStatus string
const (
// CSAFTrackingStatusDraft is the "draft" category.
CSAFTrackingStatusDraft TrackingStatus = "draft"
// CSAFTrackingStatusFinal is the "final" category.
CSAFTrackingStatusFinal TrackingStatus = "final"
// CSAFTrackingStatusInterim is the "interim" category.
CSAFTrackingStatusInterim TrackingStatus = "interim"
)
var csafTrackingStatusPattern = alternativesUnmarshal(
string(CSAFTrackingStatusDraft),
string(CSAFTrackingStatusFinal),
string(CSAFTrackingStatusInterim))
// Revisions is a list of Revision.
type Revisions []*Revision
// Tracking holds information that is necessary to track a CSAF document.
type Tracking struct {
Aliases []*string `json:"aliases,omitempty"` // unique elements
CurrentReleaseDate *string `json:"current_release_date"` // required
Generator *Generator `json:"generator"`
ID *TrackingID `json:"id"` // required
InitialReleaseDate *string `json:"initial_release_date"` // required
RevisionHistory Revisions `json:"revision_history"` // required
Status *TrackingStatus `json:"status"` // required
Version *RevisionNumber `json:"version"` // required
}
// Lang is a language identifier, corresponding to IETF BCP 47 / RFC 5646.
type Lang string
var langPattern = patternUnmarshal("^(([A-Za-z]{2,3}(-[A-Za-z]{3}(-[A-Za-z]{3}){0,2})?|[A-Za-z]{4,8})(-[A-Za-z]{4})?(-([A-Za-z]{2}|[0-9]{3}))?(-([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-[A-WY-Za-wy-z0-9](-[A-Za-z0-9]{2,8})+)*(-[Xx](-[A-Za-z0-9]{1,8})+)?|[Xx](-[A-Za-z0-9]{1,8})+|[Ii]-[Dd][Ee][Ff][Aa][Uu][Ll][Tt]|[Ii]-[Mm][Ii][Nn][Gg][Oo])$")
// Document contains meta-data about an advisory.
type Document struct {
Acknowledgements *Acknowledgements `json:"acknowledgements,omitempty"`
AggregateSeverity *AggregateSeverity `json:"aggregate_severity,omitempty"`
Category *DocumentCategory `json:"category"` // required
CSAFVersion *Version `json:"csaf_version"` // required
Distribution *DocumentDistribution `json:"distribution,omitempty"`
Lang *Lang `json:"lang,omitempty"`
Notes Notes `json:"notes,omitempty"`
Publisher *DocumentPublisher `json:"publisher"` // required
References References `json:"references,omitempty"`
SourceLang *Lang `json:"source_lang,omitempty"`
Title *string `json:"title"` // required
Tracking *Tracking `json:"tracking"` // required
}
// ProductGroupID is a reference token for product group instances.
type ProductGroupID string
// ProductGroup is a group of products in the document that belong to one group.
type ProductGroup struct {
GroupID *string `json:"group_id"` // required
ProductIDs *Products `json:"product_ids"` // required, two or more unique elements
Summary *string `json:"summary,omitempty"`
}
// ProductGroups is a list of ProductGroupIDs
type ProductGroups struct {
ProductGroupIDs []*ProductGroupID `json:"product_group_ids"` // unique elements
}
// RelationshipCategory is the category of a relationship.
type RelationshipCategory string
const (
// CSAFRelationshipCategoryDefaultComponentOf is the "default_component_of" category.
CSAFRelationshipCategoryDefaultComponentOf RelationshipCategory = "default_component_of"
// CSAFRelationshipCategoryExternalComponentOf is the "external_component_of" category.
CSAFRelationshipCategoryExternalComponentOf RelationshipCategory = "external_component_of"
// CSAFRelationshipCategoryInstalledOn is the "installed_on" category.
CSAFRelationshipCategoryInstalledOn RelationshipCategory = "installed_on"
// CSAFRelationshipCategoryInstalledWith is the "installed_with" category.
CSAFRelationshipCategoryInstalledWith RelationshipCategory = "installed_with"
// CSAFRelationshipCategoryOptionalComponentOf is the "optional_component_of" category.
CSAFRelationshipCategoryOptionalComponentOf RelationshipCategory = "optional_component_of"
)
var csafRelationshipCategoryPattern = alternativesUnmarshal(
string(CSAFRelationshipCategoryDefaultComponentOf),
string(CSAFRelationshipCategoryExternalComponentOf),
string(CSAFRelationshipCategoryInstalledOn),
string(CSAFRelationshipCategoryInstalledWith),
string(CSAFRelationshipCategoryOptionalComponentOf))
// Relationship establishes a link between two existing FullProductName elements.
type Relationship struct {
Category *RelationshipCategory `json:"category"` // required
FullProductName *FullProductName `json:"full_product_name"` // required
ProductReference *ProductID `json:"product_reference"` // required
RelatesToProductReference *ProductID `json:"relates_to_product_reference"` // required
}
// Relationships is a list of Relationship.
type Relationships []*Relationship
// Branches is a list of Branch.
type Branches []*Branch
// ProductTree contains product names that can be referenced elsewhere in the document.
type ProductTree struct {
Branches Branches `json:"branches,omitempty"`
FullProductNames *FullProductNames `json:"full_product_names,omitempty"`
ProductGroups *ProductGroups `json:"product_groups,omitempty"`
RelationShips *Relationships `json:"relationships,omitempty"`
}
// CVE holds the MITRE standard Common Vulnerabilities and Exposures (CVE) tracking number for a vulnerability.
type CVE string
var cvePattern = patternUnmarshal("^CVE-[0-9]{4}-[0-9]{4,}$")
// WeaknessID is the identifier of a weakness.
type WeaknessID string
var weaknessIDPattern = patternUnmarshal("^CWE-[1-9]\\d{0,5}$")
// CWE holds the MITRE standard Common Weakness Enumeration (CWE) for the weakness associated.
type CWE struct {
ID *WeaknessID `json:"id"` // required
Name *string `json:"name"` // required
}
// FlagLabel is the label of a flag for a vulnerability.
type FlagLabel string
const (
// CSAFFlagLabelComponentNotPresent is the "component_not_present" label.
CSAFFlagLabelComponentNotPresent FlagLabel = "component_not_present"
// CSAFFlagLabelInlineMitigationsAlreadyExist is the "inline_mitigations_already_exist" label.
CSAFFlagLabelInlineMitigationsAlreadyExist FlagLabel = "inline_mitigations_already_exist"
// CSAFFlagLabelVulnerableCodeCannotBeControlledByAdversary is the "vulnerable_code_cannot_be_controlled_by_adversary" label.
CSAFFlagLabelVulnerableCodeCannotBeControlledByAdversary FlagLabel = "vulnerable_code_cannot_be_controlled_by_adversary"
// CSAFFlagLabelVulnerableCodeNotInExecutePath is the "vulnerable_code_not_in_execute_path" label.
CSAFFlagLabelVulnerableCodeNotInExecutePath FlagLabel = "vulnerable_code_not_in_execute_path"
// CSAFFlagLabelVulnerableCodeNotPresent is the "vulnerable_code_not_present" label.
CSAFFlagLabelVulnerableCodeNotPresent FlagLabel = "vulnerable_code_not_present"
)
var csafFlagLabelPattern = alternativesUnmarshal(
string(CSAFFlagLabelComponentNotPresent),
string(CSAFFlagLabelInlineMitigationsAlreadyExist),
string(CSAFFlagLabelVulnerableCodeCannotBeControlledByAdversary),
string(CSAFFlagLabelVulnerableCodeNotInExecutePath),
string(CSAFFlagLabelVulnerableCodeNotPresent))
// Flag contains product specific information in regard to this vulnerability as a single
// machine readable flag. For example, this could be a machine readable justification
// code why a product is not affected.
type Flag struct {
Date *string `json:"date,omitempty"`
GroupIDs *ProductGroups `json:"group_ids,omitempty"`
Label *FlagLabel `json:"label"` // required
ProductIds *Products `json:"product_ids,omitempty"`
}
// Flags is a list if Flag elements.
type Flags []*Flag
// VulnerabilityID is the identifier of a vulnerability.
type VulnerabilityID struct {
SystemName *string `json:"system_name"` // required
Text *string `json:"text"` // required
}
// VulnerabilityIDs is a list of VulnerabilityID elements.
type VulnerabilityIDs []*VulnerabilityID
// InvolvementParty is the party of an involvement.
type InvolvementParty string
const (
// CSAFInvolvementPartyCoordinator is the "coordinator" party.
CSAFInvolvementPartyCoordinator InvolvementParty = "coordinator"
// CSAFInvolvementPartyDiscoverer is the "discoverer" party.
CSAFInvolvementPartyDiscoverer InvolvementParty = "discoverer"
// CSAFInvolvementPartyOther is the "other" party.
CSAFInvolvementPartyOther InvolvementParty = "other"
// CSAFInvolvementPartyUser is the "user" party.
CSAFInvolvementPartyUser InvolvementParty = "user"
// CSAFInvolvementPartyVendor is the "vendor" party.
CSAFInvolvementPartyVendor InvolvementParty = "vendor"
)
var csafInvolvementPartyPattern = alternativesUnmarshal(
string(CSAFInvolvementPartyCoordinator),
string(CSAFInvolvementPartyDiscoverer),
string(CSAFInvolvementPartyOther),
string(CSAFInvolvementPartyUser),
string(CSAFInvolvementPartyVendor))
// InvolvementStatus is the status of an involvement.
type InvolvementStatus string
const (
// CSAFInvolvementStatusCompleted is the "completed" status.
CSAFInvolvementStatusCompleted InvolvementStatus = "completed"
// CSAFInvolvementStatusContactAttempted is the "contact_attempted" status.
CSAFInvolvementStatusContactAttempted InvolvementStatus = "contact_attempted"
// CSAFInvolvementStatusDisputed is the "disputed" status.
CSAFInvolvementStatusDisputed InvolvementStatus = "disputed"
// CSAFInvolvementStatusInProgress is the "in_progress" status.
CSAFInvolvementStatusInProgress InvolvementStatus = "in_progress"
// CSAFInvolvementStatusNotContacted is the "not_contacted" status.
CSAFInvolvementStatusNotContacted InvolvementStatus = "not_contacted"
// CSAFInvolvementStatusOpen is the "open" status.
CSAFInvolvementStatusOpen InvolvementStatus = "open"
)
var csafInvolvementStatusPattern = alternativesUnmarshal(
string(CSAFInvolvementStatusCompleted),
string(CSAFInvolvementStatusContactAttempted),
string(CSAFInvolvementStatusDisputed),
string(CSAFInvolvementStatusInProgress),
string(CSAFInvolvementStatusNotContacted),
string(CSAFInvolvementStatusOpen))
// Involvement is a container that allows the document producers to comment on the level of involvement
// (or engagement) of themselves (or third parties) in the vulnerability identification, scoping, and
// remediation process. It can also be used to convey the disclosure timeline.
// The ordered tuple of the values of party and date (if present) SHALL be unique within the involvements
// of a vulnerability.
type Involvement struct {
Date *string `json:"date,omitempty"`
Party *InvolvementParty `json:"party"` // required
Status *InvolvementStatus `json:"status"` // required
Summary *string `json:"summary,omitempty"`
}
// Involvements is a list of Involvement elements.
type Involvements []*Involvement
// ProductStatus contains different lists of ProductIDs which provide details on
// the status of the referenced product related to the current vulnerability.
type ProductStatus struct {
FirstAffected *Products `json:"first_affected,omitempty"`
FirstFixed *Products `json:"first_fixed,omitempty"`
Fixed *Products `json:"fixed,omitempty"`
KnownAffected *Products `json:"known_affected,omitempty"`
KnownNotAffected *Products `json:"known_not_affected,omitempty"`
LastAffected *Products `json:"last_affected,omitempty"`
Recommended *Products `json:"recommended,omitempty"`
UnderInvestigation *Products `json:"under_investigation,omitempty"`
}
// RemediationCategory is the category of a remediation.
type RemediationCategory string
const (
// CSAFRemediationCategoryMitigation is the "mitigation" category.
CSAFRemediationCategoryMitigation RemediationCategory = "mitigation"
// CSAFRemediationCategoryNoFixPlanned is the "no_fix_planned" category.
CSAFRemediationCategoryNoFixPlanned RemediationCategory = "no_fix_planned"
// CSAFRemediationCategoryNoneAvailable is the "none_available" category.
CSAFRemediationCategoryNoneAvailable RemediationCategory = "none_available"
// CSAFRemediationCategoryVendorFix is the "vendor_fix" category.
CSAFRemediationCategoryVendorFix RemediationCategory = "vendor_fix"
// CSAFRemediationCategoryWorkaround is the "workaround" category.
CSAFRemediationCategoryWorkaround RemediationCategory = "workaround"
)
var csafRemediationCategoryPattern = alternativesUnmarshal(
string(CSAFRemediationCategoryMitigation),
string(CSAFRemediationCategoryNoFixPlanned),
string(CSAFRemediationCategoryNoneAvailable),
string(CSAFRemediationCategoryVendorFix),
string(CSAFRemediationCategoryWorkaround))
// RestartRequiredCategory is the category of RestartRequired.
type RestartRequiredCategory string
const (
// CSAFRestartRequiredCategoryConnected is the "connected" category.
CSAFRestartRequiredCategoryConnected RestartRequiredCategory = "connected"
// CSAFRestartRequiredCategoryDependencies is the "dependencies" category.
CSAFRestartRequiredCategoryDependencies RestartRequiredCategory = "dependencies"
// CSAFRestartRequiredCategoryMachine is the "machine" category.
CSAFRestartRequiredCategoryMachine RestartRequiredCategory = "machine"
// CSAFRestartRequiredCategoryNone is the "none" category.
CSAFRestartRequiredCategoryNone RestartRequiredCategory = "none"
// CSAFRestartRequiredCategoryParent is the "parent" category.
CSAFRestartRequiredCategoryParent RestartRequiredCategory = "parent"
// CSAFRestartRequiredCategoryService is the "service" category.
CSAFRestartRequiredCategoryService RestartRequiredCategory = "service"
// CSAFRestartRequiredCategorySystem is the "system" category.
CSAFRestartRequiredCategorySystem RestartRequiredCategory = "system"
// CSAFRestartRequiredCategoryVulnerableComponent is the "vulnerable_component" category.
CSAFRestartRequiredCategoryVulnerableComponent RestartRequiredCategory = "vulnerable_component"
// CSAFRestartRequiredCategoryZone is the "zone" category.
CSAFRestartRequiredCategoryZone RestartRequiredCategory = "zone"
)
var csafRestartRequiredCategoryPattern = alternativesUnmarshal(
string(CSAFRestartRequiredCategoryConnected),
string(CSAFRestartRequiredCategoryDependencies),
string(CSAFRestartRequiredCategoryMachine),
string(CSAFRestartRequiredCategoryNone),
string(CSAFRestartRequiredCategoryParent),
string(CSAFRestartRequiredCategoryService),
string(CSAFRestartRequiredCategorySystem),
string(CSAFRestartRequiredCategoryVulnerableComponent),
string(CSAFRestartRequiredCategoryZone))
// RestartRequired provides information on category of restart is required by this remediation to become
// effective.
type RestartRequired struct {
Category *RestartRequiredCategory `json:"category"` // required
Details *string `json:"details,omitempty"`
}
// Remediation specifies details on how to handle (and presumably, fix) a vulnerability.
type Remediation struct {
Category *RemediationCategory `json:"category"` // required
Date *string `json:"date,omitempty"`
Details *string `json:"details"` // required
Entitlements []*string `json:"entitlements,omitempty"`
GroupIds *ProductGroups `json:"group_ids,omitempty"`
ProductIds *Products `json:"product_ids,omitempty"`
RestartRequired *RestartRequired `json:"restart_required,omitempty"`
URL *string `json:"url,omitempty"`
}
// Remediations is a list of Remediation elements.
type Remediations []*Remediation
// CVSSVersion2 is the version of a CVSS2 item.
type CVSSVersion2 string
// CVSSVersion20 is the current version of the schema.
const CVSSVersion20 CVSSVersion2 = "2.0"
var cvssVersion2Pattern = alternativesUnmarshal(string(CVSSVersion20))
// CVSS2VectorString is the VectorString of a CVSS2 item with version 3.x.
type CVSS2VectorString string
var cvss2VectorStringPattern = patternUnmarshal(`^((AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))/)*(AV:[NAL]|AC:[LMH]|Au:[MSN]|[CIA]:[NPC]|E:(U|POC|F|H|ND)|RL:(OF|TF|W|U|ND)|RC:(UC|UR|C|ND)|CDP:(N|L|LM|MH|H|ND)|TD:(N|L|M|H|ND)|[CIA]R:(L|M|H|ND))$`)
// CVSSVersion3 is the version of a CVSS3 item.
type CVSSVersion3 string
// CVSSVersion30 is version 3.0 of a CVSS3 item.
const CVSSVersion30 CVSSVersion3 = "3.0"
// CVSSVersion31 is version 3.1 of a CVSS3 item.
const CVSSVersion31 CVSSVersion3 = "3.1"
var cvss3VersionPattern = alternativesUnmarshal(
string(CVSSVersion30),
string(CVSSVersion31))
// CVSS3VectorString is the VectorString of a CVSS3 item with version 3.x.
type CVSS3VectorString string
// cvss3VectorStringPattern is a combination of the vectorString patterns of CVSS 3.0
// and CVSS 3.1 since the only difference is the number directly after the first dot.
var cvss3VectorStringPattern = patternUnmarshal(`^CVSS:3[.][01]/((AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])/)*(AV:[NALP]|AC:[LH]|PR:[NLH]|UI:[NR]|S:[UC]|[CIA]:[NLH]|E:[XUPFH]|RL:[XOTWU]|RC:[XURC]|[CIA]R:[XLMH]|MAV:[XNALP]|MAC:[XLH]|MPR:[XNLH]|MUI:[XNR]|MS:[XUC]|M[CIA]:[XNLH])$`)
// CVSS2 holding a CVSS v2.0 value
type CVSS2 struct {
Version *CVSSVersion2 `json:"version"` // required
VectorString *CVSS2VectorString `json:"vectorString"` // required
AccessVector *CVSS20AccessVector `json:"accessVector,omitempty"`
AccessComplexity *CVSS20AccessComplexity `json:"accessComplexity,omitempty"`
Authentication *CVSS20Authentication `json:"authentication,omitempty"`
ConfidentialityImpact *CVSS20Cia `json:"confidentialityImpact,omitempty"`
IntegrityImpact *CVSS20Cia `json:"integrityImpact,omitempty"`
AvailabilityImpact *CVSS20Cia `json:"availabilityImpact,omitempty"`
BaseScore *float64 `json:"baseScore"` // required
Exploitability *CVSS20Exploitability `json:"exploitability,omitempty"`
RemediationLevel *CVSS20RemediationLevel `json:"remediationLevel,omitempty"`
ReportConfidence *CVSS20ReportConfidence `json:"reportConfidence,omitempty"`
TemporalScore *float64 `json:"temporalScore,omitempty"`
CollateralDamagePotential *CVSS20CollateralDamagePotential `json:"collateralDamagePotential,omitempty"`
TargetDistribution *CVSS20TargetDistribution `json:"targetDistribution,omitempty"`
ConfidentialityRequirement *CVSS20CiaRequirement `json:"confidentialityRequirement,omitempty"`
IntegrityRequirement *CVSS20CiaRequirement `json:"integrityRequirement,omitempty"`
AvailabilityRequirement *CVSS20CiaRequirement `json:"availabilityRequirement,omitempty"`
EnvironmentalScore *float64 `json:"environmentalScore,omitempty"`
}
// CVSS3 holding a CVSS v3.x value
type CVSS3 struct {
Version *CVSSVersion3 `json:"version"` // required
VectorString *CVSS3VectorString `json:"vectorString"` // required
AttackVector *CVSS3AttackVector `json:"attackVector,omitempty"`
AttackComplexity *CVSS3AttackComplexity `json:"attackComplexity,omitempty"`
PrivilegesRequired *CVSS3PrivilegesRequired `json:"privilegesRequired,omitempty"`
UserInteraction *CVSS3UserInteraction `json:"userInteraction,omitempty"`
Scope *CVSS3Scope `json:"scope,omitempty"`
ConfidentialityImpact *CVSS3Cia `json:"confidentialityImpact,omitempty"`
IntegrityImpact CVSS3Cia `json:"integrityImpact,omitempty"`
AvailabilityImpact *CVSS3Cia `json:"availabilityImpact,omitempty"`
BaseScore *float64 `json:"baseScore"` // required
BaseSeverity *CVSS3Severity `json:"baseSeverity"` // required
ExploitCodeMaturity *CVSS3ExploitCodeMaturity `json:"exploitCodeMaturity,omitempty"`
RemediationLevel *CVSS3RemediationLevel `json:"remediationLevel,omitempty"`
ReportConfidence *CVSS3Confidence `json:"reportConfidence,omitempty"`
TemporalScore *float64 `json:"temporalScore,omitempty"`
TemporalSeverity *CVSS3Severity `json:"temporalSeverity,omitempty"`
ConfidentialityRequirement *CVSS3CiaRequirement `json:"confidentialityRequirement,omitempty"`
IntegrityRequirement *CVSS3CiaRequirement `json:"integrityRequirement,omitempty"`
AvailabilityRequirement *CVSS3CiaRequirement `json:"availabilityRequirement,omitempty"`
ModifiedAttackVector *CVSS3ModifiedAttackVector `json:"modifiedAttackVector,omitempty"`
ModifiedAttackComplexity *CVSS3ModifiedAttackComplexity `json:"modifiedAttackComplexity,omitempty"`
ModifiedPrivilegesRequired *CVSS3ModifiedPrivilegesRequired `json:"modifiedPrivilegesRequired,omitempty"`
ModifiedUserInteraction *CVSS3ModifiedUserInteraction `json:"modifiedUserInteraction,omitempty"`
ModifiedScope *CVSS3ModifiedScope `json:"modifiedScope,omitempty"`
ModifiedConfidentialityImpact *CVSS3ModifiedCia `json:"modifiedConfidentialityImpact,omitempty"`
ModifiedIntegrityImpact *CVSS3ModifiedCia `json:"modifiedIntegrityImpact,omitempty"`
ModifiedAvailabilityImpact *CVSS3ModifiedCia `json:"modifiedAvailabilityImpact,omitempty"`
EenvironmentalScore *float64 `json:"environmentalScore,omitempty"`
EnvironmentalSeverity *CVSS3Severity `json:"environmentalSeverity,omitempty"`
}
// Score specifies information about (at least one) score of the vulnerability and for which
// products the given value applies. A Score item has at least 2 properties.
type Score struct {
CVSS2 *CVSS2 `json:"cvss_v2,omitempty"`
CVSS3 *CVSS3 `json:"cvss_v3,omitempty"`
Products *Products `json:"products"` // required
}
// Scores is a list of Score elements.
type Scores []*Score
// ThreatCategory is the category of a threat.
type ThreatCategory string
const (
// CSAFThreatCategoryExploitStatus is the "exploit_status" category.
CSAFThreatCategoryExploitStatus ThreatCategory = "exploit_status"
// CSAFThreatCategoryImpact is the "impact" category.
CSAFThreatCategoryImpact ThreatCategory = "impact"
// CSAFThreatCategoryTargetSet is the "target_set" category.
CSAFThreatCategoryTargetSet ThreatCategory = "target_set"
)
var csafThreatCategoryPattern = alternativesUnmarshal(
string(CSAFThreatCategoryExploitStatus),
string(CSAFThreatCategoryImpact),
string(CSAFThreatCategoryTargetSet))
// Threat contains information about a vulnerability that can change with time.
type Threat struct {
Category *ThreatCategory `json:"category"` // required
Date *string `json:"date,omitempty"`
Details *string `json:"details"` // required
GroupIds *ProductGroups `json:"group_ids,omitempty"`
ProductIds *Products `json:"product_ids,omitempty"`
}
// Threats is a list of Threat elements.
type Threats []*Threat
// Notes is a list of Note.
type Notes []*Note
// References is a list of Reference.
type References []*Reference
// Vulnerability contains all fields that are related to a single vulnerability in the document.
type Vulnerability struct {
Acknowledgements Acknowledgements `json:"acknowledgements,omitempty"`
CVE *CVE `json:"cve,omitempty"`
CWE *CWE `json:"cwe,omitempty"`
DiscoveryDate *string `json:"discovery_date,omitempty"`
Flags Flags `json:"flags,omitempty"`
IDs VulnerabilityIDs `json:"ids,omitempty"` // unique ID elements
Involvements Involvements `json:"involvements,omitempty"`
Notes Notes `json:"notes,omitempty"`
ProductStatus *ProductStatus `json:"product_status,omitempty"`
References References `json:"references,omitempty"`
ReleaseDate *string `json:"release_date,omitempty"`
Remediations Remediations `json:"remediations,omitempty"`
Scores Scores `json:"scores,omitempty"`
Threats Threats `json:"threats,omitempty"`
Title *string `json:"title,omitempty"`
}
// Vulnerabilities is a list of Vulnerability
type Vulnerabilities []*Vulnerability
// Advisory represents a CSAF advisory.
type Advisory struct {
Document *Document `json:"document"` // required
ProductTree *ProductTree `json:"product_tree,omitempty"`
Vulnerabilities Vulnerabilities `json:"vulnerabilities,omitempty"`
}
// Validate validates a AggregateSeverity.
func (as *AggregateSeverity) Validate() error {
if as.Text == nil {
return errors.New("'text' is missing")
}
return nil
}
// Validate validates a DocumentDistribution.
func (dd *DocumentDistribution) Validate() error {
if dd.Text == nil && dd.TLP == nil {
return errors.New("needs at least properties 'text' or 'tlp'")
}
return nil
}
// Validate validates a list of notes.
func (ns Notes) Validate() error {
for i, n := range ns {
if err := n.Validate(); err != nil {
return fmt.Errorf("%d. note is invalid: %w", i+1, err)
}
}
return nil
}
// Validate validates a single note.
func (n *Note) Validate() error {
switch {
case n == nil:
return errors.New("is nil")
case n.NoteCategory == nil:
return errors.New("'note_category' is missing")
case n.Text == nil:
return errors.New("'text' is missing")
default:
return nil
}
}
// Validate validates a DocumentPublisher.
func (p *DocumentPublisher) Validate() error {
switch {
case p.Category == nil:
return errors.New("'document' is missing")
case p.Name == nil:
return errors.New("'name' is missing")
case p.Namespace == nil:
return errors.New("'namespace' is missing")
default:
return nil
}
}
// Validate validates a single reference.
func (r *Reference) Validate() error {
switch {
case r.Summary == nil:
return errors.New("summary' is missing")
case r.URL == nil:
return errors.New("'url' is missing")
default:
return nil
}
}
// Validate validates a list of references.
func (rs References) Validate() error {
for i, r := range rs {
if err := r.Validate(); err != nil {
return fmt.Errorf("%d. reference is invalid: %w", i+1, err)
}
}
return nil
}
// Validate validates a single revision.
func (r *Revision) Validate() error {
switch {
case r.Date == nil:
return errors.New("'date' is missing")
case r.Number == nil:
return errors.New("'number' is missing")
case r.Summary == nil:
return errors.New("'summary' is missing")
default:
return nil
}
}
// Validate validates a list of revisions.
func (rs Revisions) Validate() error {
for i, r := range rs {
if err := r.Validate(); err != nil {
return fmt.Errorf("%d. revision is invalid: %w", i+1, err)
}
}
return nil
}
// Validate validates an Engine.
func (e *Engine) Validate() error {
if e.Version == nil {
return errors.New("'version' is missing")
}
return nil
}
// Validate validates a Generator.
func (g *Generator) Validate() error {
if g.Engine == nil {
return errors.New("'engine' is missing")
}
if err := g.Engine.Validate(); err != nil {
return fmt.Errorf("'engine' is invalid: %w", err)
}
return nil
}
// Validate validates a single Tracking.
func (t *Tracking) Validate() error {
switch {
case t.CurrentReleaseDate == nil:
return errors.New("'current_release_date' is missing")
case t.ID == nil:
return errors.New("'id' is missing")
case t.InitialReleaseDate == nil:
return errors.New("'initial_release_date' is missing")
case t.RevisionHistory == nil:
return errors.New("'revision_history' is missing")
case t.Status == nil:
return errors.New("'status' is missing")
case t.Version == nil:
return errors.New("'version' is missing")
}
if err := t.RevisionHistory.Validate(); err != nil {
return fmt.Errorf("'revision_history' is invalid: %w", err)
}
if t.Generator != nil {
if err := t.Generator.Validate(); err != nil {
return fmt.Errorf("'generator' is invalid: %w", err)
}
}
return nil
}
// Validate validates a Document.
func (doc *Document) Validate() error {
switch {
case doc.Category == nil:
return errors.New("'category' is missing")
case doc.CSAFVersion == nil:
return errors.New("'csaf_version' is missing")
case doc.Publisher == nil:
return errors.New("'publisher' is missing")
case doc.Title == nil:
return errors.New("'title' is missing")
case doc.Tracking == nil:
return errors.New("'tracking' is missing")
}
if err := doc.Tracking.Validate(); err != nil {
return fmt.Errorf("'tracking' is invalid: %w", err)
}
if doc.Distribution != nil {
if err := doc.Distribution.Validate(); err != nil {
return fmt.Errorf("'distribution' is invalid: %w", err)
}
}
if doc.AggregateSeverity != nil {
if err := doc.AggregateSeverity.Validate(); err != nil {
return fmt.Errorf("'aggregate_severity' is invalid: %w", err)
}
}
if err := doc.Publisher.Validate(); err != nil {
return fmt.Errorf("'publisher' is invalid: %w", err)
}
if err := doc.References.Validate(); err != nil {
return fmt.Errorf("'references' is invalid: %w", err)
}
if err := doc.Notes.Validate(); err != nil {
return fmt.Errorf("'notes' is invalid: %w", err)
}
return nil
}
// Validate validates a single FileHash.
func (fh *FileHash) Validate() error {
switch {
case fh == nil:
return errors.New("is nil")
case fh.Algorithm == nil:
return errors.New("'algorithm' is missing")
case fh.Value == nil:
return errors.New("'value' is missing")
default:
return nil
}
}
// Validate validates a list of file hashes.
func (hs *Hashes) Validate() error {
switch {
case hs.FileHashes == nil:
return errors.New("'hashes' is missing")
case hs.FileName == nil:
return errors.New("'filename' is missing")
}
for i, fh := range hs.FileHashes {
if err := fh.Validate(); err != nil {
return fmt.Errorf("%d. file hash is invalid: %w", i+1, err)
}
}
return nil
}