| Commit message (Collapse) | Author | Age |
|
|
|
|
|
|
|
|
|
| |
The library ultimately taking care of communicating with the Nitrokey
device, libnitrokey, unconditionally expects hexadecimal strings
supplied as part of the configuration of an OTP slot to have an even
number of bytes.
Users should not be aware of this detail and so with this change we take
care of padding the supplied string with a leading zero to make such a
configuration go through without an error.
|
|
|
|
|
|
|
|
|
|
|
|
| |
When reading a secret in ascii or base32 format from the user, we
perform a conversion of the potentially decoded string into hexadecimal
bytes, because that is what libnitrokey expects.
The format string we used in the conversion, however, did not account
for padding with a leading zero for single digit results. E.g., the
newline/line feed symbol '\n', which has a decimal value of 10 would
result in the string 'a' being produced, whereas '0a' would be the
correct result.
This change corrects the format string to fix this problem.
|
|
|
|
|
|
|
|
|
| |
The otp set subcommand allows for three different formats in which the
user may pass in the secret, with the default being hexadecimal. By
convention we convey the default being used in the help text to the
respective command, but that default was missing here.
To that end, this change makes sure to include the default format being
used in corresponding help text.
|
|
|
|
|
|
| |
This change introduces a constant for the frequently used string
"nitrocli" to the program and replaces usages of those strings with
references to the constant.
|
|
|
|
|
|
|
|
|
|
|
| |
Subcommands of the encrypted and unencrypted commands were found to have
a wrong help text displayed. The reason for that behavior was that the
subargs were are constructing as part of the argument parsing process
were missing the command being requested and instead containing only the
subcommand.
This change fixes this deficiency. It also adds a test ensuring that the
"Usage" string displayed in the help text of each command and subcommand
contains the proper arguments.
|
|
|
|
|
|
|
|
|
|
| |
Similar to the with_*device functions introduced in a previous change,
this change introduces a with_password_safe function that is a short
hand for opening the Nitrokey, retrieving a handle to the password safe,
and invoking a user-supplied function on it.
This function will allow us to prevent life time inference problems
caused by passing around a PasswordSafe object, which will contain an
additional reference (and with that, lifetime) in nitrokey version 0.4.
|
|
|
|
|
|
|
| |
With an upcoming change we will require an ExecCtx in one of the
op functions passed to the with_* and try_with_* functionality. To
allow for such cases, this change adjusts the signature of those
functions to provide a reference to such a context.
|
|
|
|
|
|
|
|
|
|
|
| |
This change introduces a new trait, TryInto, to the crate. In the future
this trait will allow us to keep a flexible set of error result types
from the various try_with_* functions, which use a certain nitrokey
error variant to check for the entry of a wrong secret.
Note that while a TryInto trait exists in Rust's standard library, that
was not found to be helpful because we have no way to define it for
nitrkey crate's error type. Because of that, we will always have a
mismatch between our internal error and std::convert::Infallible.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The upcoming nitrokey 0.4 release changes the way a device handle can be
acquired, requiring a manager instance for doing so in an attempt to
prevent users from opening multiple sessions (which is not something
that libnitrokey supports).
A straight integration of the reworked API surface into our program
would severely complicate the architecture because of the additional
requirement of keeping a manager object around while a device is being
used.
To make the program more amenable to those changes in nitrokey, this
patch reworks the way we interact with a device handle: instead of
passing the device object around we pass in the functionality making use
of it in the form of a function. In more concrete terms, instead of
retrieving a device handle via get_device() we now have a with_device()
function that takes care of opening the device and then passing it to a
user-provided function.
|
|
|
|
|
|
|
|
|
| |
The try_with_* and authenticate functions accept a user-supplied
function to work with. Currently this function is declared as Fn. That,
however, is unnecessarily restrictive.
With this change we declare said function an FnMut instead, which allows
it to potentially capture variables from its environment in a mutable
manner.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We recently fixed a compilation failure in some test code caused by a
use declaration that was ultimately unused. To this point we were under
the impression that there was a set of lints that were known to be
potentially changing in backwards incompatible ways while others would
not. Discovery of unused use declarations or symbols was always assumed
to fall into the latter category.
Because such a build breakage due to semantic change in what a lint can
detect by now is a repeated pattern (with dire consequences), this
change downgrades all 'deny'-style lints to warnings in order to prevent
similar problems in the future.
|
|
|
|
|
|
|
|
| |
For functionality that explicitly works with the storage device we emit
an error message stating that a "Nitrokey Storage" device could not be
found. When the user chooses the model using the -m/--model argument
that is not the case.
With this patch we adjust the error message printed.
|
|
|
|
|
| |
This patch replaces two cases where we use Result::or_else over the more
idiomatic (and shorter) Result::map_err for converting errors.
|
|
|
|
|
|
|
|
|
|
| |
This change removes the explicit change of the global allocator to the
system allocator that we introduced a while back.
The reason this was needed in the past was due to Rust's use of jemalloc
in the default configuration, which increases binary size quite
significantly. However, with Rust issue #36963 fixed, jemalloc is now an
explicit opt-in and the system allocator is the default choice --
rendering our explicit change rather pointless.
|
|
|
|
|
|
|
|
|
|
|
| |
When the gpg-connect-agent binary is not available on the system we
report an error that is really only hinting at the problem and without
knowing internals it is hard to guess what may be wrong:
$ nitrocli pws get 0
> IO error: No such file or directory (os error 2)
This change adjusts the code to make the error less ambiguous and more
to the point.
|
|
|
|
|
|
|
| |
This change adds support for changing the read-write mode of the
unencrypted volume. To do so, we introduce a new top-level command,
unencrypted, with a new subcommand, set, that accepts the new mode of
the volume.
|
|
|
|
|
|
|
|
|
| |
This change rewords the error message that is emitted if the lock
command fails. The old message was incorrectly stating a problem with
the retrieval of the device's status.
While at it, also slightly rephrase the description for the hidden
command to be more in line with that of the other storage commands, and
replace lowercase 'nitrokey' with a capitalized one in a few comments.
|
|
|
|
|
|
|
| |
The --ascii option of the otp set subcommand has been deprecated a while
in favor of --format. As the next release is slated to be a major one
breaking backwards compatibility, this change removes this option for
good.
|
|
|
|
|
|
|
|
| |
This change is the last step in the process of restructuring the storage
command. In particular, now that functionality pertaining hidden volumes
has been moved out into a dedicated top-level command, it renames said
command to encrypted, because dealing with the encrypted volume is the
only functionality it provides.
|
|
|
|
|
|
| |
This patch marks the next step in the process of restructuring the
storage command. Specifically, it promotes the storage hidden subcommand
to a top-level command, hidden.
|
|
|
|
|
|
|
|
| |
In an attempt to rework the structure of the storage command to better
accommodate future requirements for allowing to change the read-write
state of the unencrypted volume (as well as potentially the encrypted
one), this change removes the storage status subcommand and merges its
output into the storage command.
|
|
|
|
|
|
|
|
|
|
| |
When a PIN is changed using the pin set command, the last action is to
confirm the operation with the previously used PIN. This step will cause
this PIN, which is now stale and no longer valid, to be cached, which in
turn can cause follow up command using the same PIN type to use this
wrong cached entry for authentication.
To fix this problem, this change explicitly clear the PIN entry from the
cache after the PIN has been changed.
|
|
|
|
|
|
|
|
|
|
|
|
| |
So far we have cached secrets in gpg-agent(1) whenever that made sense
to do (i.e., for the two PINs in most contexts but not for passwords).
While there is reason to believe that such caching is desired by the
majority of users, not everybody has a use for it.
To give users an opportunity to opt out of such caching, this change
introduces a new environment variable, NITROCLI_NO_CACHE, that, when
present in the environment, instructs the program to bypass the cache
for all operations that require a secret and to instead inquire such
secrets each time they are needed.
|
|
|
|
|
|
|
|
|
|
| |
The input to the Enum macro is supposed to resemble the definition of an
enum in Rust code. When manually defining an enum (or a struct for that
matter), we typically terminate all branches with a comma, and don't
just omit that on the last line.
To mirror this behavior, this change adjusts the Enum macro to accept
(and in fact, require) a comma-terminated last line as well, as opposed
to not accepting it as had been the case so far.
|
|
|
|
|
|
|
|
|
| |
Macros typically should reference types by their full path and not
assume that they are in scope wherever the macro is expanded. We did
missed one spot where AsRef was not fully qualified in the Enum macro.
While that is not much of an issue here (and there may be more
occurrences, e.g., in the auto derives) lets fix that up for the sake of
consistency.
|
|
|
|
|
|
|
|
|
|
| |
With Rust 1.35 we get compile errors due to doc comments that are added
to macro invocations but not actually included in the expanded output.
The rustc wrongly assumes that we want to document the resulting code
and not just provide details about the invocation itself.
This change explicitly allows for those cases. Alternatively we could
have "downgraded" the doc comments to normal comments or removed them
altogether. There is little difference between those alternatives.
|
|
|
|
|
| |
This change adds a test case for the -V/--version option to the suite of
tests.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Due to a bug in argparse [0], custom stdout and stderr settings are
ignored when using argparse::Print, as we currently do for the --version
option. This patch adds a workaround for this problem: Instead of using
argparse::Print, we use argparse::StoreTrue for the --version option.
The argument parsing will fail as the command is missing, but the
version variable will still be set to true if the version option was
set. So we ignore the parsing result and discard the argparse output if
the version variable is set.
[0] https://github.com/tailhook/rust-argparse/pull/50
|
|
|
|
|
|
|
|
|
| |
The split between the parse_arguments and the handle_arguments functions
is not really useful for reasoning about the code. In fact, it just adds
additional overhead in the form of complex function signatures into the
picture.
As it provides no real other value, this change merges the functionality
of both functions into a single one: handle_arguments.
|
|
|
|
|
|
|
|
|
| |
To be able to decide whether to print the argparse output depending on
the result of the argument parsing, this patch wraps stdout and stderr
in a BufWriter before invoking argparse. Our BufWriter implementation
only writes to the inner Write if the flush method is called. This
allows us to decide whether the buffered data should be written or
silently dropped.
|
|
|
|
|
|
|
|
|
|
| |
We have introduced the parse function to unify the common parsing
related tasks. In that vein, this change goes one step further and
adjusts the function to actually consume the ArgumentParser object used
by it.
All clients using this function actually do not access the parser
afterwards, and, in fact, some of them have to explicitly drop it
because of borrow conflicts with "referred" arguments.
|
|
|
|
|
| |
This patch changes the error handling in the args' module parse function
to use the Result's map_err instead of a more verbose if let expression.
|
|
|
|
|
|
|
|
| |
The factory reset only clears the slot status. The slot content is
overwritten with random data. Therefore accessing a PWS slot after a
factory reset returns garbage data. We fixed this by always querying
the status before accessing the PWS. This patch adds a corresponding
test case.
|
|
|
|
|
|
|
|
|
|
|
|
| |
The Nitrokey devices do not check whether a PWS slot is programmed
before accessing it (upstream issues [0] [1]). Until this is fixed in
the firmware, we have to manually check the slot status in pws get. This
could have been done in libnitrokey or the nitrokey crate, yet this
would lead to unnecessary commands if we check multiple fields of a slot
at the same time.
[0] https://github.com/Nitrokey/nitrokey-pro-firmware/issues/56
[1] https://github.com/Nitrokey/nitrokey-storage-firmware/issues/81
|
| |
|
|
|
|
|
|
| |
After performing the factory reset, we also build the AES key so that
the device is fully usable. Due to timing issue, we have to add a delay
between the factory reset and building the AES key.
|
|
|
|
|
|
|
|
| |
The -V/--version option prints the nitrocli version to stdout and exits.
In the future, it should also print the used libnitrokey version, but as
the required function is only available with nitrokey 0.3.2 and as the
current interface does not reflect the latest change in version naming,
I skipped that in this patch.
|
|
|
|
|
|
|
| |
The duplicate_associated_type_bindings lint seems to have been removed
with the Rust 1.32 release.
This change removes the lint from the program to prevent the newly
introduced warning from being emitted.
|
|
|
|
|
|
|
|
|
| |
This change adds tests for the lock command. For the Nitrokey Pro we
cannot test too much because the only side-effect is that the password
safe is closed and it will be opened automatically again by virtue of
our non-interactive testing methodology.
For Storage devices we verify that the encrypted volume is closed, which
is a documented side-effect.
|
|
|
|
|
|
|
| |
This change adds a test for the creation, opening, and closing of a
hidden subvolume. In order to support that in a non-interactive fashion,
we introduce and honor the NITROCLI_PASSWORD environment variable, that
prevents an interactive password query.
|
|
|
|
|
|
|
|
|
| |
With this change we implement the storage hidden subcommand. We support
creation, opening, and closing of hidden volumes.
Note that the opening of a hidden volume automatically closes any opened
encrypted volumes and vice versa. To that end, we force file system
level caches to disk even from the storage open and storage hidden open
commands.
|
|
|
|
|
|
|
|
|
| |
This change introduces a new subcommand to the storage command called
'hidden'. This subcommand can be used to interact with hidden volumes.
Right now we support three operations pertaining hidden volumes: create,
open, and close.
This patch merely provides the infrastructure for parsing the commands
and all their arguments, it does not yet implement them fully.
|
|
|
|
|
|
|
|
|
|
|
|
| |
With the required interface for secrets well defined, this change
introduces a second secret type in addition to PINs: passwords. Similar
to a PIN, a password can contain pretty arbitrary characters but
passwords can be retried repeatedly, whereas PINs cause a lockout after
a certain number of failed attempts.
Our first use case for passwords will be for hidden volumes. For those,
we do not want to gpg-agent to cache entries and so a password entry
indicates that it is not to be cached through the previously introduced
mechanism for optional caching.
|
|
|
|
|
|
|
|
| |
Another commonality between a password and a PIN is that they typically
both have a minimum length.
To accommodate for this requirement, this change introduces another
method to the SecretEntry trait that represents the secret's minimum
character length.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Currently, when we enter a secret (i.e., a PIN) through the pinentry
module, this PIN will automatically be cached and not asked from the
user again on subsequent inquiries. However, caching may not always be
desired. For the upcoming support of passwords used in conjunction with
hidden volumes, we do not want any caching because different passwords
can be entered for different volumes and the user's intention is not
clear until a password has actually been entered.
To accommodate this use case, this change modifies the signature of the
SecretEntry trait's cache_id method to return an optional cache ID. If
none is returned, caching of the entered secret is disabled.
|
|
|
|
|
|
|
|
|
| |
We do not know what kind of data future implementers of the SecretEntry
trait may want to return. For all we know these could just be static
strings, in which case the forced conversion into a String by virtue of
the return type is wasteful.
To be more flexible in the future while gaining some consistency, this
change makes all those trait's methods return a Cow object instead.
|
|
|
|
|
|
|
|
|
|
|
|
| |
Now that we have introduced the notion of a secret abstracting over
whether something is a PIN or a password in terms of terminology, we
need to define what makes a secret in code. From the pinentry module's
perspective, the commonality between the two is that they both can be
entered through a dialog containing a prompt and a description, and they
can be cached.
This change introduces a trait, SecretEntry, that defines methods
representing those properties. Right now only the existing PinEntry
struct implements this trait.
|
|
|
|
|
|
|
|
|
|
|
|
| |
In the past we have worked solely with PINs. PINs in our (or rather, the
Nitrokey's) sense are not necessarily numbers but they can be reasonably
short in length, because they can only be retried a limited number of
times.
In the future, however, we will introduce the notion of a password,
which does not carry such a restriction.
The commonality between the two is that they are secrets and so with
this change we refer to secrets -- rather than PINs -- in places where
both passwords and PINs can conceptually be used.
|
|
|
|
|
|
| |
Various functions in the pinentry module contain an arguably redundant
'_pin' suffix in their name. Examples include inquire_pin and clear_pin.
This change removes this part from their names.
|
|
|
|
|
|
|
|
|
| |
The functionality we have in place for choosing a PIN can arguably be
moved into the pinentry module: it can be considered logic directly
related to working with PINs or secrets and that has no dependencies to
unrelated modules of the program.
This patch moves the choose_pin and check_pin functions into the
pinentry module.
|