Giter VIP home page Giter VIP logo

nitrocli's Introduction

pipeline crates.io rustc

nitrocli

nitrocli is a program that provides a command line interface for interaction with Nitrokey Pro, Nitrokey Storage, and Librem Key devices.

The following commands are currently supported:

  • list: List all attached Nitrokey devices.
  • status: Report status information about the Nitrokey.
  • lock: Lock the Nitrokey.
  • config: Access the Nitrokey's configuration
    • get: Read the current configuration.
    • set: Change the configuration.
  • encrypted: Work with the Nitrokey Storage's encrypted volume.
    • open: Open the encrypted volume. The user PIN needs to be entered.
    • close: Close the encrypted volume.
  • hidden: Work with the Nitrokey Storage's hidden volume.
    • create: Create a hidden volume.
    • open: Open a hidden volume with a password.
    • close: Close a hidden volume.
  • otp: Access one-time passwords (OTP).
    • get: Generate a one-time password.
    • set: Set an OTP slot.
    • status: List all OTP slots.
    • clear: Delete an OTP slot.
  • pin: Manage the Nitrokey's PINs.
    • clear: Remove the user and admin PIN from gpg-agent's cache.
    • set: Change the admin or the user PIN.
    • unblock: Unblock and reset the user PIN.
  • pws: Access the password safe (PWS).
    • get: Query the data on a PWS slot.
    • set: Set the data on a PWS slot.
    • status: List all PWS slots.
    • clear: Delete a PWS slot.
  • unencrypted: Work with the Nitrokey Storage's unencrypted volume.
    • set: Change the read-write mode of the unencrypted volume.

Usage

Usage is as simple as providing the name of the respective command as a parameter (note that some commands are organized through subcommands, which are required as well), e.g.:

# Open the nitrokey's encrypted volume.
$ nitrocli storage open

$ nitrocli status
Status:
  model:             Storage
  serial number:     0x00053141
  firmware version:  v0.54
  user retry count:  3
  admin retry count: 3
  Storage:
    SD card ID:        0x05dcad1d
    SD card usage:     24% .. 99% not written
    firmware:          unlocked
    storage keys:      created
    volumes:
      unencrypted:     active
      encrypted:       active
      hidden:          inactive

# Close it again.
$ nitrocli storage close

More examples, a more detailed explanation of the purpose, the potential subcommands, as well as the parameters of each command are provided in the man page.

Installation

In addition to Rust itself and Cargo, its package management tool, the following dependencies are required:

  • hidapi: In order to provide USB access this library is used.
  • GnuPG: The gpg-connect-agent program allows the user to enter PINs.

Via Packages

Packages are available for:

From Crates.io

nitrocli is published on crates.io and can directly be installed from there:

$ cargo install nitrocli --root=$PWD/nitrocli

From Source

After cloning the repository the build is as simple as running:

$ cargo build --release

It is recommended that the resulting executable be installed in a directory accessible via the PATH environment variable.

With Nix flakes

Running nitrocli

Repository comes with a flake.nix file, so it can be run directly:

$ nix run d-e-s-o/nitrocli
Installing system-wide

nitrocli can be installed by adding the repository flake as an input:

{
  inputs = {
    nitrocli.url = "github:d-e-s-o/nitrocli?dir=contrib/nix";
    ...
  };

  outputs = {
    nitrocli,
    ...
  }: {
    # ...
    # Where modules are defined
    environment.systemPackages = [ nitrocli.defaultPackage ];
  };
  ...
}

Shell Completion

nitrocli comes with completion support for options and arguments to them (for various shells). A completion script can be generated via the shell-complete utility program and then only needs to be sourced to make the current shell provide context-sensitive tab completion support.

$ cargo run --bin=shell-complete bash > nitrocli.bash
$ source nitrocli.bash

The generated completion script (bash specific, in this case) can be installed system-wide as usual and sourced through Bash initialization files, such as ~/.bashrc.

Completion scripts for other shells work in a similar manner. Please refer to the help text (--help) of the shell-complete program for the list of supported shells.

