Skip to content

Commit

Permalink
cpe_name
Browse files Browse the repository at this point in the history
  • Loading branch information
cn-kali-team committed Aug 11, 2023
1 parent 32a0b3f commit f7a6c58
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 31 deletions.
28 changes: 19 additions & 9 deletions cpe/src/dictionary.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! ### Common Platform Enumeration (CPE): Dictionary
//! The Dictionary specification defines the concept of a CPE dictionary, which is a repository of CPE names and metadata, with each name identifying a single class of IT product. The Dictionary specification defines processes for using the dictionary, such as how to search for a particular CPE name or look for dictionary entries that belong to a broader product class. Also, the Dictionary specification outlines all the rules that dictionary maintainers must follow when creating new dictionary entries and updating existing entries.
//!
use crate::{parse_uri_attribute, CPEAttributes};
use crate::{parse_uri_attribute, CPEName};
use chrono::{DateTime, Utc};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
Expand Down Expand Up @@ -30,6 +30,7 @@ by validation. In essence, a dictionary file can contain additional information
to use or not, but this information is not required to be used or understood.
*/
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct CPEItem {
#[serde(
rename(serialize = "name", deserialize = "@name"),
Expand Down Expand Up @@ -59,6 +60,7 @@ pub struct CPEItem {
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Title {
#[serde(rename(serialize = "lang", deserialize = "@lang"))]
pub lang: String,
Expand All @@ -73,6 +75,7 @@ The NotesType complex type defines an element that consists of one or more
child note elements. It is assumed that each of these note elements is representative of the same
language as defined by their parent.*/
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Notes {
#[serde(rename(serialize = "lang", deserialize = "@lang"))]
pub lang: String,
Expand All @@ -87,6 +90,7 @@ version of OVAL or a related system testing language, and the content will be an
written in that language. The external file reference could be used to point to the file in which the
content test identifier is defined.*/
#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
#[serde(deny_unknown_fields)]
pub struct Check {
#[serde(rename = "system")]
pub system: String,
Expand All @@ -97,6 +101,7 @@ pub struct Check {
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct References {
reference: Vec<Reference>,
}
Expand All @@ -108,6 +113,7 @@ extra descriptive material, for example a supplier's web site or platform
documentation.
*/
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Reference {
#[serde(rename(serialize = "href", deserialize = "@href"))]
pub href: String,
Expand All @@ -116,18 +122,20 @@ pub struct Reference {
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct CPE23Item {
#[serde(
rename(serialize = "name", deserialize = "@name"),
deserialize_with = "uri_to_attribute",
serialize_with = "attribute_to_uri"
)]
pub name: CPEAttributes,
pub name: CPEName,
#[serde(skip_serializing_if = "Option::is_none")]
pub deprecation: Option<Deprecation>,
}

#[derive(Deserialize, Serialize, Debug, Clone, Default)]
#[serde(deny_unknown_fields)]
pub struct Deprecation {
#[serde(rename(serialize = "date", deserialize = "@date"))]
pub date: DateTime<Utc>,
Expand All @@ -136,13 +144,14 @@ pub struct Deprecation {
}

#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct DeprecatedInfo {
#[serde(
rename(serialize = "name", deserialize = "@name"),
deserialize_with = "uri_to_attribute",
serialize_with = "attribute_to_uri"
)]
pub name: CPEAttributes,
pub name: CPEName,
#[serde(rename(serialize = "type", deserialize = "@type"))]
pub d_type: String,
}
Expand All @@ -153,6 +162,7 @@ also allowed although it is not part of the official schema. Individual organiza
generator information that they feel is important and it will be skipped during the validation. All that
this schema really cares about is that the stated generator information is there.*/
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(deny_unknown_fields)]
pub struct Generator {
/// The optional product_name element specifies the name of the application used to generate the file.
pub product_name: String,
Expand All @@ -174,7 +184,7 @@ fn parse_name<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: Deserializer<'de>,
{
struct ParseString(PhantomData<CPEAttributes>);
struct ParseString(PhantomData<CPEName>);
impl<'de> de::Visitor<'de> for ParseString {
type Value = String;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
Expand All @@ -200,13 +210,13 @@ where
deserializer.deserialize_any(ParseString(PhantomData))
}

pub fn uri_to_attribute<'de, D>(deserializer: D) -> Result<CPEAttributes, D::Error>
pub fn uri_to_attribute<'de, D>(deserializer: D) -> Result<CPEName, D::Error>
where
D: Deserializer<'de>,
{
struct UriToAttribute(PhantomData<CPEAttributes>);
struct UriToAttribute(PhantomData<CPEName>);
impl<'de> de::Visitor<'de> for UriToAttribute {
type Value = CPEAttributes;
type Value = CPEName;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("uri_to_attribute")
}
Expand All @@ -217,7 +227,7 @@ where
// cpe:2.3:part:vendor:product:version:update:edition:language:sw_edition:target_sw: target_hw:other
// https://cpe.mitre.org/specification/#downloads
let value = parse_uri_attribute(value).unwrap_or_default();
match CPEAttributes::from_str(value.as_str()) {
match CPEName::from_str(value.as_str()) {
Ok(p) => Ok(p),
Err(e) => Err(de::Error::custom(e)),
}
Expand All @@ -232,7 +242,7 @@ where
deserializer.deserialize_any(UriToAttribute(PhantomData))
}

pub fn attribute_to_uri<S>(cpe: &CPEAttributes, s: S) -> Result<S::Ok, S::Error>
pub fn attribute_to_uri<S>(cpe: &CPEName, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Expand Down
15 changes: 8 additions & 7 deletions cpe/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ use part::CPEPart;
// cpe:2.3:part:vendor:product:version:update:edition:language:sw_edition:target_sw: target_hw:other
// CPE属性
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq)]
pub struct CPEAttributes {
#[serde(deny_unknown_fields)]
pub struct CPEName {
// 分类:a,o,h
pub part: CPEPart,
// 创建产品个人或者组织/厂商
Expand All @@ -56,7 +57,7 @@ pub struct CPEAttributes {
pub other: Component,
}

impl CPEAttributes {
impl CPEName {
// 从uri转CPE属性
pub fn from_uri(uri: &str) -> Result<Self> {
let uri = match uri.strip_prefix("cpe:2.3:") {
Expand Down Expand Up @@ -116,7 +117,7 @@ impl CPEAttributes {
});
}
};
let mut att = CPEAttributes {
let mut att = CPEName {
part: CPEPart::default(),
vendor: Default::default(),
product: Default::default(),
Expand Down Expand Up @@ -186,14 +187,14 @@ impl CPEAttributes {
}
}

impl FromStr for CPEAttributes {
impl FromStr for CPEName {
type Err = CPEError;
fn from_str(uri: &str) -> Result<Self> {
CPEAttributes::from_uri(uri)
CPEName::from_uri(uri)
}
}

impl fmt::Display for CPEAttributes {
impl fmt::Display for CPEName {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
part,
Expand Down Expand Up @@ -270,7 +271,7 @@ pub fn version_cmp(a: &str, b: &str, operator: &str) -> bool {
false
}

impl CPEAttributes {
impl CPEName {
// 匹配指定版本是否存在漏洞
pub fn match_version(&self, version: &str) -> bool {
if self.version.is_any() {
Expand Down
35 changes: 24 additions & 11 deletions cve/src/configurations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
/// A configuration is a container that holds a set of nodes which then contain CPE Name Match Criteria. Configurations consist of three different types.
///
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Configurations {
// 版本
#[serde(rename = "CVE_data_version")]
Expand All @@ -13,6 +14,7 @@ pub struct Configurations {
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Node {
// 逻辑操作符
pub operator: Operator,
Expand All @@ -24,28 +26,39 @@ pub struct Node {
/// Applicability statements are made to withstand changes to the Official CPE Dictionary without requiring consistent maintenance. CPE Match criteria comes in two forms CPE Match Strings and CPE Match String Ranges. Each of these are abstract concepts that are then correlated to CPE Names in the Official CPE Dictionary. Match criteria are displayed in bold text within a configuration node.
///
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Match {
// 是否存在漏洞
pub vulnerable: bool,
/// A CPE Match string is a single CPE Names string that correlates to one or many CPE Names in the Official CPE Dictionary. When a match string has the bug icon next to it, all matching CPE Names are considered vulnerable. You can click the caret below a CPE Match String to see the CPE Names in the dictionary that match.
#[serde(
serialize_with = "cpe::dictionary::attribute_to_uri",
deserialize_with = "cpe::dictionary::uri_to_attribute"
)]
pub cpe23_uri: cpe::CPEAttributes,
#[serde(flatten)]
pub cpe_uri: CPEUri,
// 包括 从版本开始
#[serde(skip_serializing_if = "Option::is_none")]
pub version_start_including: Option<String>,
// 排除 从版本开始
#[serde(skip_serializing_if = "Option::is_none")]
pub version_start_excluding: Option<String>,
// 包括 到版本结束
#[serde(skip_serializing_if = "Option::is_none")]
pub version_end_including: Option<String>,
// 排除 到版本结束
#[serde(skip_serializing_if = "Option::is_none")]
pub version_end_excluding: Option<String>,
#[serde(rename = "cpe_name")]
pub cpe_name: Vec<CPEUri>,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CPEUri {
/// A CPE Match string is a single CPE Names string that correlates to one or many CPE Names in the Official CPE Dictionary. When a match string has the bug icon next to it, all matching CPE Names are considered vulnerable. You can click the caret below a CPE Match String to see the CPE Names in the dictionary that match.
#[serde(
serialize_with = "cpe::dictionary::attribute_to_uri",
deserialize_with = "cpe::dictionary::uri_to_attribute"
)]
pub cpe23_uri: cpe::CPEName,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "UPPERCASE")]
#[serde(rename_all = "UPPERCASE", deny_unknown_fields)]
pub enum Operator {
And,
Or,
Expand Down Expand Up @@ -87,11 +100,11 @@ impl Match {
}

pub fn is_match(&self, product: &str, version: &str) -> bool {
if self.cpe23_uri.match_product(product) {
if self.cpe_uri.cpe23_uri.match_product(product) {
if self.has_version_range() {
return self.match_version_range(version);
}
return self.cpe23_uri.match_version(version);
return self.cpe_uri.cpe23_uri.match_version(version);
}
false
}
Expand Down
6 changes: 3 additions & 3 deletions cve/src/impact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::str::FromStr;
/// Must contain: At least one entry, can be text, CVSSv2, CVSSv3, others may be added
///
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Impact {
// TODO: Implement V1?
// cvssV2 过期
Expand All @@ -24,7 +24,7 @@ pub struct Impact {
/// The CVSSv2 <https://www.first.org/cvss/v2/guide> scoring data, split up into Base Metrics Group (BM), Temporal Metrics Group (TM) and Environmental Metrics Group (EM).
///
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ImpactMetricV2 {
pub cvss_v2: cvss::v2::CVSS,
// 漏洞的可利用 评分
Expand All @@ -44,7 +44,7 @@ pub struct ImpactMetricV2 {
///
/// The CVSSv3 <https://www.first.org/cvss/specification-document> scoring data.
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ImpactMetricV3 {
pub cvss_v3: cvss::v3::CVSS,
// 漏洞的可利用 评分
Expand Down
12 changes: 11 additions & 1 deletion cve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use serde::{Deserialize, Serialize};
/// These objects can in turn contain more objects, arrays, strings and so on. The reason for this is so that each top level object type can contain self-identifying data such as CVE_Data_version. Most objects can in turn contains virtually any other object. In general, if you traverse into the nested tree of objects you should not encounter any chains that contains more than one instance of a given object container. Simply put you should not for example encounter a chain such as: root, CVE_affects, CVE_configuration, CVE_workaround, CVE_configuration. Please note that this rule may be subject to change as we get new container types and use cases.
#[derive(Debug, Deserialize, Serialize)]
#[allow(non_snake_case)]
#[serde(deny_unknown_fields)]
pub struct CVEContainer {
/// This string identifies what kind of data is held in this JSON file. This is mandatory and designed to prevent problems with attempting to detect what kind of file this is. Valid values for this string are CVE, CNA, CVEMENTOR.
pub CVE_data_type: String,
Expand All @@ -42,7 +43,7 @@ pub struct CVEContainer {

// 单个CVE信息
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
#[allow(clippy::upper_case_acronyms)]
pub struct CVEItem {
// CVE 信息
Expand All @@ -58,6 +59,7 @@ pub struct CVEItem {
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct CVE {
/// This string identifies what kind of data is held in this JSON file. This is mandatory and designed to prevent problems with attempting to detect what kind of file this is. Valid values for this string are CVE, CNA, CVEMENTOR.
pub data_type: String,
Expand All @@ -79,11 +81,13 @@ pub struct CVE {
/// These URLs are supplemental information relevant to the vulnerability, which include details that may not be present in the CVE Description. References are given resource tags such as third-party advisory, vendor advisory, technical paper, press/media, VDB entries, etc. These tags can help users quickly categorize the type of information each reference contains. References for a CVE are provided through the CVE list, the NVD does not have direct control over them. If you have concerns with existing CVE references or find other publicly available information that would be useful, then you can submit a request using the form at <https://cveform.mitre.org/> for the CVE Assignment Team to review.
///
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct References {
pub reference_data: Vec<Reference>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Reference {
pub url: String,
pub name: String,
Expand All @@ -92,16 +96,19 @@ pub struct Reference {
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Description {
pub description_data: Vec<DescriptionData>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct DescriptionData {
pub lang: String,
pub value: String,
}
/// This is metadata about the CVE ID such as the CVE ID, who requested it, who assigned it, when it was requested, when it was assigned, the current state (PUBLIC, REJECT, etc.) and so on.
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct Meta {
/// CVE-YEAR-NNNNNNN - the CVE ID in the format listed in <http://cve.mitre.org/cve/identifiers/syntaxchange.html#new>
#[serde(rename = "ID")]
Expand All @@ -114,15 +121,18 @@ pub struct Meta {
///
/// Must contain: At least one entry, can be text, OWASP, CWE, please note that while only one is required you can use more than one (or indeed all three) as long as they are correct).
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct ProblemType {
#[serde(rename = "problemtype_data")]
problem_type_data: Vec<ProblemTypeDataItem>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct ProblemTypeDataItem {
pub description: Vec<ProblemTypeDescription>,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(deny_unknown_fields)]
pub struct ProblemTypeDescription {
pub lang: String,
pub value: String,
Expand Down

0 comments on commit f7a6c58

Please sign in to comment.