cvss-2.0.0/.cargo_vcs_info.json0000644000000001420000000000100120060ustar { "git": { "sha1": "7d6eaeea07b42931dd35e5d755bf8ba963088f6a" }, "path_in_vcs": "cvss" }cvss-2.0.0/CHANGELOG.md000064400000000000000000000023160072674642500124440ustar 00000000000000# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## 2.0.0 (2022-05-01) ### Added - `no_std` support ([#549]) ### Changed - Structured `Error` type ([#546]) - Upgrade to 2021 edition; MSRV 1.56 ([#547]) - Flatten module structure ([#548]) ### Fixed - Computation for "no impact" vectors ([#399]) [#399]: https://github.com/RustSec/rustsec/pull/399 [#546]: https://github.com/RustSec/rustsec/pull/546 [#547]: https://github.com/RustSec/rustsec/pull/547 [#548]: https://github.com/RustSec/rustsec/pull/548 [#549]: https://github.com/RustSec/rustsec/pull/549 ## 1.0.2 (2021-05-10) ### Fixed - Dangling link in rustdoc ([#360]) [#360]: https://github.com/RustSec/rustsec/pull/360 ## 1.0.1 (2021-01-25) ### Changed - Rename default branch to `main` ## 1.0.0 (2019-09-23) - Migrate to GitHub Actions ## 0.3.0 (2019-09-06) - CVSS v3.0 support - severity: Add `FromStr` and `serde` support ## 0.2.0 (2019-08-28) - Add `Base::exploitability` and `impact` methods; docs - `serde` support ## 0.1.0 (2019-08-27) - Initial release cvss-2.0.0/CODE_OF_CONDUCT.md000064400000000000000000000062310072674642500134320ustar 00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at bascule@gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ cvss-2.0.0/Cargo.toml0000644000000021310000000000100100040ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56" name = "cvss" version = "2.0.0" authors = ["Tony Arcieri "] description = "Common Vulnerability Scoring System parser/serializer" readme = "README.md" keywords = [ "cvssv3", "security", "advisory", "vulnerability", ] categories = ["parser-implementations"] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustSec/rustsec/tree/main/cvss" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [dependencies.serde] version = "1" optional = true [features] default = [ "std", "v3", ] std = [] v3 = [] cvss-2.0.0/Cargo.toml.orig000064400000000000000000000012170072674642500135210ustar 00000000000000[package] name = "cvss" description = "Common Vulnerability Scoring System parser/serializer" version = "2.0.0" authors = ["Tony Arcieri "] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustSec/rustsec/tree/main/cvss" readme = "README.md" categories = ["parser-implementations"] keywords = ["cvssv3", "security", "advisory", "vulnerability"] edition = "2021" rust-version = "1.56" [dependencies] serde = { version = "1", optional = true } [features] default = ["std", "v3"] v3 = [] std = [] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] cvss-2.0.0/LICENSE-APACHE000064400000000000000000000251370072674642500125650ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. cvss-2.0.0/LICENSE-MIT000064400000000000000000000020640072674642500122670ustar 00000000000000Copyright (c) 2019-2021 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cvss-2.0.0/README.md000064400000000000000000000036710072674642500121170ustar 00000000000000# RustSec: Common Vulnerability Scoring System [![Latest Version][crate-image]][crate-link] [![Docs][docs-image]][docs-link] [![Build Status][build-image]][build-link] [![Safety Dance][safety-image]][safety-link] ![MSRV][rustc-image] ![Apache 2.0 OR MIT licensed][license-image] [![Project Chat][zulip-image]][zulip-link] Rust implementation of the [Common Vulnerability Scoring System (Version 3.1) Specification][spec]. [Documentation][docs-link] ## Minimum Supported Rust Version Rust **1.56** ## License Licensed under either of: - Apache License, Version 2.0 ([LICENSE-APACHE] or ) - MIT license ([LICENSE-MIT] or ) at your option. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions. [//]: # (badges) [crate-image]: https://img.shields.io/crates/v/cvss.svg [crate-link]: https://crates.io/crates/cvss [docs-image]: https://docs.rs/cvss/badge.svg [docs-link]: https://docs.rs/cvss/ [build-image]: https://github.com/RustSec/rustsec/actions/workflows/cvss.yml/badge.svg [build-link]: https://github.com/RustSec/rustsec/actions/workflows/cvss.yml [safety-image]: https://img.shields.io/badge/unsafe-forbidden-success.svg [safety-link]: https://github.com/rust-secure-code/safety-dance/ [rustc-image]: https://img.shields.io/badge/rustc-1.56+-blue.svg [license-image]: https://img.shields.io/badge/license-Apache2.0%2FMIT-blue.svg [zulip-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [zulip-link]: https://rust-lang.zulipchat.com/#narrow/stream/146229-wg-secure-code/ [//]: # (general links) [spec]: https://www.first.org/cvss/specification-document [LICENSE-APACHE]: https://github.com/RustSec/cargo-audit/blob/main/LICENSE-APACHE [LICENSE-MIT]: https://github.com/RustSec/cargo-audit/blob/main/LICENSE-MIT cvss-2.0.0/src/error.rs000064400000000000000000000044640072674642500131270ustar 00000000000000//! Error types use crate::MetricType; use alloc::string::String; use core::fmt; /// Result type with the `cvss` crate's [`Error`] type. pub type Result = core::result::Result; /// Kinds of errors #[derive(Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Error { /// Invalid component of a CVSS metric group. InvalidComponent { /// Invalid component. component: String, }, /// Invalid metric. InvalidMetric { /// The metric that was invalid. metric_type: MetricType, /// The value that was provided which is invalid. value: String, }, /// Invalid CVSS string prefix. InvalidPrefix { /// Prefix which is invalid. prefix: String, }, /// Invalid severity InvalidSeverity { /// Provided name which was unrecognized. name: String, }, /// Unknown metric name. UnknownMetric { /// Provided name which was unrecognized. name: String, }, /// Unsupported CVSS version UnsupportedVersion { /// Provided version string. version: String, }, } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::InvalidComponent { component } => { write!(f, "invalid CVSS metric group component: `{}`", component) } Error::InvalidMetric { metric_type, value } => { write!( f, "invalid CVSS {} ({}) metric: `{}`", metric_type.name(), metric_type.description(), value ) } Error::InvalidPrefix { prefix } => { write!(f, "invalid CVSS string prefix: `{}`", prefix) } Error::InvalidSeverity { name } => { write!(f, "invalid CVSS Qualitative Severity Rating: `{}`", name) } Error::UnknownMetric { name } => write!(f, "unknown CVSS metric name: `{}`", name), Error::UnsupportedVersion { version } => { write!(f, "unsupported CVSS version: {}", version) } } } } #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] impl std::error::Error for Error {} cvss-2.0.0/src/lib.rs000064400000000000000000000021460072674642500125370ustar 00000000000000#![no_std] #![cfg_attr(docsrs, feature(doc_cfg))] #![doc = include_str!("../README.md")] #![doc(html_logo_url = "https://raw.githubusercontent.com/RustSec/logos/main/rustsec-logo-lg.png")] #![forbid(unsafe_code)] #![warn(missing_docs, rust_2018_idioms, unused_qualifications)] //! ## Usage //! //! The [`v3::Base`] type provides the main functionality currently implemented //! by this crate, namely: support for parsing, serializing, and scoring //! `CVSS:3.0` and `CVSS:3.1` Base Metric Group vector strings as described in //! the [CVSS v3.1 Specification]. //! //! Serde support is available through the optional `serde` Cargo feature. //! //! [CVSS v3.1 Specification]: https://www.first.org/cvss/specification-document // TODO(tarcieri): other CVSS versions, CVSS v3.1 Temporal and Environmental Groups extern crate alloc; #[cfg(feature = "std")] extern crate std; #[cfg(feature = "v3")] pub mod v3; mod error; mod metric; mod severity; pub use crate::{ error::{Error, Result}, metric::{Metric, MetricType}, severity::Severity, }; /// Prefix used by all CVSS strings pub const PREFIX: &str = "CVSS"; cvss-2.0.0/src/metric.rs000064400000000000000000000046560072674642500132640ustar 00000000000000//! CVSS metrics. use crate::{Error, Result}; use alloc::borrow::ToOwned; use core::{ fmt::{self, Debug, Display}, str::FromStr, }; /// Trait for CVSS metrics. pub trait Metric: Copy + Clone + Debug + Display + Eq + FromStr + Ord { /// [`MetricType`] of this metric. const TYPE: MetricType; /// Get the name of this metric. fn name() -> &'static str { Self::TYPE.name() } /// Get CVSS v3.1 score for this metric. fn score(self) -> f64; /// Get `str` describing this metric's value fn as_str(self) -> &'static str; } /// Enum over all of the available metrics. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] #[non_exhaustive] pub enum MetricType { /// Availability Impact (A) A, /// Attack Complexity (AC) AC, /// Attack Vector (AV) AV, /// Confidentiality Impact (C) C, /// Integrity Impact (I) I, /// Privileges Required (PR) PR, /// Scope (S) S, /// User Interaction (UI) UI, } impl MetricType { /// Get the name of this metric (i.e. acronym) pub fn name(self) -> &'static str { match self { Self::A => "A", Self::AC => "AC", Self::AV => "AV", Self::C => "C", Self::I => "I", Self::PR => "PR", Self::S => "S", Self::UI => "UI", } } /// Get a description of this metric. pub fn description(self) -> &'static str { match self { Self::A => "Availability Impact", Self::AC => "Attack Complexity", Self::AV => "Attack Vector", Self::C => "Confidentiality Impact", Self::I => "Integrity Impact", Self::PR => "Privileges Required", Self::S => "Scope", Self::UI => "User Interaction", } } } impl Display for MetricType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.name()) } } impl FromStr for MetricType { type Err = Error; fn from_str(s: &str) -> Result { match s { "A" => Ok(Self::A), "AC" => Ok(Self::AC), "AV" => Ok(Self::AV), "C" => Ok(Self::C), "I" => Ok(Self::I), "PR" => Ok(Self::PR), "S" => Ok(Self::S), "UI" => Ok(Self::UI), _ => Err(Error::UnknownMetric { name: s.to_owned() }), } } } cvss-2.0.0/src/severity.rs000064400000000000000000000045570072674642500136530ustar 00000000000000//! Qualitative Severity Rating Scale use crate::{Error, Result}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; #[cfg(feature = "serde")] use { alloc::string::String, serde::{de, ser, Deserialize, Serialize}, }; /// Qualitative Severity Rating Scale /// /// Described in CVSS v3.1 Specification: Section 5: /// /// /// > For some purposes it is useful to have a textual representation of the /// > numeric Base, Temporal and Environmental scores. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Severity { /// None: CVSS Score 0.0 None, /// Low: CVSS Score 0.1 - 3.9 Low, /// Medium: CVSS Score 4.0 - 6.9 Medium, /// High: CVSS Score 7.0 - 8.9 High, /// Critical: CVSS Score 9.0 - 10.0 Critical, } impl Severity { /// Get a `str` describing the severity level pub fn as_str(self) -> &'static str { match self { Severity::None => "none", Severity::Low => "low", Severity::Medium => "medium", Severity::High => "high", Severity::Critical => "critical", } } } impl FromStr for Severity { type Err = Error; fn from_str(s: &str) -> Result { match s.to_ascii_lowercase().as_str() { "none" => Ok(Severity::None), "low" => Ok(Severity::Low), "medium" => Ok(Severity::Medium), "high" => Ok(Severity::High), "critical" => Ok(Severity::Critical), _ => Err(Error::InvalidSeverity { name: s.to_owned() }), } } } impl fmt::Display for Severity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for Severity { fn deserialize>( deserializer: D, ) -> core::result::Result { String::deserialize(deserializer)? .parse() .map_err(de::Error::custom) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for Severity { fn serialize( &self, serializer: S, ) -> core::result::Result { self.as_str().serialize(serializer) } } cvss-2.0.0/src/v3/base/a.rs000064400000000000000000000073420072674642500134560ustar 00000000000000//! Availability Impact (A) use crate::{Error, Metric, MetricType, Result}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// Availability Impact (A) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.3.3: /// /// /// > This metric measures the impact to the availability of the impacted /// > component resulting from a successfully exploited vulnerability. /// > While the Confidentiality and Integrity impact metrics apply to the /// > loss of confidentiality or integrity of data (e.g., information, /// > files) used by the impacted component, this metric refers to the loss /// > of availability of the impacted component itself, such as a networked /// > service (e.g., web, database, email). Since availability refers to the /// > accessibility of information resources, attacks that consume network /// > bandwidth, processor cycles, or disk space all impact the availability /// > of an impacted component. The Base Score is greatest when the /// > consequence to the impacted component is highest. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Availability { /// None (N) /// /// > There is no impact to availability within the impacted component. None, /// Low (L) /// /// > Performance is reduced or there are interruptions in resource /// > availability. Even if repeated exploitation of the vulnerability /// > is possible, the attacker does not have the ability to completely /// > deny service to legitimate users. The resources in the impacted /// > component are either partially available all of the time, or fully /// > available only some of the time, but overall there is no direct, /// > serious consequence to the impacted component. Low, /// High (H) /// /// > There is a total loss of availability, resulting in the attacker /// > being able to fully deny access to resources in the impacted /// > component; this loss is either sustained (while the attacker /// > continues to deliver the attack) or persistent (the condition /// > persists even after the attack has completed). Alternatively, /// > the attacker has the ability to deny some availability, but /// > the loss of availability presents a direct, serious consequence /// > to the impacted component (e.g., the attacker cannot disrupt /// > existing connections, but can prevent new connections; the /// > attacker can repeatedly exploit a vulnerability that, in each /// > instance of a successful attack, leaks a only small amount of /// > memory, but after repeated exploitation causes a service to become /// > completely unavailable). High, } impl Metric for Availability { const TYPE: MetricType = MetricType::A; fn score(self) -> f64 { match self { Availability::None => 0.0, Availability::Low => 0.22, Availability::High => 0.56, } } fn as_str(self) -> &'static str { match self { Availability::None => "N", Availability::Low => "L", Availability::High => "H", } } } impl fmt::Display for Availability { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for Availability { type Err = Error; fn from_str(s: &str) -> Result { match s { "N" => Ok(Availability::None), "L" => Ok(Availability::Low), "H" => Ok(Availability::High), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base/ac.rs000064400000000000000000000071360072674642500136220ustar 00000000000000//! Attack Complexity (AC) use crate::{Error, Metric, MetricType, Result}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// Attack Complexity (AC) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.1.2: /// /// /// > This metric describes the conditions beyond the attacker’s control that /// > must exist in order to exploit the vulnerability. As described below, /// > such conditions may require the collection of more information about the /// > target, or computational exceptions. Importantly, the assessment of this /// > metric excludes any requirements for user interaction in order to exploit /// > the vulnerability (such conditions are captured in the User Interaction /// > metric). If a specific configuration is required for an attack to /// > succeed, the Base metrics should be scored assuming the vulnerable /// > component is in that configuration. The Base Score is greatest for the /// > least complex attacks. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum AttackComplexity { /// High (H) /// /// > A successful attack depends on conditions beyond the attacker's control. /// > That is, a successful attack cannot be accomplished at will, but requires /// > the attacker to invest in some measurable amount of effort in preparation /// > or execution against the vulnerable component before a successful attack /// > can be expected. For example, a successful attack may depend on an /// > attacker overcoming any of the following conditions: /// > /// > - The attacker must gather knowledge about the environment in which /// > the vulnerable target/component exists. For example, a requirement /// > to collect details on target configuration settings, sequence numbers, /// > or shared secrets. /// > - The attacker must prepare the target environment to improve exploit /// > reliability. For example, repeated exploitation to win a race /// > condition, or overcoming advanced exploit mitigation techniques. /// > - The attacker must inject themselves into the logical network path /// > between the target and the resource requested by the victim in order /// > to read and/or modify network communications (e.g., a man in the middle /// > attack). High, /// Low (L) /// /// > Specialized access conditions or extenuating circumstances do not exist. /// > An attacker can expect repeatable success when attacking the vulnerable component. Low, } impl Default for AttackComplexity { fn default() -> AttackComplexity { AttackComplexity::High } } impl Metric for AttackComplexity { const TYPE: MetricType = MetricType::AC; fn score(self) -> f64 { match self { AttackComplexity::High => 0.44, AttackComplexity::Low => 0.77, } } fn as_str(self) -> &'static str { match self { AttackComplexity::High => "H", AttackComplexity::Low => "L", } } } impl fmt::Display for AttackComplexity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for AttackComplexity { type Err = Error; fn from_str(s: &str) -> Result { match s { "H" => Ok(AttackComplexity::High), "L" => Ok(AttackComplexity::Low), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base/av.rs000064400000000000000000000112220072674642500136340ustar 00000000000000//! CVSS v3.1 Base Metric Group - Attack Vector (AV) use crate::{Error, Metric, MetricType}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// Attack Vector (AV) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.1.1: /// /// /// > This metric reflects the context by which vulnerability exploitation /// > is possible. This metric value (and consequently the Base Score) will be /// > larger the more remote (logically, and physically) an attacker can be in /// > order to exploit the vulnerable component. The assumption is that the /// > number of potential attackers for a vulnerability that could be exploited /// > from across a network is larger than the number of potential attackers /// > that could exploit a vulnerability requiring physical access to a device, /// > and therefore warrants a greater Base Score. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum AttackVector { /// Physical (P) /// /// > The attack requires the attacker to physically touch or manipulate /// > the vulnerable component. Physical interaction may be brief /// > (e.g., evil maid attack) or persistent. An example of such an attack /// > is a cold boot attack in which an attacker gains access to disk /// > encryption keys after physically accessing the target system. /// > Other examples include peripheral attacks via FireWire/USB Direct /// > Memory Access (DMA). Physical, /// Local (L) /// /// > The vulnerable component is not bound to the network stack and the /// > attacker’s path is via read/write/execute capabilities. Either: /// > /// > - the attacker exploits the vulnerability by accessing the target /// > system locally (e.g., keyboard, console), or remotely (e.g., SSH) /// > - the attacker relies on User Interaction by another person to /// > perform actions required to exploit the vulnerability (e.g., using /// > social engineering techniques to trick a legitimate user into /// > opening a malicious document). Local, /// Adjacent (A) /// /// > The vulnerable component is bound to the network stack, but the /// > attack is limited at the protocol level to a logically adjacent /// > topology. This can mean an attack must be launched from the same /// > shared physical (e.g., Bluetooth or IEEE 802.11) or logical /// > (e.g., local IP subnet) network, or from within a secure or /// > otherwise limited administrative domain (e.g., MPLS, secure VPN to /// > an administrative network zone). One example of an Adjacent attack /// > would be an ARP (IPv4) or neighbor discovery (IPv6) flood leading to /// > a denial of service on the local LAN segment (e.g., CVE‑2013‑6014). Adjacent, /// Network (N) /// /// > The vulnerable component is bound to the network stack and the set of /// > possible attackers extends beyond the other options listed below, up to /// > and including the entire Internet. Such a vulnerability is often /// > termed “remotely exploitable” and can be thought of as an attack being /// > exploitable at the protocol level one or more network hops away /// > (e.g., across one or more routers). An example of a network attack is /// > an attacker causing a denial of service (DoS) by sending a specially /// > crafted TCP packet across a wide area network (e.g., CVE‑2004‑0230). Network, } impl Metric for AttackVector { const TYPE: MetricType = MetricType::AV; fn score(self) -> f64 { match self { AttackVector::Physical => 0.20, AttackVector::Local => 0.55, AttackVector::Adjacent => 0.62, AttackVector::Network => 0.85, } } fn as_str(self) -> &'static str { match self { AttackVector::Physical => "P", AttackVector::Local => "L", AttackVector::Adjacent => "A", AttackVector::Network => "N", } } } impl fmt::Display for AttackVector { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for AttackVector { type Err = Error; fn from_str(s: &str) -> Result { match s { "P" => Ok(AttackVector::Physical), "L" => Ok(AttackVector::Local), "A" => Ok(AttackVector::Adjacent), "N" => Ok(AttackVector::Network), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base/c.rs000064400000000000000000000054750072674642500134650ustar 00000000000000//! Confidentiality Impact (C) use crate::{Error, Metric, MetricType}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// Confidentiality Impact (C) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.3.1: /// /// /// > This metric measures the impact to the confidentiality of the information /// > resources managed by a software component due to a successfully exploited /// > vulnerability. Confidentiality refers to limiting information access and /// > disclosure to only authorized users, as well as preventing access by, or /// > disclosure to, unauthorized ones. The Base Score is greatest when the loss /// > to the impacted component is highest. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Confidentiality { /// None (N) /// /// > There is no loss of confidentiality within the impacted component. None, /// Low (L) /// /// > There is some loss of confidentiality. Access to some restricted /// > information is obtained, but the attacker does not have control over /// > what information is obtained, or the amount or kind of loss is /// > limited. The information disclosure does not cause a direct, serious /// > loss to the impacted component. Low, /// High (H) /// /// > There is a total loss of confidentiality, resulting in all resources /// > within the impacted component being divulged to the attacker. /// > Alternatively, access to only some restricted information is /// > obtained, but the disclosed information presents a direct, serious /// > impact. For example, an attacker steals the administrator's password, /// > or private encryption keys of a web server. High, } impl Metric for Confidentiality { const TYPE: MetricType = MetricType::C; fn score(self) -> f64 { match self { Confidentiality::None => 0.0, Confidentiality::Low => 0.22, Confidentiality::High => 0.56, } } fn as_str(self) -> &'static str { match self { Confidentiality::None => "N", Confidentiality::Low => "L", Confidentiality::High => "H", } } } impl fmt::Display for Confidentiality { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for Confidentiality { type Err = Error; fn from_str(s: &str) -> Result { match s { "N" => Ok(Confidentiality::None), "L" => Ok(Confidentiality::Low), "H" => Ok(Confidentiality::High), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base/i.rs000064400000000000000000000046450072674642500134710ustar 00000000000000//! Integrity Impact (I) use crate::{Error, Metric, MetricType, Result}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// Integrity Impact (I) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.3.2: /// /// /// > This metric measures the impact to integrity of a successfully exploited /// > vulnerability. Integrity refers to the trustworthiness and veracity of /// > information. The Base Score is greatest when the consequence to the /// > impacted component is highest. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Integrity { /// None (N) /// /// > There is no loss of integrity within the impacted component. None, /// Low (L) /// /// > Modification of data is possible, but the attacker does not have /// > control over the consequence of a modification, or the amount of /// > modification is limited. The data modification does not have a /// > direct, serious impact on the impacted component. Low, /// High (H) /// /// > There is a total loss of integrity, or a complete loss of protection. /// > For example, the attacker is able to modify any/all files protected /// > by the impacted component. Alternatively, only some files can be /// > modified, but malicious modification would present a direct, serious /// > consequence to the impacted component. High, } impl Metric for Integrity { const TYPE: MetricType = MetricType::I; fn score(self) -> f64 { match self { Integrity::None => 0.0, Integrity::Low => 0.22, Integrity::High => 0.56, } } fn as_str(self) -> &'static str { match self { Integrity::None => "N", Integrity::Low => "L", Integrity::High => "H", } } } impl fmt::Display for Integrity { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for Integrity { type Err = Error; fn from_str(s: &str) -> Result { match s { "N" => Ok(Integrity::None), "L" => Ok(Integrity::Low), "H" => Ok(Integrity::High), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base/pr.rs000064400000000000000000000055770072674642500136670ustar 00000000000000//! Privileges Required (PR) use crate::{error::Error, Metric, MetricType}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// Privileges Required (PR) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.1.3: /// /// /// > This metric describes the level of privileges an attacker must possess /// > *before* successfully exploiting the vulnerability. The Base Score is /// > greatest if no privileges are required. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum PrivilegesRequired { /// High (H) /// /// > The attacker requires privileges that provide significant /// > (e.g., administrative) control over the vulnerable component allowing /// > access to component-wide settings and files. High, /// Low (L) /// /// > The attacker requires privileges that provide basic user capabilities /// > that could normally affect only settings and files owned by a user. /// > Alternatively, an attacker with Low privileges has the ability to /// > access only non-sensitive resources. Low, /// None (N) /// /// > The attacker is unauthorized prior to attack, and therefore does not /// > require any access to settings or files of the the vulnerable system /// > to carry out an attack. None, } impl PrivilegesRequired { /// Score when accounting for scope change pub fn scoped_score(self, scope_change: bool) -> f64 { match self { PrivilegesRequired::High => { if scope_change { 0.50 } else { 0.27 } } PrivilegesRequired::Low => { if scope_change { 0.68 } else { 0.62 } } PrivilegesRequired::None => 0.85, } } } impl Metric for PrivilegesRequired { const TYPE: MetricType = MetricType::PR; fn score(self) -> f64 { self.scoped_score(false) } fn as_str(self) -> &'static str { match self { PrivilegesRequired::High => "H", PrivilegesRequired::Low => "L", PrivilegesRequired::None => "N", } } } impl fmt::Display for PrivilegesRequired { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for PrivilegesRequired { type Err = Error; fn from_str(s: &str) -> Result { match s { "H" => Ok(PrivilegesRequired::High), "L" => Ok(PrivilegesRequired::Low), "N" => Ok(PrivilegesRequired::None), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base/s.rs000064400000000000000000000067610072674642500135040ustar 00000000000000//! Scope (S) use crate::{Error, Metric, MetricType, Result}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// Scope (S) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.2: /// /// /// > The Scope metric captures whether a vulnerability in one vulnerable /// > component impacts resources in components beyond its security scope. /// > /// > Formally, a security authority is a mechanism (e.g., an application, /// > an operating system, firmware, a sandbox environment) that defines and /// > enforces access control in terms of how certain subjects/actors /// > (e.g., human users, processes) can access certain restricted /// > objects/resources (e.g., files, CPU, memory) in a controlled manner. /// > All the subjects and objects under the jurisdiction of a single security /// > authority are considered to be under one security scope. If a /// > vulnerability in a vulnerable component can affect a component which is /// > in a different security scope than the vulnerable component, a Scope /// > change occurs. Intuitively, whenever the impact of a vulnerability /// > breaches a security/trust boundary and impacts components outside the /// > security scope in which vulnerable component resides, a Scope change occurs. /// > /// > The security scope of a component encompasses other components that /// > provide functionality solely to that component, even if these other /// > components have their own security authority. For example, a database /// > used solely by one application is considered part of that application’s /// > security scope even if the database has its own security authority, /// > e.g., a mechanism controlling access to database records based on /// > database users and associated database privileges. /// > /// > The Base Score is greatest when a scope change occurs. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Scope { /// Unchanged (U) /// /// > An exploited vulnerability can only affect resources managed by the /// > same security authority. In this case, the vulnerable component and /// > the impacted component are either the same, or both are managed by /// > the same security authority. Unchanged, /// Changed (C) /// /// > An exploited vulnerability can affect resources beyond the security /// > scope managed by the security authority of the vulnerable component. /// > In this case, the vulnerable component and the impacted component /// > are different and managed by different security authorities. Changed, } impl Scope { /// Has the scope changed? pub fn is_changed(self) -> bool { self == Scope::Changed } } impl Metric for Scope { const TYPE: MetricType = MetricType::S; fn score(self) -> f64 { unimplemented!() } fn as_str(self) -> &'static str { match self { Scope::Unchanged => "U", Scope::Changed => "C", } } } impl fmt::Display for Scope { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for Scope { type Err = Error; fn from_str(s: &str) -> Result { match s { "U" => Ok(Scope::Unchanged), "C" => Ok(Scope::Changed), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base/ui.rs000064400000000000000000000043040072674642500136460ustar 00000000000000//! User Interaction (UI) use crate::{Error, Metric, MetricType, Result}; use alloc::borrow::ToOwned; use core::{fmt, str::FromStr}; /// User Interaction (UI) - CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2.1.4: /// /// /// > This metric captures the requirement for a human user, other than the /// > attacker, to participate in the successful compromise of the vulnerable /// > component. This metric determines whether the vulnerability can be /// > exploited solely at the will of the attacker, or whether a separate user /// > (or user-initiated process) must participate in some manner. /// > The Base Score is greatest when no user interaction is required. #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum UserInteraction { /// Required (R) /// /// > Successful exploitation of this vulnerability requires a user to /// > take some action before the vulnerability can be exploited. For /// > example, a successful exploit may only be possible during the /// > installation of an application by a system administrator. Required, /// None (N) /// /// > The vulnerable system can be exploited without interaction from any user. None, } impl Metric for UserInteraction { const TYPE: MetricType = MetricType::UI; fn score(self) -> f64 { match self { UserInteraction::Required => 0.62, UserInteraction::None => 0.85, } } fn as_str(self) -> &'static str { match self { UserInteraction::Required => "R", UserInteraction::None => "N", } } } impl fmt::Display for UserInteraction { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:{}", Self::name(), self.as_str()) } } impl FromStr for UserInteraction { type Err = Error; fn from_str(s: &str) -> Result { match s { "R" => Ok(UserInteraction::Required), "N" => Ok(UserInteraction::None), _ => Err(Error::InvalidMetric { metric_type: Self::TYPE, value: s.to_owned(), }), } } } cvss-2.0.0/src/v3/base.rs000064400000000000000000000233020072674642500132300ustar 00000000000000//! CVSS v3.1 Base Metric Group mod a; mod ac; mod av; mod c; mod i; mod pr; mod s; mod ui; pub use self::{ a::Availability, ac::AttackComplexity, av::AttackVector, c::Confidentiality, i::Integrity, pr::PrivilegesRequired, s::Scope, ui::UserInteraction, }; use super::Score; use crate::{Error, Metric, MetricType, Result, PREFIX}; use alloc::{borrow::ToOwned, vec::Vec}; use core::{fmt, str::FromStr}; #[cfg(feature = "serde")] use { alloc::string::{String, ToString}, serde::{de, ser, Deserialize, Serialize}, }; #[cfg(feature = "std")] use crate::Severity; /// CVSS v3.1 Base Metric Group /// /// Described in CVSS v3.1 Specification: Section 2: /// /// /// > The Base metric group represents the intrinsic characteristics of a /// > vulnerability that are constant over time and across user environments. /// > It is composed of two sets of metrics: the Exploitability metrics and /// > the Impact metrics. /// > /// > The Exploitability metrics reflect the ease and technical means by which /// > the vulnerability can be exploited. That is, they represent characteristics /// > of *the thing that is vulnerable*, which we refer to formally as the /// > *vulnerable component*. The Impact metrics reflect the direct consequence /// > of a successful exploit, and represent the consequence to the /// > *thing that suffers the impact*, which we refer to formally as the /// > *impacted component*. /// > /// > While the vulnerable component is typically a software application, /// > module, driver, etc. (or possibly a hardware device), the impacted /// > component could be a software application, a hardware device or a network /// > resource. This potential for measuring the impact of a vulnerability other /// > than the vulnerable component, was a key feature introduced with /// > CVSS v3.0. This property is captured by the Scope metric. #[derive(Clone, Debug, Default, Eq, PartialEq)] pub struct Base { /// Minor component of the version pub minor_version: usize, /// Attack Vector (AV) pub av: Option, /// Attack Complexity (AC) pub ac: Option, /// Privileges Required (PR) pub pr: Option, /// User Interaction (UI) pub ui: Option, /// Scope (S) pub s: Option, /// Confidentiality Impact (C) pub c: Option, /// Integrity Impact (I) pub i: Option, /// Availability Impact (A) pub a: Option, } impl Base { /// Calculate Base CVSS score: overall value for determining the severity /// of a vulnerability, generally referred to as the "CVSS score". /// /// Described in CVSS v3.1 Specification: Section 2: /// /// /// > When the Base metrics are assigned values by an analyst, the Base /// > equation computes a score ranging from 0.0 to 10.0. /// > /// > Specifically, the Base equation is derived from two sub equations: /// > the Exploitability sub-score equation, and the Impact sub-score /// > equation. The Exploitability sub-score equation is derived from the /// > Base Exploitability metrics, while the Impact sub-score equation is /// > derived from the Base Impact metrics. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn score(&self) -> Score { let exploitability = self.exploitability().value(); let iss = self.impact().value(); let iss_scoped = if !self.is_scope_changed() { 6.42 * iss } else { (7.52 * (iss - 0.029)) - (3.25 * (iss - 0.02).powf(15.0)) }; let score = if iss_scoped <= 0.0 { 0.0 } else if !self.is_scope_changed() { (iss_scoped + exploitability).min(10.0) } else { (1.08 * (iss_scoped + exploitability)).min(10.0) }; Score::new(score).roundup() } /// Calculate Base Exploitability score: sub-score for measuring /// ease of exploitation. /// /// Described in CVSS v3.1 Specification: Section 2: /// /// /// > The Exploitability metrics reflect the ease and technical means by which /// > the vulnerability can be exploited. That is, they represent characteristics /// > of *the thing that is vulnerable*, which we refer to formally as the /// > *vulnerable component*. pub fn exploitability(&self) -> Score { let av_score = self.av.map(|av| av.score()).unwrap_or(0.0); let ac_score = self.ac.map(|ac| ac.score()).unwrap_or(0.0); let ui_score = self.ui.map(|ui| ui.score()).unwrap_or(0.0); let pr_score = self .pr .map(|pr| pr.scoped_score(self.is_scope_changed())) .unwrap_or(0.0); (8.22 * av_score * ac_score * pr_score * ui_score).into() } /// Calculate Base Impact Score (ISS): sub-score for measuring the /// consequences of successful exploitation. /// /// Described in CVSS v3.1 Specification: Section 2: /// /// /// > The Impact metrics reflect the direct consequence /// > of a successful exploit, and represent the consequence to the /// > *thing that suffers the impact*, which we refer to formally as the /// > *impacted component*. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn impact(&self) -> Score { let c_score = self.c.map(|c| c.score()).unwrap_or(0.0); let i_score = self.i.map(|i| i.score()).unwrap_or(0.0); let a_score = self.a.map(|a| a.score()).unwrap_or(0.0); (1.0 - ((1.0 - c_score) * (1.0 - i_score) * (1.0 - a_score)).abs()).into() } /// Calculate Base CVSS `Severity` according to the /// Qualitative Severity Rating Scale (i.e. Low / Medium / High / Critical) /// /// Described in CVSS v3.1 Specification: Section 5: /// #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn severity(&self) -> Severity { self.score().severity() } /// Has the scope changed? fn is_scope_changed(&self) -> bool { self.s.map(|s| s.is_changed()).unwrap_or(false) } } macro_rules! write_metrics { ($f:expr, $($metric:expr),+) => { $( if let Some(metric) = $metric { write!($f, "/{}", metric)?; } )+ }; } impl fmt::Display for Base { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}:3.{}", PREFIX, self.minor_version)?; write_metrics!(f, self.av, self.ac, self.pr, self.ui, self.s, self.c, self.i, self.a); Ok(()) } } impl FromStr for Base { type Err = Error; fn from_str(s: &str) -> Result { let component_vec = s .split('/') .map(|component| { let mut parts = component.split(':'); let id = parts.next().ok_or_else(|| Error::InvalidComponent { component: component.to_owned(), })?; let value = parts.next().ok_or_else(|| Error::InvalidComponent { component: component.to_owned(), })?; if parts.next().is_some() { return Err(Error::InvalidComponent { component: component.to_owned(), }); } Ok((id, value)) }) .collect::>>()?; let mut components = component_vec.iter(); let &(id, version_string) = components.next().ok_or(Error::InvalidPrefix { prefix: s.to_owned(), })?; if id != PREFIX { return Err(Error::InvalidPrefix { prefix: id.to_owned(), }); } let mut metrics = Self { minor_version: match version_string { "3.0" => 0, "3.1" => 1, _ => { return Err(Error::UnsupportedVersion { version: version_string.to_owned(), }) } }, ..Default::default() }; for &component in components { let id = component.0.to_ascii_uppercase(); let value = component.1.to_ascii_uppercase(); match id.parse::()? { MetricType::AV => metrics.av = Some(value.parse()?), MetricType::AC => metrics.ac = Some(value.parse()?), MetricType::PR => metrics.pr = Some(value.parse()?), MetricType::UI => metrics.ui = Some(value.parse()?), MetricType::S => metrics.s = Some(value.parse()?), MetricType::C => metrics.c = Some(value.parse()?), MetricType::I => metrics.i = Some(value.parse()?), MetricType::A => metrics.a = Some(value.parse()?), } } Ok(metrics) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for Base { fn deserialize>( deserializer: D, ) -> core::result::Result { String::deserialize(deserializer)? .parse() .map_err(de::Error::custom) } } #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for Base { fn serialize( &self, serializer: S, ) -> core::result::Result { self.to_string().serialize(serializer) } } cvss-2.0.0/src/v3/score.rs000064400000000000000000000032760072674642500134410ustar 00000000000000//! CVSS v3.1 scores use crate::severity::Severity; /// CVSS V3.1 scores. /// /// Formula described in CVSS v3.1 Specification: Section 5: /// #[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)] pub struct Score(f64); impl Score { /// Create a new score object pub fn new(score: f64) -> Score { Score(score) } /// Get the score as a floating point value pub fn value(self) -> f64 { self.0 } /// Round the score up to the algorithm described in /// CVSS v3.1: Appendix A - Floating Point Rounding. /// /// #[cfg(feature = "std")] pub fn roundup(self) -> Score { let score_int = (self.0 * 100_000.0) as u64; if score_int % 10000 == 0 { Score((score_int as f64) / 100_000.0) } else { let score_floor = ((score_int as f64) / 10_000.0).floor(); Score((score_floor + 1.0) / 10.0) } } /// Convert the numeric score into a `Severity` pub fn severity(self) -> Severity { if self.0 < 0.1 { Severity::None } else if self.0 < 4.0 { Severity::Low } else if self.0 < 7.0 { Severity::Medium } else if self.0 < 9.0 { Severity::High } else { Severity::Critical } } } impl From for Score { fn from(score: f64) -> Score { Score(score) } } impl From for f64 { fn from(score: Score) -> f64 { score.value() } } impl From for Severity { fn from(score: Score) -> Severity { score.severity() } } cvss-2.0.0/src/v3.rs000064400000000000000000000003500072674642500123140ustar 00000000000000//! Common Vulnerability Scoring System (v3.1) //! //! // TODO(tarcieri): Environmental and Temporal Metrics pub mod base; mod score; pub use self::{base::Base, score::Score}; cvss-2.0.0/tests/base.rs000064400000000000000000000213430072674642500132560ustar 00000000000000/// Base Metrics tests /// /// NOTE: These CVEs are actually `CVSS:3.0` and have been modified for the /// purposes of these tests use core::str::FromStr; /// CVE-2013-1937 #[test] fn cve_2013_1937() { let cvss_for_cve_2013_1937 = "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2013_1937).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2013_1937); assert_eq!(base.score().value(), 6.1); } /// Missing CVSS:3.1 prefix #[test] fn bad_prefix() { let cvss_for_cve_2013_1937e = "AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"; assert!(cvss::v3::Base::from_str(cvss_for_cve_2013_1937e).is_err()); } /// CVSS:3.0 prefix (parse these as for the purposes of this library they're identical) #[test] fn cvss_v3_0_prefix() { let cvss_for_cve_2013_1937 = "CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2013_1937).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2013_1937); assert_eq!(base.score().value(), 6.1); } /// CVE-2013-0375 #[test] fn cve_2013_0375() { let cvss_for_cve_2013_0375 = "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2013_0375).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2013_0375); assert_eq!(base.score().value(), 6.4); } /// CVE-2014-3566 #[test] fn cve_2014_3566() { let cvss_for_cve_2014_3566 = "CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2014_3566).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2014_3566); assert_eq!(base.score().value(), 3.1); } /// CVE-2012-1516 #[test] fn cve_2012_1516() { let cvss_for_cve_2012_1516 = "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2012_1516).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2012_1516); assert_eq!(base.score().value(), 9.9); } /// CVE-2009-0783 #[test] fn cve_2009_0783() { let cvss_for_cve_2009_0783 = "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:L"; let base = cvss::v3::Base::from_str(cvss_for_cve_2009_0783).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2009_0783); assert_eq!(base.score().value(), 4.2); } /// CVE-2012-0384 #[test] fn cve_2012_0384() { let cvss_for_cve_2012_0384 = "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2012_0384).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2012_0384); assert_eq!(base.score().value(), 8.8); } /// CVE-2015-1098 #[test] fn cve_2015_1098() { let cvss_for_cve_2015_1098 = "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2015_1098).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2015_1098); assert_eq!(base.score().value(), 7.8); } /// CVE-2014-0160 #[test] fn cve_2014_0160() { let cvss_for_cve_2014_0160 = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2014_0160).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2014_0160); assert_eq!(base.score().value(), 7.5); } /// CVE-2014-6271 #[test] fn cve_2014_6271() { let cvss_for_cve_2014_6271 = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2014_6271).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2014_6271); assert_eq!(base.score().value(), 9.8); } /// CVE-2008-1447 #[test] fn cve_2008_1447() { let cvss_for_cve_2008_1447 = "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:N/I:H/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2008_1447).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2008_1447); assert_eq!(base.score().value(), 6.8); } /// CVE-2014-2005 #[test] fn cve_2014_2005() { let cvss_for_cve_2014_2005 = "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2014_2005).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2014_2005); assert_eq!(base.score().value(), 6.8); } /// CVE-2010-0467 #[test] fn cve_2010_0467() { let cvss_for_cve_2010_0467 = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2010_0467).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2010_0467); assert_eq!(base.score().value(), 5.8); } /// CVE-2012-1342 #[test] fn cve_2012_1342() { let cvss_for_cve_2012_1342 = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:L/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2012_1342).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2012_1342); assert_eq!(base.score().value(), 5.8); } /// CVE-2013-6014 #[test] fn cve_2013_6014() { let cvss_for_cve_2013_6014 = "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2013_6014).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2013_6014); assert_eq!(base.score().value(), 9.3); } /// CVE-2014-9253 #[test] fn cve_2014_9253() { let cvss_for_cve_2014_9253 = "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2014_9253).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2014_9253); assert_eq!(base.score().value(), 5.4); } /// CVE-2009-0658 #[test] fn cve_2009_0658() { let cvss_for_cve_2009_0658 = "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2009_0658).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2009_0658); assert_eq!(base.score().value(), 7.8); } /// CVE-2011-1265 #[test] fn cve_2011_1265() { let cvss_for_cve_2011_1265 = "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2011_1265).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2011_1265); assert_eq!(base.score().value(), 8.8); } /// CVE-2014-2019 #[test] fn cve_2014_2019() { let cvss_for_cve_2014_2019 = "CVSS:3.1/AV:P/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2014_2019).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2014_2019); assert_eq!(base.score().value(), 4.6); } /// CVE-2015-0970 #[test] fn cve_2015_0970() { let cvss_for_cve_2015_0970 = "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2015_0970).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2015_0970); assert_eq!(base.score().value(), 8.8); } /// CVE-2014-0224 #[test] fn cve_2014_0224() { let cvss_for_cve_2014_0224 = "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N"; let base = cvss::v3::Base::from_str(cvss_for_cve_2014_0224).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2014_0224); assert_eq!(base.score().value(), 7.4); } /// CVE-2012-5376 #[test] fn cve_2012_5376() { let cvss_for_cve_2012_5376 = "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H"; let base = cvss::v3::Base::from_str(cvss_for_cve_2012_5376).unwrap(); assert_eq!(&base.to_string(), cvss_for_cve_2012_5376); assert_eq!(base.score().value(), 9.6); } /// No impact scope changed #[test] fn no_impact_scope_changed() { // https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:N => 0.0 let cvss_for_no_impact_scope_changed = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:N/A:N"; let base = cvss::v3::Base::from_str(cvss_for_no_impact_scope_changed).unwrap(); assert_eq!(&base.to_string(), cvss_for_no_impact_scope_changed); assert_eq!(base.score().value(), 0.0); } /// No impact scope unchanged #[test] fn no_impact_scope_unchanged() { // https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N => 0.0 let cvss_for_no_impact_scope_unchanged = "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N"; let base = cvss::v3::Base::from_str(cvss_for_no_impact_scope_unchanged).unwrap(); assert_eq!(&base.to_string(), cvss_for_no_impact_scope_unchanged); assert_eq!(base.score().value(), 0.0); } #[test] fn low_scope_unchanged() { // https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L => 1.6 let cvss_for_low_scope_unchanged = "CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:U/C:N/I:N/A:L"; let base = cvss::v3::Base::from_str(cvss_for_low_scope_unchanged).unwrap(); assert_eq!(&base.to_string(), cvss_for_low_scope_unchanged); assert_eq!(base.score().value(), 1.6); } #[test] fn low_scope_changed() { // https://www.first.org/cvss/calculator/3.1#CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:C/C:N/I:N/A:L => 1.8 let cvss_for_low_scope_changed = "CVSS:3.1/AV:P/AC:H/PR:H/UI:R/S:C/C:N/I:N/A:L"; let base = cvss::v3::Base::from_str(cvss_for_low_scope_changed).unwrap(); assert_eq!(&base.to_string(), cvss_for_low_scope_changed); assert_eq!(base.score().value(), 1.8); }