CVRF: 处理 vulnerabilities
Signed-off-by: Jia Chao <jiac13@chinaunicom.cn>
This commit is contained in:
parent
973e22c89e
commit
89c831a48b
201
src/lib.rs
201
src/lib.rs
|
@ -95,7 +95,7 @@ impl XmlReader {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
struct CVRF {
|
pub struct CVRF {
|
||||||
// <DocumentTitle xml:lang="en">
|
// <DocumentTitle xml:lang="en">
|
||||||
pub documenttitle: String,
|
pub documenttitle: String,
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ struct CVRF {
|
||||||
pub producttree: ProductTree,
|
pub producttree: ProductTree,
|
||||||
|
|
||||||
// <Vulnerability xmlns="http://www.icasi.org/CVRF/schema/vuln/1.1" Ordinal="1">
|
// <Vulnerability xmlns="http://www.icasi.org/CVRF/schema/vuln/1.1" Ordinal="1">
|
||||||
pub vulnerability: Vulnerability,
|
pub vulnerabilities: Vec<Vulnerability>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CVRF {
|
impl CVRF {
|
||||||
|
@ -133,7 +133,7 @@ impl CVRF {
|
||||||
documentnotes: vec![],
|
documentnotes: vec![],
|
||||||
documentreferences: vec![],
|
documentreferences: vec![],
|
||||||
producttree: ProductTree::new(),
|
producttree: ProductTree::new(),
|
||||||
vulnerability: Vulnerability::new(),
|
vulnerabilities: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,6 +163,7 @@ impl CVRF {
|
||||||
"DocumentNotes" => self.handle_notes(xmlreader),
|
"DocumentNotes" => self.handle_notes(xmlreader),
|
||||||
"DocumentReferences" => self.handle_references(xmlreader),
|
"DocumentReferences" => self.handle_references(xmlreader),
|
||||||
"ProductTree" => self.producttree.load_from_xmlreader(xmlreader),
|
"ProductTree" => self.producttree.load_from_xmlreader(xmlreader),
|
||||||
|
"Vulnerability" => self.handle_vulnerabilities(xmlreader),
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -199,6 +200,14 @@ impl CVRF {
|
||||||
self.documentreferences.push(reference);
|
self.documentreferences.push(reference);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_vulnerabilities(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
let mut vulnerability = Vulnerability::new();
|
||||||
|
vulnerability.load_from_xmlreader(xmlreader);
|
||||||
|
if vulnerability.cve != "" {
|
||||||
|
self.vulnerabilities.push(vulnerability);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// depth = 2
|
// depth = 2
|
||||||
|
@ -628,7 +637,6 @@ impl ProductTree {
|
||||||
_type.clear();
|
_type.clear();
|
||||||
_name.clear();
|
_name.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, xmlreader))]
|
#[instrument(skip(self, xmlreader))]
|
||||||
|
@ -756,6 +764,84 @@ impl Vulnerability {
|
||||||
remediations: Vec::new(),
|
remediations: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, xmlreader))]
|
||||||
|
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
let key = if let Some(key) = xmlreader.next_start_name_under_depth(1) {
|
||||||
|
key
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
match key.as_str() {
|
||||||
|
"Notes" => self.handle_notes(xmlreader),
|
||||||
|
"ReleaseDate" => self.releasedate = xmlreader.next_characters(),
|
||||||
|
"CVE" => self.cve = xmlreader.next_characters(),
|
||||||
|
"ProductStatuses" => self.handle_productstatuses(xmlreader),
|
||||||
|
"Threats" => self.handle_threats(xmlreader),
|
||||||
|
"CVSSScoreSets" => self.handle_cvssscoresets(xmlreader),
|
||||||
|
"Remediations" => self.handle_remediations(xmlreader),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_notes(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
let mut note = Note::new();
|
||||||
|
note.load_from_xmlreader(xmlreader);
|
||||||
|
|
||||||
|
if xmlreader.depth < 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.notes.push(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_productstatuses(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
let mut status = ProductStatus::new();
|
||||||
|
status.load_from_xmlreader(xmlreader);
|
||||||
|
if xmlreader.depth < 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.productstatuses.push(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_threats(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
let mut threat = Threat::new();
|
||||||
|
threat.load_from_xmlreader(xmlreader);
|
||||||
|
if xmlreader.depth < 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.threats.push(threat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_cvssscoresets(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
let mut scoreset = ScoreSet::new();
|
||||||
|
scoreset.load_from_xmlreader(xmlreader);
|
||||||
|
if xmlreader.depth < 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.cvssscoresets.push(scoreset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_remediations(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
let mut remediation = Remediation::new();
|
||||||
|
remediation.load_from_xmlreader(xmlreader);
|
||||||
|
if xmlreader.depth < 3 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
self.remediations.push(remediation);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// depth = 4
|
// depth = 4
|
||||||
|
@ -779,6 +865,30 @@ impl ProductStatus {
|
||||||
products: Vec::new(),
|
products: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, xmlreader))]
|
||||||
|
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
match xmlreader.next() {
|
||||||
|
Ok(XmlEvent::StartElement { attributes, .. }) => {
|
||||||
|
if xmlreader.depth == 4 {
|
||||||
|
self.status = attributes[0].value.clone();
|
||||||
|
}
|
||||||
|
self.products.push(xmlreader.next_characters());
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::EndElement { .. }) => {
|
||||||
|
if xmlreader.depth < 4 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("XmlReader Error: {e}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// depth = 4
|
// depth = 4
|
||||||
|
@ -801,6 +911,31 @@ impl Threat {
|
||||||
description: String::new(),
|
description: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, xmlreader))]
|
||||||
|
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
match xmlreader.next() {
|
||||||
|
Ok(XmlEvent::StartElement { attributes, .. }) => {
|
||||||
|
if xmlreader.depth == 4 {
|
||||||
|
self.r#type = attributes[0].value.clone();
|
||||||
|
} else {
|
||||||
|
self.description = xmlreader.next_characters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::EndElement { .. }) => {
|
||||||
|
if xmlreader.depth < 4 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("XmlReader Error: {e}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// depth = 4
|
// depth = 4
|
||||||
|
@ -824,6 +959,23 @@ impl ScoreSet {
|
||||||
vector: String::new(),
|
vector: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, xmlreader))]
|
||||||
|
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
loop {
|
||||||
|
let key = if let Some(key) = xmlreader.next_start_name_under_depth(3) {
|
||||||
|
key
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
match key.as_str() {
|
||||||
|
"BaseScore" => self.basescore = xmlreader.next_characters(),
|
||||||
|
"Vector" => self.vector = xmlreader.next_characters(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// depth = 4
|
// depth = 4
|
||||||
|
@ -858,4 +1010,45 @@ impl Remediation {
|
||||||
url: String::new(),
|
url: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(skip(self, xmlreader))]
|
||||||
|
fn load_from_xmlreader(&mut self, xmlreader: &mut XmlReader) {
|
||||||
|
// 读取类型
|
||||||
|
loop {
|
||||||
|
match xmlreader.next() {
|
||||||
|
Ok(XmlEvent::StartElement { attributes, .. }) => {
|
||||||
|
if xmlreader.depth == 4 {
|
||||||
|
self.r#type = attributes[0].value.clone();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::EndElement { .. }) => {
|
||||||
|
if xmlreader.depth < 4 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("XmlReader Error: {e}");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其它字段
|
||||||
|
loop {
|
||||||
|
let key = if let Some(key) = xmlreader.next_start_name_under_depth(3) {
|
||||||
|
key
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
match key.as_str() {
|
||||||
|
"Description" => self.description = xmlreader.next_characters(),
|
||||||
|
"DATE" => self.date = xmlreader.next_characters(),
|
||||||
|
"URL" => self.url = xmlreader.next_characters(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
48
src/test.rs
48
src/test.rs
|
@ -84,4 +84,52 @@ fn cvrf_works() {
|
||||||
cvrf.producttree.packages.get(producttree_src).unwrap()[2].content,
|
cvrf.producttree.packages.get(producttree_src).unwrap()[2].content,
|
||||||
producttree_src_content
|
producttree_src_content
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// vulnerabilities
|
||||||
|
let cvrf_vulner_releasedate = "2024-04-19";
|
||||||
|
let cvrf_vulner_cve = "CVE-2023-45288";
|
||||||
|
let cvrf_vulner_productstatues_status = "Fixed";
|
||||||
|
let cvrf_vulner_productstatues_product = "openEuler-22.03-LTS";
|
||||||
|
let cvrf_vulner_basescore = "7.5";
|
||||||
|
let cvrf_vulner_vector = "AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H";
|
||||||
|
let cvrf_vulner_remedition_type = "Vendor Fix";
|
||||||
|
let cvrf_vulner_remedition_descrition = "golang security update";
|
||||||
|
let cvrf_vulner_remedition_date = "2024-04-19";
|
||||||
|
let cvrf_vulner_remedition_url = "https://www.openeuler.org/en/security/safety-bulletin/detail.html?id=openEuler-SA-2024-1488";
|
||||||
|
|
||||||
|
assert_eq!(cvrf.vulnerabilities[0].notes.len(), 1);
|
||||||
|
assert_eq!(cvrf.vulnerabilities[0].releasedate, cvrf_vulner_releasedate);
|
||||||
|
assert_eq!(cvrf.vulnerabilities[0].cve, cvrf_vulner_cve);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].productstatuses[0].status,
|
||||||
|
cvrf_vulner_productstatues_status
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].productstatuses[0].products[2],
|
||||||
|
cvrf_vulner_productstatues_product
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].cvssscoresets[0].basescore,
|
||||||
|
cvrf_vulner_basescore
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].cvssscoresets[0].vector,
|
||||||
|
cvrf_vulner_vector
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].remediations[0].r#type,
|
||||||
|
cvrf_vulner_remedition_type
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].remediations[0].description,
|
||||||
|
cvrf_vulner_remedition_descrition
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].remediations[0].date,
|
||||||
|
cvrf_vulner_remedition_date
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
cvrf.vulnerabilities[0].remediations[0].url,
|
||||||
|
cvrf_vulner_remedition_url
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user