Known Problems

  • Due to a problem with the default hidapi version on macOS, users are advised to build and install libnitrokey from source and then set the USE_SYSTEM_LIBNITROKEY environment variable when building nitrocli using one of the methods described above.
  • nitrocli cannot connect to a Nitrokey device that is currently being accessed by nitrokey-app (upstream issue). To prevent this problem, quit nitrokey-app before using nitrocli.
  • Applications using the Nitrokey device (such as nitrocli or nitrokey-app) cannot easily share access with an instance of scdaemon/GnuPG running shortly afterwards (upstream issue). As a workaround, users can kill scdaemon after calling nitrocli with gpg-connect-agent 'SCD KILLSCD' /bye.

Public API and Stability

nitrocli follows the Semantic Versioning specification 2.0.0. Its public API is defined by the nitrocli(1) man page.

Contributing

Contributions are generally welcome. Please follow the guidelines outlined in CONTRIBUTING.md.

Acknowledgments

Robin Krahl (@robinkrahl) has been a crucial help for the development of nitrocli.

The Nitrokey GmbH has generously provided the necessary hardware in the form of Nitrokey Pro and Nitrokey Storage devices for developing and testing the program.

Purism was kind enough to help development of support for Librem Keys by providing the necessary hardware devices to test on.

License

nitrocli is made available under the terms of the GPLv3.

See the LICENSE file that accompanies this distribution for the full text of the license.

nitrocli complies with version 3.0 of the REUSE specification.

nitrocli's People

Contributors

d-e-s-o avatar robinkrahl avatar szszszsz avatar vtimofeenko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

nitrocli's Issues

Warning and confirmation strategy

nitrokey-app warns the user about insecure configurations. We should consider whether we also want to have these warnings.

  • default PINs: I don’t think we should to check that. Changing the default PINs should be common sense.
  • missing AES key: Might make sense when accessing features that need an AES key.
  • SD card not filled with random data: Would make sense to check that as it’s non-intuitive and as the user can clear that warning using the NK_clear_new_sd_card_warning function if they don’t want to clear the SD card.

These are all I could think of, but there might be more. On a related note, we have commands that may easily cause significant damage – namely the factory reset. If the admin PIN is cached, the user does not have to confirm the reset. Possible strategies:

  • Clear the admin PIN cache before dangerous operations.
  • Explicitly ask for confirmation.
  • No confirmation required.

I’d prefer the first option.

Add support for OTP URIs

Google Authenticator introduced the otpauth URI scheme to share OTP data (secret, OTP algorithm, HOTP counter, TOTP time window, issuer, …). A minimal example:

otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP

A complete example:

otpauth://totp/ACME%20Co:[email protected]?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30

