From 57e3c6bf010d51842cbc86a9801fd9baee1b22eb Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Wed, 23 Jan 2019 02:29:00 +0000 Subject: Prevent direct instantiation of Pro and Storage The Pro and Storage structs may only be created using the connect functions. This patch adds a private PhantomData field to the structs to ensure that the compiler does not allow direct instantiation. --- CHANGELOG.md | 2 ++ TODO.md | 1 - src/device.rs | 29 +++++++++++++++++++++++------ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4df5c6..1e962e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ - Return `CommunicationError::NotConnected` instead of `CommandError::Undefined` from the connect functions. - Remove the `CommandError::Undefined` variant. +- Add a private `PhantomData` field to `Pro` and `Storage` to make direct + instantiation impossible. # v0.3.4 (2019-01-20) - Fix authentication methods that assumed that `char` is signed. diff --git a/TODO.md b/TODO.md index 487f56d..8f4e348 100644 --- a/TODO.md +++ b/TODO.md @@ -8,7 +8,6 @@ - Fix timing issues with the `totp_no_pin` and `totp_pin` test cases. - Clear passwords from memory. - Find a nicer syntax for the `write_config` test. -- Prevent construction of internal types. - Check integer conversions. - Consider implementing `Into` for `(Device, CommandError)` - Lock password safe in `PasswordSafe::drop()` (see [nitrokey-storage-firmware diff --git a/src/device.rs b/src/device.rs index 16064c3..40d6ba4 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,4 +1,5 @@ use std::fmt; +use std::marker; use libc; use nitrokey_sys; @@ -154,7 +155,11 @@ pub enum DeviceWrapper { /// [`connect`]: fn.connect.html /// [`Pro::connect`]: #method.connect #[derive(Debug)] -pub struct Pro {} +pub struct Pro { + // make sure that users cannot directly instantiate this type + #[doc(hidden)] + marker: marker::PhantomData<()>, +} /// A Nitrokey Storage device without user or admin authentication. /// @@ -196,7 +201,11 @@ pub struct Pro {} /// [`connect`]: fn.connect.html /// [`Storage::connect`]: #method.connect #[derive(Debug)] -pub struct Storage {} +pub struct Storage { + // make sure that users cannot directly instantiate this type + #[doc(hidden)] + marker: marker::PhantomData<()>, +} /// The status of a volume on a Nitrokey Storage device. #[derive(Debug)] @@ -713,8 +722,12 @@ fn get_connected_model() -> Option { fn create_device_wrapper(model: Model) -> DeviceWrapper { match model { - Model::Pro => DeviceWrapper::Pro(Pro {}), - Model::Storage => DeviceWrapper::Storage(Storage {}), + Model::Pro => DeviceWrapper::Pro(Pro { + marker: marker::PhantomData, + }), + Model::Storage => DeviceWrapper::Storage(Storage { + marker: marker::PhantomData, + }), } } @@ -790,7 +803,9 @@ impl Pro { pub fn connect() -> Result { // TODO: maybe Option instead of Result? match connect_enum(Model::Pro) { - true => Ok(Pro {}), + true => Ok(Pro { + marker: marker::PhantomData, + }), false => Err(CommunicationError::NotConnected.into()), } } @@ -836,7 +851,9 @@ impl Storage { pub fn connect() -> Result { // TODO: maybe Option instead of Result? match connect_enum(Model::Storage) { - true => Ok(Storage {}), + true => Ok(Storage { + marker: marker::PhantomData, + }), false => Err(CommunicationError::NotConnected.into()), } } -- cgit v1.2.1