Skip to content

Commit

Permalink
fix(scan): abort on invalid NVD API key
Browse files Browse the repository at this point in the history
  • Loading branch information
mrl5 committed Jul 23, 2022
1 parent d76aa2d commit 291f60e
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 12 deletions.
22 changes: 17 additions & 5 deletions crates/cli/src/command/cve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::conf::ApiKeys;
use cpe_tag::validators::validate_cpe_batch;
use security_advisories::http::get_client;
use security_advisories::service::{
fetch_cves_by_cpe, fetch_known_exploited_cves, get_cves_summary,
fetch_cves_by_cpe, fetch_known_exploited_cves, get_cves_summary, throw_on_invalid_api_key,
};
use serde_json::from_str;
use serde_json::Value;
Expand Down Expand Up @@ -44,7 +44,7 @@ pub async fn execute(
} else {
None
},
);
)?;
}
None => continue,
}
Expand All @@ -53,12 +53,24 @@ pub async fn execute(
Ok(())
}

fn print_cves(cves: Value, show_summary: bool, known_exploited_cves: Option<&[String]>) {
fn print_cves(
cves: Value,
show_summary: bool,
known_exploited_cves: Option<&[String]>,
) -> Result<(), Box<dyn Error>> {
if show_summary {
for cve in get_cves_summary(&cves, known_exploited_cves) {
println!("{}", cve);
match get_cves_summary(&cves, known_exploited_cves) {
Ok(summary) => {
for cve in summary {
println!("{}", cve);
}
Ok(())
}
Err(e) => Err(e),
}
} else {
throw_on_invalid_api_key(&cves)?;
println!("{}", cves);
Ok(())
}
}
13 changes: 9 additions & 4 deletions crates/cli/src/command/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,16 @@ async fn handle_cves(

for cpe in matches {
match fetch_cves_by_cpe(client, cpe, api_keys).await {
Ok(res) => {
for cve in get_cves_summary(&res, Some(known_exploited_cves)) {
cves.insert(cve);
Ok(res) => match get_cves_summary(&res, Some(known_exploited_cves)) {
Ok(summary) => {
for cve in summary {
cves.insert(cve);
}
}
}
Err(e) => {
return Err(e);
}
},
Err(e) => {
log::error!("{category}/{pkg_name}: {e}");
}
Expand Down
14 changes: 13 additions & 1 deletion crates/security-advisories/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use reqwest::Client;
use secrecy::Secret;
use serde_json::Value;
use std::error::Error;
use std::io::{Error as IOError, ErrorKind};
use std::path::Path;
mod cisa;
mod nvd;
Expand Down Expand Up @@ -39,10 +40,21 @@ pub async fn fetch_feed_checksum(client: &Client) -> Result<String, Box<dyn Erro
pub fn get_cves_summary(
full_cve_resp: &Value,
known_exploitable_cves: Option<&[String]>,
) -> Vec<CveSummary> {
) -> Result<Vec<CveSummary>, Box<dyn Error>> {
throw_on_invalid_api_key(full_cve_resp)?;
nvd::get_cves_summary(full_cve_resp, known_exploitable_cves)
}

pub fn throw_on_invalid_api_key(resp: &Value) -> Result<(), Box<dyn Error>> {
if nvd::is_api_key_invalid(resp) {
return Err(Box::new(IOError::new(
ErrorKind::InvalidInput,
"Invalid NVD API key",
)));
}
Ok(())
}

pub async fn download_cpe_match_feed(
client: &Client,
feed_path: &Path,
Expand Down
17 changes: 15 additions & 2 deletions crates/security-advisories/src/service/nvd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ pub async fn fetch_cves_by_cpe(
pub fn get_cves_summary(
full_cve_resp: &Value,
known_exploitable_cves: Option<&[String]>,
) -> Vec<CveSummary> {
) -> Result<Vec<CveSummary>, Box<dyn Error>> {
let mut summary_items = vec![];

if let Some(resp_items) = full_cve_resp["result"]["CVE_Items"].as_array() {
Expand All @@ -78,7 +78,12 @@ pub fn get_cves_summary(
}
}

summary_items
Ok(summary_items)
}

pub fn is_api_key_invalid(nvd_response: &Value) -> bool {
log::debug!("{}", nvd_response);
nvd_response["error"].as_str() == Some("Invalid apiKey")
}

pub async fn fetch_feed_checksum(client: &Client) -> Result<String, Box<dyn Error>> {
Expand Down Expand Up @@ -214,4 +219,12 @@ mod tests {
let summary = get_cve_summary(&unlisted_cve, Some(&known_exploitable_cves)).unwrap();
assert_eq!(summary.is_known_exploited_vuln, Some(false));
}

#[test]
fn it_should_recognize_invalid_api_key() {
let cve = from_str(r#"{"CVE_data_meta":{"ASSIGNER":"cve@gitlab.com","ID":"CVE-2021-22204"},"data_format":"MITRE","data_type":"CVE","data_version":"4.0","description":{"description_data":[{"lang":"en","value":"Improper neutralization of user data in the DjVu file format in ExifTool versions 7.44 and up allows arbitrary code execution when parsing the malicious image"}]},"problemtype":{"problemtype_data":[{"description":[{"lang":"en","value":"CWE-74"}]}]},"references":{"reference_data":[]}}"#).unwrap();
let invalid_api_key_resp = from_str(r#"{"loggedIn":true,"authorized":true,"error":"Invalid apiKey","message":"Invalid apiKey"}"#).unwrap();
assert!(!is_api_key_invalid(&cve));
assert!(is_api_key_invalid(&invalid_api_key_resp));
}
}

0 comments on commit 291f60e

Please sign in to comment.