Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into map/modeled-coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
maplant committed Aug 22, 2023
2 parents 25d787a + 3a3552a commit 34057e7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 26 deletions.
53 changes: 29 additions & 24 deletions denylist/src/denylist.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
use crate::{client::DenyListClient, models::metadata::Asset, Error, Result};
use crate::{client::DenyListClient, models::metadata::Asset, Error, Result, Settings};
use bytes::Buf;
use helium_crypto::{PublicKey, PublicKeyBinary, Verify};
use serde::Serialize;
use std::{fs, hash::Hasher, path, str::FromStr};
use std::{fs, hash::Hasher, path};
use twox_hash::XxHash64;
use xorf::{Filter as XorFilter, Xor32};

pub const SERIAL_SIZE: usize = 32;

/// the pubkey used to verify the signature of denylist updates
// TODO: is there a better home for this key ?
const PUB_KEY_B58: &str = "1SbEYKju337P6aYsRd9DT2k4qgK5ZK62kXbSvnJgqeaxK3hqQrYURZjL";
/// a copy of the last saved filter bin downloaded from github
/// if present will be used to initialise the denylist upon verifier startup
// TODO: look at using the tempfile crate to handle this
Expand All @@ -23,6 +19,7 @@ pub struct DenyList {
pub client: DenyListClient,
#[serde(skip_serializing)]
pub filter: Xor32,
pub sign_keys: Vec<PublicKey>,
}

impl TryFrom<Vec<PublicKeyBinary>> for DenyList {
Expand All @@ -35,12 +32,13 @@ impl TryFrom<Vec<PublicKeyBinary>> for DenyList {
tag_name: 0,
client,
filter,
sign_keys: vec![],
})
}
}

impl DenyList {
pub fn new() -> Result<Self> {
pub fn new(settings: &Settings) -> Result<Self> {
tracing::debug!("initializing new denylist");
// if exists default to the local saved filter bin,
// otherwise default to empty filter
Expand All @@ -54,14 +52,16 @@ impl DenyList {
);
Vec::new()
});
let filter = filter_from_bin(&bin).unwrap_or_else(|_| Xor32::from(Vec::new()));
let sign_keys = settings.sign_keys()?;
let filter = filter_from_bin(&bin, &sign_keys).unwrap_or_else(|_| Xor32::from(Vec::new()));
let client = DenyListClient::new()?;
Ok(Self {
// default tag to 0, proper tag name will be set on first
// call to update_to_latest
tag_name: 0,
client,
filter,
sign_keys,
})
}

Expand Down Expand Up @@ -93,7 +93,7 @@ impl DenyList {
tracing::debug!("found asset for tag");
let asset_url = &asset.browser_download_url;
let bin = self.client.get_bin(asset_url).await?;
if let Ok(filter) = filter_from_bin(&bin) {
if let Ok(filter) = filter_from_bin(&bin, &self.sign_keys) {
self.filter = filter;
self.tag_name = new_tag_name;
save_local_filter_bin(&bin, FILTER_BIN_PATH)?;
Expand All @@ -113,7 +113,7 @@ impl DenyList {
}

/// deconstruct bytes into the filter component parts
pub fn filter_from_bin(bin: &Vec<u8>) -> Result<Xor32> {
pub fn filter_from_bin(bin: &Vec<u8>, sign_keys: &[PublicKey]) -> Result<Xor32> {
if bin.is_empty() {
return Err(Error::InvalidBinary("invalid filter bin".to_string()));
}
Expand All @@ -122,21 +122,26 @@ pub fn filter_from_bin(bin: &Vec<u8>) -> Result<Xor32> {
let _version = buf.get_u8();
let signature_len = buf.get_u16_le() as usize;
let signature = buf.copy_to_bytes(signature_len).to_vec();
let pubkey = PublicKey::from_str(PUB_KEY_B58)?;
match pubkey.verify(buf, &signature) {
Ok(_) => {
tracing::info!("updating filter to latest");
let _serial = buf.get_u32_le();
let xor = bincode::deserialize::<Xor32>(buf)?;
Ok(xor)
}
Err(_) => {
sign_keys
.iter()
.any(|pubkey| {
pubkey
.verify(buf, &signature)
.map(|res| {
tracing::info!(%pubkey, "valid denylist signer");
res
})
.is_ok()
})
.then(|| {
buf.advance(4);
bincode::deserialize::<Xor32>(buf)
})
.transpose()?
.ok_or_else(|| {
tracing::warn!("filter signature verification failed");
Err(Error::InvalidBinary(
"filter signature verification failed".to_string(),
))
}
}
Error::InvalidBinary("filter signature verification failed".to_string())
})
}

fn public_key_hash<R: AsRef<[u8]>>(public_key: R) -> u64 {
Expand Down
14 changes: 13 additions & 1 deletion denylist/src/settings.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{Error, Result};
use config::{Config, Environment, File};
use helium_crypto::PublicKey;
use serde::Deserialize;
use std::{path::Path, time::Duration};
use std::{path::Path, str::FromStr, time::Duration};

#[derive(Debug, Deserialize, Clone)]
pub struct Settings {
Expand All @@ -15,6 +16,10 @@ pub struct Settings {
/// Cadence at which we poll for an updated denylist (secs)
#[serde(default = "default_trigger_interval")]
pub trigger: u64,
// vec of b58 helium encoded pubkeys
// used to verify signature of denylist filters
#[serde(default)]
pub sign_keys: Vec<String>,
}

pub fn default_log() -> String {
Expand Down Expand Up @@ -56,4 +61,11 @@ impl Settings {
pub fn trigger_interval(&self) -> Duration {
Duration::from_secs(self.trigger)
}

pub fn sign_keys(&self) -> std::result::Result<Vec<PublicKey>, helium_crypto::Error> {
self.sign_keys
.iter()
.map(|pubkey| PublicKey::from_str(pubkey))
.collect()
}
}
2 changes: 1 addition & 1 deletion iot_verifier/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl Runner {
let beacon_max_retries = settings.beacon_max_retries;
let witness_max_retries = settings.witness_max_retries;
let deny_list_latest_url = settings.denylist.denylist_url.clone();
let mut deny_list = DenyList::new()?;
let mut deny_list = DenyList::new(&settings.denylist)?;
// force update to latest in order to update the tag name
// when first run, the denylist will load the local filter
// but we dont save the tag name so it defaults to 0
Expand Down

0 comments on commit 34057e7

Please sign in to comment.