We could implement this as:

  • an extension (#50)
  • a new otp subcommand (otp set-url)
  • a new input format for the secret for the otp set subcommand (i. .e nitrocli otp set 1 acme "otpauth://totp/Example:[email protected]?secret=JBSWY3DPEHPK3PXP" --format url)

I prefer option 3. The downside is that the user always has to set a name and cannot reuse the label or issuer from the URL, but as we have a very short character limit for the name, that’s probably the better solution anyway. Also, we might need a dependency for URL parsing, but I think that’s acceptable.

Not building anymore

I was trying to build latest nitrocli version on Arch Linux. It would fail with following error:
unnecessary trailing semicolon in macros.rs:131:21
$($body);*
error: could not compile 'libc'.
and a bunch of warnings regarding deprecation of cargo's use_std feature.

Use different crate for argument parsing

The author of argparse has made it fairly clear that the crate is in maintenance mode (at best; at worst I'd say it's abandoned). While it does pretty much what we want it to, there are flaws that I find increasingly annoying:

  1. We had to implement some workaround for a bug in its code that won't get fixed because the proposed fix broke backwards compatibility.
  2. The help texts it builds and displays are extremely rigid in their layout, providing a sub-par user experience (I've always dislike how we list all available commands/subcommand only on a single line) and not playing nice with extensions, of which there could be a lot.
  3. Let's face it, the way it is used is awkward and definitely not as obvious as it could be. While our code base has evolved around it fairly nicely, I still find myself trying to understand nuances related to argument handling over and over again.

So at this point I would be interested in considering alternatives. The only viable one I am aware of is structopt. In the past we've shied away from it due to bloat (without having conducted actual testing on this crate), and while that is still a concern, I'd say point 2) above tipped me over as user experience over all is still higher ranked.

We should start by prototyping use of structopt and having a look at the outcome (code structure and resulting binary size).

Dealing with multiple devices

As we now are able to detect multiple devices and select one of them to connect to, we should decide how to deal with multiple devices.

We already have the --model option and I think we should also have a --serial-number option, maybe even a --usb-path option, to select the Nitrokey device to connect to.

But what should we do if there are multiple devices but the user did not select one of them (or the user selected a model and there are multiple devices of that model)? Currently we just use the first one returned by hidapi. This is the easiest solution, but it is also potentially dangerous. My suggestion is to abort if we have more than one eligible device, asking the user to select one of them. What do you think?

CI for pull requests

As far as I see, Gitlab does not execute the CI pipeline for Github pull requests. Can you mirror the pull requests to Gitlab? If not, would it make sense to use Gitlab for pull requests?

Rust Edition 2018 support

We should adjust the application to use Rust Edition 2018.

@robinkrahl are you already using Rust 1.31 or would that be a disruption for you to upgrade? I've converted my other crates already, so I can go ahead and do it, just checking with you first as it's not urgent.

Check and set time on Nitrokey

TOTP generation requires that the Nitrokey’s clock is synced. We should provide a command to set the clock to a given value and/or to synchronize it with the system clock. We could even consider to print a warning if the user tries to generate a TOTP on an out-of-sync device.

In my opinion, this is the last major issue to take care of before the next release.

Add non-interactive passphrase query

For testing (#14), we need a non-interactive way to enter passphrases. I’d prefer to use environment variables to provide the passphrases. Regardless of the mechanism, we could either compile it conditionally for tests, or add it is a feature for all users. The downside of the latter option would be that it is much less secure than pinentry. But I think we should let the user decide how to use the tool. Even gpg provides a --passphrase option. – What do you think?

Provide bash completion

nitrocli should provide a bash completion script (and possibly also completion for other shells). As writing it manually is tedious – especially with regard to nitrocli’s complicated command structure –, we should try to generate the completion script automatically.

A quick search only yielded one tool that might do that, auto-auto-complete. I did not yet evaluate whether we could use it with our command structure.

Update summary in Cargo.toml

A command line tool for interacting with the Nitrokey Storage device.

The summary should also mention the Nitrokey Pro.

Support base32 OTP secrets

Apparently, the de-facto standard set by Google Authenticator is sharing OTP secrets as base32 strings. We should support this input type in otp set. I suggest to replace the --ascii option with a --format [ascii|hex|base32] option.

Testing the application

I think we should try to test the command-line interface using integration tests. We could either manually execute the command or use the assert_cmd crate.

The most complex part is dealing with the different scenarios 1) no device present, 2) Nitrokey Pro present, 3) Nitrokey Storage present, and potentially 4) several devices present. For nitrokey, I defined features for the device types and prefixed every test with a conditional ignore, for example:

#[test]
#[cfg_attr(not(any(feature = "test-pro", feature = "test-storage")), ignore)]
fn hotp_no_pin() {
    // ...
}

I’m not really happy with this solution, but it was the best option I could think of. What are your thoughts on this issue?

Pin should be cleared if it is known to be wrong

Hi!

I use 20 char pin and made a typo by entering 21 chars, so I get:
$ nitrocli pws status Could not access the password safe: The supplied string is too long

If I try to run this command again (or any other command requiring pin), I get this message again and no way to enter pin anew until I clear the cache manually using 'nitrocli pin clear'.

I think that in cases when pin is obviously wrong (like too long string) it should be purged from cache automatically.

nitrocli's name

First of all, thank you very much for this very helpful piece of software. We at Nitrokey depend on exactly such initiatives to get the overall project moving.

I'm wondering if the name nitrocli is the right name, especially when we anticipate that this software may become available in Linux distributions (as discussed in a separate issue ticket). I doubt because I find nitroclinot very expressive. Perhaps something like nitrokey-cli or nitrokey-toolwould be more self explanatory?

Select OTP slots by name

Hi!

Please add functionality to select OTP slots by name, e.g. if I have many slots it is more convenient to call
nitrocli otp get github
than
nitrocli otp get $(nitrocli otp status | awk '$3 ~ /github/ { print $2 }')
or remembering in what slot github's OTP lives.

