Skip to content

Commit

Permalink
cpe
Browse files Browse the repository at this point in the history
  • Loading branch information
cn-kali-team committed Aug 10, 2023
1 parent d2918de commit f80c5d0
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 119 deletions.
1 change: 1 addition & 0 deletions cpe/src/component.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! component
use language_tags::LanguageTag;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{convert::TryFrom, fmt, str::FromStr};
Expand Down
62 changes: 55 additions & 7 deletions cpe/src/dictionary.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,34 @@
//! ### 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 chrono::{DateTime, Utc};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::fmt;
use std::marker::PhantomData;

use std::str::FromStr;
/// The cpe-list element acts as a top-level container for CPE Name items. Each individual item must be unique. Please refer to the description of ListType for additional information about the structure of this element.
///
#[derive(Deserialize, Serialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct CPEList {
pub generator: Generator,
pub cpe_item: Vec<CPEItem>,
}

/**
The ItemType complex type defines an element that represents a single CPE
Name. The required name attribute is a URI which must be a unique key and should follow the URI
structure outlined in the CPE Specification. The optional title element is used to provide a
human-readable title for the platform. To support uses intended for multiple languages, this element
supports the ‘xml:lang’ attribute. At most one title element can appear for each language. The notes
element holds optional descriptive material. Multiple notes elements are allowed, but only one per
language should be used. Note that the language associated with the notes element applies to all child
note elements. The optional references element holds external info references. The optional check
element is used to call out an OVAL Definition that can confirm or reject an IT system as an instance of
the named platform. Additional elements not part of the CPE namespace are allowed and are just skipped
by validation. In essence, a dictionary file can contain additional information that a user can choose
to use or not, but this information is not required to be used or understood.
*/
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct CPEItem {
#[serde(
Expand Down Expand Up @@ -50,15 +68,24 @@ pub struct Title {
)]
pub desc: String,
}

/**
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)]
pub struct Notes {
#[serde(rename(serialize = "lang", deserialize = "@lang"))]
pub lang: String,
#[serde(rename(serialize = "value", deserialize = "$value"))]
pub desc: String,
}

/**
The CheckType complex type is used to define an element to hold information
about an individual check. It includes a checking system specification URI, string content, and an
optional external file reference. The checking system specification should be the URI for a particular
version of OVAL or a related system testing language, and the content will be an identifier of a test
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)]
pub struct Check {
#[serde(rename = "system")]
Expand All @@ -73,7 +100,13 @@ pub struct Check {
pub struct References {
reference: Vec<Reference>,
}

/**
The ReferencesType complex type defines an element used to hold a
collection of individual references. Each reference consists of a piece of text (intended to be
human-readable) and a URI (intended to be a URL, and point to a real resource) and is used to point to
extra descriptive material, for example a supplier's web site or platform
documentation.
*/
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Reference {
#[serde(rename(serialize = "href", deserialize = "@href"))]
Expand Down Expand Up @@ -113,12 +146,27 @@ pub struct DeprecatedInfo {
#[serde(rename(serialize = "type", deserialize = "@type"))]
pub d_type: String,
}

/** The GeneratorType complex type defines an element that is used to hold
information about when a particular document was compiled, what version of the schema was used, what
tool compiled the document, and what version of that tool was used. Additional generator information is
also allowed although it is not part of the official schema. Individual organizations can place
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)]
pub struct Generator {
/// The optional product_name element specifies the name of the application used to generate the file.
pub product_name: String,
/// The optional product_version element specifies the version of the application used to generate the file.
pub product_version: String,
/// The required schema_version element specifies the version of the schema that the document has been written against and that should be used for validation.
pub schema_version: String,
/** The required timestamp element specifies when the particular
document was compiled. The format for the timestamp is yyyy-mm-ddThh:mm:ss. Note that the
timestamp element does not specify when an item in the document was created or modified but
rather when the actual XML document that contains the items was created. For example, a document
might pull a bunch of existing items together, each of which was created at some point in the
past. The timestamp in this case would be when this combined document was
created.*/
pub timestamp: DateTime<Utc>,
}

