mirror of
https://github.com/chirpstack/chirpstack.git
synced 2025-03-23 04:25:30 +00:00
Improve dev-nonce validation.
This commit is contained in:
parent
d69ff895b6
commit
24b975b337
@ -28,6 +28,9 @@ impl ToStatus for storage::error::Error {
|
||||
storage::error::Error::InvalidMIC => {
|
||||
Status::new(Code::InvalidArgument, format!("{}", self))
|
||||
}
|
||||
storage::error::Error::InvalidDevNonce => {
|
||||
Status::new(Code::InvalidArgument, format!("{}", self))
|
||||
}
|
||||
storage::error::Error::Validation(_) => {
|
||||
Status::new(Code::InvalidArgument, format!("{}", self))
|
||||
}
|
||||
|
@ -157,6 +157,43 @@ pub async fn reset_nonces(dev_eui: &EUI64) -> Result<DeviceKeys, Error> {
|
||||
Ok(dk)
|
||||
}
|
||||
|
||||
pub async fn validate_and_store_dev_nonce(
|
||||
dev_eui: &EUI64,
|
||||
dev_nonce: i32,
|
||||
) -> Result<DeviceKeys, Error> {
|
||||
let dk = task::spawn_blocking({
|
||||
let dev_eui = *dev_eui;
|
||||
move || -> Result<DeviceKeys, Error> {
|
||||
let c = get_db_conn()?;
|
||||
c.transaction::<DeviceKeys, Error, _>(|| {
|
||||
let mut dk: DeviceKeys = device_keys::dsl::device_keys
|
||||
.find(&dev_eui)
|
||||
.for_update()
|
||||
.first(&c)
|
||||
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))?;
|
||||
|
||||
if dk.dev_nonces.contains(&(dev_nonce)) {
|
||||
return Err(Error::InvalidDevNonce);
|
||||
}
|
||||
|
||||
dk.dev_nonces.push(dev_nonce);
|
||||
|
||||
diesel::update(device_keys::dsl::device_keys.find(&dev_eui))
|
||||
.set((
|
||||
device_keys::updated_at.eq(Utc::now()),
|
||||
device_keys::dev_nonces.eq(&dk.dev_nonces),
|
||||
))
|
||||
.get_result(&c)
|
||||
.map_err(|e| Error::from_diesel(e, dev_eui.to_string()))
|
||||
})
|
||||
}
|
||||
})
|
||||
.await??;
|
||||
|
||||
info!(dev_eui = %dev_eui, dev_nonce = dev_nonce, "Device-nonce validated and stored");
|
||||
Ok(dk)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
|
@ -24,6 +24,9 @@ pub enum Error {
|
||||
#[error("Invalid MIC")]
|
||||
InvalidMIC,
|
||||
|
||||
#[error("Invalid DevNonce")]
|
||||
InvalidDevNonce,
|
||||
|
||||
#[error("Validation error: {0}")]
|
||||
Validation(String),
|
||||
|
||||
|
@ -17,7 +17,9 @@ use super::{filter_rx_info_by_tenant_id, helpers, UplinkFrameSet};
|
||||
use crate::api::helpers::ToProto;
|
||||
use crate::backend::{joinserver, keywrap};
|
||||
use crate::storage::device_session;
|
||||
use crate::storage::{application, device, device_keys, device_profile, metrics, tenant};
|
||||
use crate::storage::{
|
||||
application, device, device_keys, device_profile, error::Error as StorageError, metrics, tenant,
|
||||
};
|
||||
use crate::{config, downlink, framelog, integration, metalog, region};
|
||||
use chirpstack_api::{api, common, integration as integration_pb, internal, meta};
|
||||
|
||||
@ -87,9 +89,8 @@ impl JoinRequest {
|
||||
ctx.get_join_accept_from_js().await?;
|
||||
} else {
|
||||
// Using internal keys
|
||||
ctx.get_device_keys().await?;
|
||||
ctx.validate_dev_nonce_and_get_device_keys().await?;
|
||||
ctx.validate_mic().await?;
|
||||
ctx.validate_dev_nonce().await?;
|
||||
ctx.construct_join_accept_and_set_keys()?;
|
||||
ctx.save_device_keys().await?;
|
||||
}
|
||||
@ -208,10 +209,55 @@ impl JoinRequest {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_device_keys(&mut self) -> Result<()> {
|
||||
trace!("Getting device-keys");
|
||||
async fn validate_dev_nonce_and_get_device_keys(&mut self) -> Result<()> {
|
||||
trace!("Validate dev-nonce and get device-keys");
|
||||
let dev = self.device.as_ref().unwrap();
|
||||
let app = self.application.as_ref().unwrap();
|
||||
let join_request = self.join_request.as_ref().unwrap();
|
||||
|
||||
self.device_keys = Some(
|
||||
match device_keys::validate_and_store_dev_nonce(
|
||||
&dev.dev_eui,
|
||||
join_request.dev_nonce as i32,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(v) => v,
|
||||
Err(v) => match v {
|
||||
StorageError::InvalidDevNonce => {
|
||||
integration::log_event(
|
||||
&app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::LogEvent {
|
||||
deduplication_id: self.uplink_frame_set.uplink_set_id.to_string(),
|
||||
time: Some(Utc::now().into()),
|
||||
device_info: self.device_info.clone(),
|
||||
level: integration_pb::LogLevel::Error.into(),
|
||||
code: integration_pb::LogCode::Otaa.into(),
|
||||
description: "DevNonce has already been used".into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
metrics::save(
|
||||
&format!("device:{}", dev.dev_eui),
|
||||
&metrics::Record {
|
||||
time: Local::now(),
|
||||
metrics: [("error_OTAA".into(), 1f64)].iter().cloned().collect(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
return Err(v.into());
|
||||
}
|
||||
_ => {
|
||||
return Err(v.into());
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
self.device_keys = Some(device_keys::get(&self.device.as_ref().unwrap().dev_eui).await?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -258,48 +304,6 @@ impl JoinRequest {
|
||||
Err(anyhow!("Invalid MIC"))
|
||||
}
|
||||
|
||||
async fn validate_dev_nonce(&mut self) -> Result<()> {
|
||||
let device_keys = self.device_keys.as_mut().unwrap();
|
||||
let join_request = self.join_request.as_ref().unwrap();
|
||||
|
||||
if !device_keys
|
||||
.dev_nonces
|
||||
.contains(&(join_request.dev_nonce as i32))
|
||||
{
|
||||
device_keys.dev_nonces.push(join_request.dev_nonce as i32);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let app = self.application.as_ref().unwrap();
|
||||
let dev = self.device.as_ref().unwrap();
|
||||
|
||||
integration::log_event(
|
||||
&app.id,
|
||||
&dev.variables,
|
||||
&integration_pb::LogEvent {
|
||||
deduplication_id: self.uplink_frame_set.uplink_set_id.to_string(),
|
||||
time: Some(Utc::now().into()),
|
||||
device_info: self.device_info.clone(),
|
||||
level: integration_pb::LogLevel::Error.into(),
|
||||
code: integration_pb::LogCode::Otaa.into(),
|
||||
description: "DevNonce has already been used".into(),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
metrics::save(
|
||||
&format!("device:{}", dev.dev_eui),
|
||||
&metrics::Record {
|
||||
time: Local::now(),
|
||||
metrics: [("error_OTAA".into(), 1f64)].iter().cloned().collect(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
Err(anyhow!("DevNone has already been used"))
|
||||
}
|
||||
|
||||
fn get_random_dev_addr(&mut self) -> Result<()> {
|
||||
let conf = config::get();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user