Of course it may cause problems if several slots have the same name (report an error than or get all of them) or if a slot name is a number within valid slot number range (for such cases a suboption indicating whether slot name or slot number was requested may be added).

Update documentation

Update the documentation (README + man page) for the 0.2.0 release:

  • config
  • otp
  • pws
  • storage
  • general
  • build instructions
  • formatted man page

Structure and naming of new commands

The current command handling code has two limitations:

  • It does not support arguments.
  • It only supports command names that are valid function names in Rust.

There are some good argument parsing libraries for Rust, but they are rather heavy-weight.

I think we currently need these commands (grouped by topic):

General

  • status: return general and model-specific information (firmware version, serial number, retry counts, storage status for NK Storage)
  • change-pin: change user or admin PIN
  • unlock-pin: unlock the user PIN
  • lock: lock the device (i. e. password store and volume, if applicable)

Configuration (config)

  • get: read the current configuration
  • set: change the configuration

OTP (otp)

  • get: generate a OTP
  • set: configure a OTP slot
  • clear: clear a OTP slot
  • status: display all slots

Password Safe (pws)

  • status: display the status of all alots
  • get: get the data stored on one slot
  • set: configure a slot
  • clear: clear a slot

Storage (storage or volume)

  • open: enable encrypted volume
  • close: disable encrypted volume

So my questions are:

  • How should we name the commands? We could use names like get-otp or otp-get. But I think the most intuitive solution would be to have subcommands (like opt [get|set] or pws [status|get|set|clear]).
  • How should we parse the arguments? Should we implement it from scratch or use one of the available libraries?

Hanging Nitrokey when switching between nitrocli and GnuPG

You already mentioned this problem in this a request:

Btw., this has bugged me for ages: does your nitrokey "hang" frequently? E.g., when I am using gpg and then nitrocli the red light just stays on and the key won't do anything or take ages to respond (sometimes it just responds with garbage after a long time). I have to disconnect and reconnect (physically) to get it into a working state again. I am still on firmware version 0.47 (but plan to upgrade soon). I think later today I can check whether my testing stick has the same problem.

I could not reproduce this at the time (as I only used my Storage for development and my Pro for GnuPG), but since I use nitrocli on my Pro too, I experience the same problem. Today I managed to reproduce it. This is a tracking issue for the upstream issue.

Supporting Nitrokey FIDO2?

We are currently discussing adding support for Nitrokey FIDO2 into our software. The device uses a FIDO2 interface and therefore (the current) libnitrokey doesn't support it (yet). One option is to add support to libnitrokey. Another option is to introduce a separate library. Actually any 3rd party FIDO2 library may be good enough. But first of all I would like to understand if you are interested in adding support for Nitrokey FIDO2 to nitrocli.

Dependency management

Before I comment on the issue, I’d like to know your goals for dependency management. My guess is that you are including the dependencies in the nitrocli repository to ensure that cargo does not download unsigned and unverified code from third parties. Is that correct?

Hidden volumes

I started looking into implementing hidden volume support. I first wanted to get the opening and closing done. I was thinking about adding a reveal and hide subcommand to the storage command (names up for debate).
I am not sure about the creation of a hidden volume, though (which likely will have to come eventually and I'd like to have a story for it; I haven't checked if there is something else that we would need to support). storage create seems a ambiguous. storage create-hidden somewhat too long and not in-line with the other subcommands? Not sure.

(I did ponder creating a new top-level command but could not really work that nicely)

The other question is whether to open the encrypted volume if it is not already opened or not (the hidden volume resides inside the encrypted volume and hence the latter must have been opened to begin with).
My take would be to not open the encrypted volume but rather fail the operation. The main reason is that I would like to have symmetry between reveal and hide, and when we hide we have no information as to whether the encrypted volume was already opened before or whether that was done as part of reveal.

Do you have thoughts on this matter, @robinkrahl?

macOS support?

Hi!

I'm trying nitrocli on macOS Mojave with my Nitrokey Storage, without success so far. All I get is:

$ nitrocli status
hidapi error: Device not found.

Is macOS supposed to be supported? I installed hidapi with brew and nitrocli with cargo install.