Expand Down Expand Up @@ -169,7 +217,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::try_from(value.as_str()) {
match CPEAttributes::from_str(value.as_str()) {
Ok(p) => Ok(p),
Err(e) => Err(de::Error::custom(e)),
}
Expand Down
8 changes: 7 additions & 1 deletion cpe/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! cpe error
use thiserror::Error;

pub type Result<T> = std::result::Result<T, CPEError>;

#[derive(Error, Debug)]
#[derive(Error, Debug, Clone)]
pub enum CPEError {
#[error("invalid wfn `{value}`")]
InvalidWfn { value: String },
Expand All @@ -21,3 +22,8 @@ pub enum CPEError {
#[error("Invalid CPE type \"{value}\"")]
InvalidCpeType { value: String },
}
impl From<&CPEError> for CPEError {
fn from(value: &CPEError) -> Self {
value.clone()
}
}
137 changes: 38 additions & 99 deletions cpe/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
//! Official Common Platform Enumeration (CPE) Dictionary
//!
//! CPE is a structured naming scheme for information technology systems, software, and packages. Based upon the generic syntax for Uniform Resource Identifiers (URI), CPE includes a formal name format, a method for checking names against a system, and a description format for binding text and tests to a name.
//! Below is the current official version of the CPE Product Dictionary. The dictionary provides an agreed upon list of official CPE names. The dictionary is provided in XML format and is available to the general public. Please check back frequently as the CPE Product Dictionary will continue to grow to include all past, present and future product releases. The CPE Dictionary is updated nightly when modifications or new names are added.
//!
//! As of December 2009, The National Vulnerability Database is now accepting contributions to the Official CPE Dictionary. Organizations interested in submitting CPE Names should contact the NVD CPE team at [email protected] for help with the processing of their submission.
//!
//! The CPE Dictionary hosted and maintained at NIST may be used by nongovernmental organizations on a voluntary basis and is not subject to copyright in the United States. Attribution would, however, be appreciated by NIST.
//!

#![doc(html_root_url = "https://emo-car.github.io/nvd-rs/cpe")]
// Package wfn provides a representation, bindings and matching of the Well-Formed CPE names as per
// https://nvlpubs.nist.gov/nistpubs/Legacy/IR/nistir7695.pdf and
// https://nvlpubs.nist.gov/nistpubs/Legacy/IR/nistir7696.pdf
use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::{convert::TryFrom, fmt, str::FromStr};
use std::{fmt, str::FromStr};

pub mod component;
pub mod dictionary;
Expand All @@ -13,9 +23,9 @@ pub mod part;

use crate::component::Language;
use crate::error::{CPEError, Result};
pub use component::Component;
pub use part::CPEPart;

use component::Component;
use part::CPEPart;
// https://csrc.nist.gov/projects/security-content-automation-protocol/specifications/cpe
// view-source:https://csrc.nist.gov/schema/cpe/2.3/cpe-dictionary_2.3.xsd
// https://scap.nist.gov/schema/cpe/2.3/cpe-naming_2.3.xsd
// cpe:2.3:part:vendor:product:version:update:edition:language:sw_edition:target_sw: target_hw:other
Expand Down Expand Up @@ -59,84 +69,20 @@ impl CPEAttributes {
};

let mut components = uri.split(':');

let part = if let Some(part) = components.next() {
CPEPart::try_from(part)?
} else {
return Err(CPEError::InvalidPart {
value: uri.to_string(),
});
};
let vendor = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let product = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let version = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let update = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let edition = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let language = if let Some(part) = components.next() {
Language::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let sw_edition = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let target_sw = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let target_hw = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
};
let other = if let Some(part) = components.next() {
Component::try_from(part)?
} else {
return Err(CPEError::InvalidUri {
value: uri.to_string(),
});
let error = CPEError::InvalidPart {
value: uri.to_string(),
};
let part = CPEPart::from_str(components.next().ok_or(&error)?)?;
let vendor = Component::from_str(components.next().ok_or(&error)?)?;
let product = Component::from_str(components.next().ok_or(&error)?)?;
let version = Component::from_str(components.next().ok_or(&error)?)?;
let update = Component::from_str(components.next().ok_or(&error)?)?;
let edition = Component::from_str(components.next().ok_or(&error)?)?;
let language = Language::from_str(components.next().ok_or(&error)?)?;
let sw_edition = Component::from_str(components.next().ok_or(&error)?)?;
let target_sw = Component::from_str(components.next().ok_or(&error)?)?;
let target_hw = Component::from_str(components.next().ok_or(&error)?)?;
let other = Component::from_str(components.next().ok_or(&error)?)?;

Ok(Self {
part,
Expand Down Expand Up @@ -205,17 +151,17 @@ impl CPEAttributes {
}
Some((k, v)) => {
match k {
"part" => att.part = CPEPart::try_from(v)?,
"vendor" => att.vendor = Component::try_from(v)?,
"product" => att.product = Component::try_from(v)?,
"version" => att.version = Component::try_from(v)?,
"update" => att.update = Component::try_from(v)?,
"edition" => att.edition = Component::try_from(v)?,
"language" => att.language = Language::try_from(v)?,
"sw_edition" => att.sw_edition = Component::try_from(v)?,
"target_sw" => att.target_sw = Component::try_from(v)?,
"target_hw" => att.target_hw = Component::try_from(v)?,
"other" => att.other = Component::try_from(v)?,
"part" => att.part = CPEPart::from_str(v)?,
"vendor" => att.vendor = Component::from_str(v)?,
"product" => att.product = Component::from_str(v)?,
"version" => att.version = Component::from_str(v)?,
"update" => att.update = Component::from_str(v)?,
"edition" => att.edition = Component::from_str(v)?,
"language" => att.language = Language::from_str(v)?,
"sw_edition" => att.sw_edition = Component::from_str(v)?,
"target_sw" => att.target_sw = Component::from_str(v)?,
"target_hw" => att.target_hw = Component::from_str(v)?,
"other" => att.other = Component::from_str(v)?,
_ => {
return Err(CPEError::InvalidPart {
value: k.to_string(),
Expand All @@ -240,13 +186,6 @@ impl CPEAttributes {
}
}

impl TryFrom<&str> for CPEAttributes {
type Error = CPEError;
fn try_from(val: &str) -> Result<Self> {
CPEAttributes::from_str(val)
}
}

impl FromStr for CPEAttributes {
type Err = CPEError;
fn from_str(uri: &str) -> Result<Self> {
Expand Down
18 changes: 6 additions & 12 deletions cpe/src/part.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::error::CPEError;
//! part
use crate::error::{CPEError, Result};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{convert::TryFrom, fmt, str::FromStr};
use std::{fmt, str::FromStr};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CPEPart {
Expand All @@ -15,7 +16,7 @@ pub enum CPEPart {
}

impl Serialize for CPEPart {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
Expand All @@ -29,7 +30,7 @@ impl Serialize for CPEPart {
}

impl<'de> Deserialize<'de> for CPEPart {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Expand All @@ -49,17 +50,10 @@ impl Default for CPEPart {
}
}

impl TryFrom<&str> for CPEPart {
type Error = CPEError;
fn try_from(val: &str) -> Result<Self, Self::Error> {
Self::from_str(val)
}
}

impl FromStr for CPEPart {
type Err = CPEError;

fn from_str(val: &str) -> Result<Self, Self::Err> {
fn from_str(val: &str) -> Result<Self> {
let c = {
let c = val.chars().next();
c.ok_or(CPEError::InvalidPart {
Expand Down
7 changes: 7 additions & 0 deletions cvss/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
//! ### Vulnerability Metrics
//! The Common Vulnerability Scoring System (CVSS) is a method used to supply a qualitative measure of severity. CVSS is not a measure of risk. CVSS consists of three metric groups: Base, Temporal, and Environmental. The Base metrics produce a score ranging from 0 to 10, which can then be modified by scoring the Temporal and Environmental metrics. A CVSS score is also represented as a vector string, a compressed textual representation of the values used to derive the score. Thus, CVSS is well suited as a standard measurement system for industries, organizations, and governments that need accurate and consistent vulnerability severity scores. Two common uses of CVSS are calculating the severity of vulnerabilities discovered on one's systems and as a factor in prioritization of vulnerability remediation activities. The National Vulnerability Database (NVD) provides CVSS scores for almost all known vulnerabilities.
//!
//! The NVD supports both Common Vulnerability Scoring System (CVSS) v2.0 and v3.X standards. The NVD provides CVSS 'base scores' which represent the innate characteristics of each vulnerability. The NVD does not currently provide 'temporal scores' (metrics that change over time due to events external to the vulnerability) or 'environmental scores' (scores customized to reflect the impact of the vulnerability on your organization). However, the NVD does supply a CVSS calculator for both CVSS v2 and v3 to allow you to add temporal and environmental score data.
//!
//! CVSS is owned and managed by FIRST.Org, Inc. (FIRST), a US-based non-profit organization, whose mission is to help computer security incident response teams across the world. The official CVSS documentation can be found at <https://www.first.org/cvss/>.

#![doc(html_root_url = "https://emo-car.github.io/nvd-rs/cvss")]
// 通用漏洞评分系统
// https://csrc.nist.gov/schema/nvd/feed/1.1-Beta/cvss-v3.x_beta.json
Expand Down

0 comments on commit f80c5d0

Please sign in to comment.