Upstream Gentoo ebuild

We have a Gentoo ebuild that I recently got up to speed again but it has to be imported by hand and it would be much nicer to have this functionality in the official Gentoo Portage tree or at least some semi-official overlay.

We should also add instructions on how to package for Gentoo to doc/packaging.md.

storage subcommand structure

I am considering changing the structure of the storage subcommand. Currently we have:

  • storage
    • status
    • close
    • open
    • hidden
      • create
      • close
      • open

I think organizing the commands as follows would be better:

  • storage
    • status
    • encrypted
      • close
      • open
    • hidden
      • create
      • close
      • open

The background is that I can't seem to find a good way to fit the changing of the read-write status of the unencrypted volume in the existing design. Also, if we later add support for changing the read-write state of the encrypted volume (I think that needs nitrokey support first, I've added a task), we will clash if we just have, say, a set in the storage subcommand.

In a way the proposed structure makes more sense, because logically there are three distinct volume types the user cares about. Now we could argue that the hidden volume is inside the encrypted volume and that should be reflected in there, but to me that's more of an implementation detail (although it has a bit of relevance to the user) and that would just make the structure ugly and hard to remember (nitrocli encrypted hidden what?).

I guess we could make do with the existing structure, at least for the two commands mentioned above, e.g., by creating a set command that accepts values such as unencrypted-ro, unencrypted-rw, encrypted-ro, encrypted-rw but I don't think that is intuitive.

Comments? @robinkrahl ?

Perhaps while at it...I am a bit confused about the comment for NK_set_encrypted_read_only:

	/**
	 * Make encrypted volume read-only.
	 * Device hides encrypted volume for a second therefore make sure
	 * buffers are flushed before running.
	 * Firmware range: v0.49 only, future (see firmware release notes)
	 * Storage only
	 * @param admin_pin 20 characters
	 * @return command processing error code
	 */

So I guess that function is not available on recent firmware. But do I understand correctly that the command may come back in the future?

Tag and sign releases

Having tags for version releases would make it easier to navigate the repository. Signing these tags would make it easier to verify the code, especially as GitHub seems to throw away commit signatures from pull requests (probably because they are rebased).

installable binaries for Windows and macOS

I believe it would be convenient for users who don't want to compile the sources themselves, to provide pre-compiled binaries in the form of an installable software package. Would you be interested in distributing such? I assume it would require an appropriate packaging, perhaps an installation wizard. If you could prepare such, we (Nitrokey UG) would be happy to sign the packages with our software signature certificate.

Discussion: Validation of user input

Most of the user input provided via arguments or options is subject to restrictions. These restrictions can be fixed (e. g. a hexadecimal string must always have an even number of hex digits) or variable (e. g. the current Nitrokey Pro has 3 HOTP slots, but the next version might have 5). To which degree should we validate such input in nitrocli (that is also validated by libnitrokey or the firmware)?

Advantages of validation in nitrocli are better error messages and failing early. Disadvantages are that we might be less compatible or might make wrong assumptions.

Currently we perform no validation. My suggestion would be to perform basic validation on fixed restrictions (hex string), but no validation for variable restrictions (slot count) unless libnitrokey gives us the required information (e. g. a TOTP_SLOT_COUNT constant).

Examples for the current error messages:

Invalid hex string:

$ nitrocli otp set 0 test test
Could not write OTP slot: Unknown

Invalid slot:

$ nitrocli otp set 30 test test
Could not write OTP slot: InvalidSlot

Support for OTPs on the Nitrokey Pro?

I’m about to write a command-line tool to generate one-time passwords on my Nitrokey Pro. I already wrote a Rust binding for libnitrokey (crate nitrokey). Before I create yet another Nitrokey CLI tool: Would you be interested in pull requests adding support for one-time password using libnitrokey? (I’m not keen on dealing with the raw hidapi communication, so that would not be an option for me.)

Going 1.0

I am cautiously confident that the code is moving towards a state where we can say it won't change in completely unexpected ways anymore (our experience with argparse is overall positive so we are unlikely to change that; nitrokey-rs is obviously there to stay; we have our testing story flushed out). As such, perhaps it is time to roughly sketch out what we see as requirements for a 1.0 release candidate.

The two big items I see are:

  • tests for all the existing commands
  • extension support needs to be ironed out and implemented fully

I don't think we need to have support for all the features that nitrokey-app or libnitrokey provides. However, I would like to see the following:

  • hidden volume support
  • everything that is necessary for the initial setup of a Nitrokey device as it is shipped from Berlin
    • I count into that the ability to upgrade the firmware of storage devices (I don't think we need to support the entire workflow, but putting the device into upgrade mode should likely be included)
    • make the unencrypted volume writable
    • (I am probably missing something)

We should also have at least considered the remaining features a Nitrokey supports, and have confidence that they will somehow fit into the existing command scheme or can be implemented as extensions in a sensible way.

It would be nice to only depend on 1.0 crates ourselves, but that is obviously out of our control to a large extent. However, nitrokey-rs is still a bit in flux and I would definitely wait until @robinkrahl has not planned any more incompatible changes.

If anybody has any thoughts/additions, I'd be happy to hear them.

nictrocli can't find device

Hi,

I'm on archlinux and I have the problem that the nitrocli doesn't detect my "Nitrokey Storage 2" even so it is connected and the normal nitrokey-app sees it. i tried to get some more information with verbose output:

╰─ nitrocli -vvv status 
[Thu Aug 22 15:06:22 2019][DEBUG_L1]	Connection success: 0 ()
[Thu Aug 22 15:06:22 2019][DEBUG_L1]	Connection success: 0 ()
[Thu Aug 22 15:06:22 2019][DEBUG_L1]	Disconnection: handle already freed: 1 ()
[Thu Aug 22 15:06:22 2019][DEBUG_L1]	Disconnection: handle already freed: 1 ()
Nitrokey device not found

Usage on a GUI-less server

Hi!

Is it possible to use nitrocli in a GUI-less / init 3 Linux environment? I tried to simulate it in an Ubuntu 19.04 Docker container, and got this error:

root@a1f753f5d989:/# nitrocli pws get 0
83918950 Inappropriate ioctl for device <Pinentry>

Any ideas? Pinentry run separately works apparently. Getting status from the Storage device works as well. gpg-connect-agent also seems to work.

I tried to use /usr/bin/pinentry-tty (as here), but got other error:

83886340 Invalid IPC response <Pinentry>

Perhaps, alternatively, is it possible to disable gpg-connect-agent usage, and make nitrocli ask the PIN directly? E.g. via some kind of switch?

Full install and execution log attached:
nitrocli.init3.log

Connected: support request.

Configuration file

What do you think about having defaults for at least some of the arguments in a configuration file? For example, once we have a --serial-number option, I’d like to be able to set the serial number of my production device for all nitrocli calls.

An implementation could use config for the file parsing and app_dirs to get XDG-compliant paths. (This would pull in serde and nom.)

Do we want to support old firmware versions?

I’m currently implementing support for setting the access mode (read-only, read-write) for the Storage. Here we have two issues:

  1. Setting the access mode for the encrypted storage is only supported in firmware version 0.49 (0.50 released on 2018-01-21).
  2. Setting the access mode for the unencrypted storage required the user PIN instead of the admin PIN in firmware versions 0.50, 0.48 and below (0.51 released on 2018-06-14).

Do we want to support the old behavior? On the one hand, it is code that I cannot test, and there is no technical reason not to upgrade the firmware. On the other hand, people might not want to update the firmware unless required, especially as the process can be tricky for new users.

I think it is reasonable not to support old firmware versions, especially if they are older than 6 months (as in this case). Do you agree?

Edit: Of course I’m only talking about the Storage where users can upgrade the firmware. For the Pro, we should support as many firmware versions as possible.

Nitrocli-0.2.4 fails to parse some base32 OTP secrets

Hi there!

I found an base32 secret which nitrocli fails to parse (it is a test example based on an invalidated real one):

$ nitrocli otp set -f base32 5 test FBILDWWGA23ZG5NVMEWT57M7RXXDYXTC
Could not write OTP slot: The supplied string is not in hexadecimal format

Oathtool is happy with this secret:
$ oathtool --totp --base32 FBILDWWGA23ZG5NVMEWT57M7RXXDYXTC
753834

If I convert it to hex via a shell script nitrocli is happy as well:
$ nitrocli otp set 5 test $(echo -n FBILDWWGA23ZG5NVMEWT57M7RXXDYXTC | base32 -d | xxd -p)
and then nitrocli otp get 5 returns the same result as oathtool --totp -b within the same time slot.

Looks like base32 parser is somehow broken for some inputs (e.g. if I replace first F to A it works).

Discussion: Advanced functionality

How should we deal with advanced functionality that goes beyond just providing access to the Nitrokey’s features? Let me illustrate this with some examples:

  1. Inspired by passmenu, I’d like to have something like otpmenu that lets the user select an OTP slot via dmenu, generates an OTP and copies it to the clipboard.
  2. As otp status is rather slow, I’d like to have something like otpcache that caches the output from otp status to speed up queries for 1.
  3. Many applications provide QR codes for OTP configuration. I’d like to have a command that allows me to select a screen region (import), tries to identify and read a QR code in this region (zbar) and then configures a slot on the Nitrokey based on the data from the QR code.

Stuff like 2. could be easily implemented as a nitrocli subcommand (though this would pollute the global command namespace). For stuff like 1. and 3., that’s harder as it would pull in many dependencies only for a niche task.

Possible solutions:

  1. Ship all these as standalone programs.
  2. Have a contrib folder with scripts like these (similar to pass).
  3. Provide some kind of plugin mechanism for subcommands (similar to cargo).

While 3. might be interesting to implement, it is totally not worth the effort. I just listed it for the sake of completeness.

I tend to prefer option 2 as it would make it easier to distribute the tools and I think they could be useful for many nitrocli users, but option 1 would be fine too. What do you think?

Add option for forgetting pin after command

Hi!

It would be nice to have an option to forget pin for commands requiring pin/password entrace. Of course I can call nitrocli pin clear after each such command, but it would be easier to do with an option.

Maybe it would be a good idea to have a config file support as well where users can specify their preferences including this option.

Additional functionality

Having just gone through the process of getting a new Nitrokey set up I feel that at least the following functions also need to be supported:

  • changing of the read-write state of the unencrypted volume
  • setting of the user & admin PIN
  • enabling of firmware upgrade mode
  • hidden volumes
  • change of update (firmware?) PIN

It is not quite clear to me whether the user & admin PIN could be set through GnuPG (which may alleviate the need for the second item), we may want to try that out

Doesn't compile on macOS

I do have the problem that it doesn't compile on macOS. I am sure I make something wrong, but I have no clue what its .... Maybe you could help ...

cargo build --release
warning: package replacement is not used: https://github.com/rust-lang/crates.io-index#hid:0.4.0
Compiling nitrocli v0.1.0 (file:///nitrocli/nitrocli)
error: linking with cc failed: exit code: 1
|
= note: “cc” “-m64” “-L” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib” “/nitrocli/nitrocli/target/release/deps/nitrocli-e29bae10c035e61e.0.o” “-o” “/nitrocli/nitrocli/target/release/deps/nitrocli-e29bae10c035e61e” “-Wl,-dead_strip” “-nodefaultlibs” “-L” “/nitrocli/nitrocli/target/release/deps” “-L” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib” “-l” “c” “/nitrocli/nitrocli/target/release/deps/libhid-488dd42f7cb67d27.rlib” “/nitrocli/nitrocli/target/release/deps/libhidapi_sys-d6356264c78813c0.rlib” “/nitrocli/nitrocli/target/release/deps/liblibc-39e9fe8562e55f31.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libstd-438eba4cd7d88a45.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libpanic_unwind-00160610bfa2c7b4.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libunwind-88eece318c5ccb15.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/librand-646fe8114e6965a2.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcollections-7d6da376f6405c93.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liballoc-ab03bba0be78edaa.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liballoc_jemalloc-3d46a711e5badb84.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/liblibc-31c7158cd96c571c.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libstd_unicode-a732f07ce6fa7392.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcore-ee2a935baf6741f5.rlib” “/Users/peacekeeper/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/x86_64-apple-darwin/lib/libcompiler_builtins-53f5ee584666574a.rlib” “-l” “hidapi” “-l” “System” “-l” “resolv” “-l” “pthread” “-l” “c” “-l” “m”
= note: ld: library not found for -lhidapi
clang: error: linker command failed with exit code 1 (use -v to see invocation)
error: aborting due to previous error(s)
error: Could not compile nitrocli.

Pinentry error

at

nitrocli --version
nitrocli 0.3.1

gpg --version
gpg (GnuPG) 2.2.17
libgcrypt 1.8.5

hidapi-0.8.0

uname -r
5.4.17-ck

when I
nitrocli pws status I get
83918929 No such file or directory <Pinentry>

might be because i dont have ccid installed, but thats a wild guess.

Add `cargo fmt` to the CI pipeline

Good to have CI in place! One additional check could be cargo fmt -- --check which displays style violations based on the rustfmt.toml. Currently, the biggest issues are whitespace (rustfmt only allows single empty lines) and attribute formatting (rustfmt uses multiple items per line for #[deny(...)]). So the question is whether you agree with these style changes. (As far as I see, they cannot be configured.) Being able to run rustfmt to quickly check e. g. the correct indentation would be quite useful.

Import and export of OTP secrets (CSV or PSKC)

In order to allow better integration with 3rd party software such as PrivacyIdea and KeyIdentity the import and export of OTP secrets in an appropriate format is desired. Common formats are CSV and PSKC.

Do you see nitrocli as the right tool to support such?

Obviously export is only possible during generation of the secret (in the software) and it doesn't mean to export a secret already configured in the Nitrokey.

PIN reuse across multiple devices

nitrocli does not keep track of the device it connects to. If a user switches between two devices without clearing the passphrase cache, nitrocli will try to connect to device A using the cached passphrase for device B. This is not a major issue, but I think we could improve nitrocli’s behavior by

  • adding the serial number (and maybe the model?) of the connected Nitrokey to the pinentry dialog, and
  • making sure that we do not reuse a cached passphrase for another device.

I was thinking of two ways to implement the second point: Firstly, we could add the serial number to the ID of the cached passphrase (e. .g nitrocli:admin:deadbeef instead of nitrocli:admin). This would make it harder to clear the cache with the clear command as we either would have to keep track of the passphrase IDs or could only clear the passphrases for the current device. Secondly, we could store the serial number together with the stored passphrase (with a separate cache ID or as a prefix for the passphrase). But it is unclear whether PRESET_PASSPHRASE is applicable for custom passphrases, and it is not enabled by default. So we cannot set the passphrase without user interaction.

Support factory reset

I’m unsure how to name the factory reset command: Based on the existing commands, reset is a fitting choice. On the other hand, it might be beneficial to have a name that is more explicit, like factory-reset. Given that we also have to name the command to build the AES key, we probably have to start using more complex command names anyway. What do you think?

Support the password safe

nitrocli should support the password safe (PWS). The password safe is unlocked using the user password. Once it is unlocked, any client can access the PWS without further authentication. The PWS can be locked using the NK_lock function. On the Pro, NK_lock does not have side effects. On the Storage, NK_lock also closes the encrypted device. I requested a lock function for the PWS without side effects (see Nitrokey/nitrokey-storage-firmware#65), but currently, there is none. (Ideally the PWS communication would be protected by a temporary password similar to the OTP communication.)

So we have three options:

  • Do not support the PWS until we can lock it without side effects.
  • Do not lock the PWS after every use, leaving it unprotected until the device is removed or the machine is restarted.
  • Lock the PWS after every access, potentially closing the encrypted volume. We could try to check whether the volume is enabled and warn the user.

What do you think?

Dependency management

The topic has come up in the past, mostly here and here: whether to keep the current repository structure with vendored dependencies or not.

I think I've come to a point where I am ready to remove checked-in dependencies and move nitrocli/* into the repository's root. The main reasons for that: even with vendored dependencies cargo insists on an internet connection (or at least I never got that working to my satisfaction without) and dependency management is too cumbersome with the increasing number of dependencies we have.
As part of the removal, I'd also remove Cargo.lock from the repository and trust dependencies and their updates won't break the build (i.e., be semver compliant) and won't introduce malicious code.

Does anybody have concerns about such a move? @robinkrahl @jan23 @alex-nitrokey

Otherwise I'll probably go ahead and experiment with such a move on devel.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.