diff options
-rw-r--r-- | nitrocli/doc/nitrocli.1 | 11 | ||||
-rw-r--r-- | nitrocli/src/args.rs | 10 | ||||
-rw-r--r-- | nitrocli/src/commands.rs | 22 |
3 files changed, 39 insertions, 4 deletions
diff --git a/nitrocli/doc/nitrocli.1 b/nitrocli/doc/nitrocli.1 index fdbdb86..21aab03 100644 --- a/nitrocli/doc/nitrocli.1 +++ b/nitrocli/doc/nitrocli.1 @@ -47,12 +47,17 @@ the current time. Therefore, the Nitrokey clock must be synchronized with the clock of the application that requests the one-time password. .TP -\fBnitrocli otp get \fIslot \fR[\fB\-a\fR|\fB\-\-algorithm \fIalgorithm\fR] +\fBnitrocli otp get \fIslot \fR[\fB\-a\fR|\fB\-\-algorithm \fIalgorithm\fR] \ +\fB[\-t\fR|\fB\-\-time \fItime\fR] Generate a one-time password. \fIslot\fR is the number of the slot to generate the password from. \fIalgorithm\fR is the OTP algorithm to use. Possible values are \fBhotp\fR for the HOTP algorithm according to RFC 4226 and \fBtotp\fR for the TOTP algorithm according to RFC 6238 (default). +Per default, this commands sets the Nitrokey's time to the system time if the +TOTP algorithm is selected. +If \fB\-\-time\fR is set, it is set to \fItime\fR instead, which must be a Unix +timestamp (i.e., the number of seconds since 1970-01-01 00:00:00 UTC). This command might require the user PIN (see the Configuration section). .TP \fBnitrocli otp set \fIslot name secret \ @@ -120,14 +125,18 @@ These two options are mutually exclusive. Configure a one-time password slot with a hexadecimal secret representation: $ \fBnitrocli otp set 0 test\-rfc4226 3132333435363738393031323334353637383930 \-\-algorithm hotp\fR $ \fBnitrocli otp set 1 test\-foobar 666F6F626172 \-\-algorithm hotp\fR + $ \fBnitrocli otp set 0 test\-rfc6238 3132333435363738393031323334353637383930 \-\-algorithm totp \-\-digits 8\fR .P Configure a one-time password slot with an ASCII secret representation: $ \fBnitrocli otp set 0 test\-rfc4226 12345678901234567890 \-\-ascii \-\-algorithm hotp\fR $ \fBnitrocli otp set 1 test\-foobar foobar \-\-ascii \-\-algorithm hotp\fR + $ \fBnitrocli otp set 0 test\-rfc6238 12345678901234567890 \-\-ascii \-\-algorithm totp \-\-digits 8\fR .P Generate a one-time password: $ \fBnitrocli otp get 0 \-\-algorithm hotp\fR 755224 + $ \fBnitrocli otp get 0 \-\-algorithm totp \-\-time 1234567890\fR + 89005924 .P Clear a one-time password slot: $ \fBnitrocli otp clear 0 \-\-algorithm hotp\fR diff --git a/nitrocli/src/args.rs b/nitrocli/src/args.rs index e533c82..b4733f6 100644 --- a/nitrocli/src/args.rs +++ b/nitrocli/src/args.rs @@ -204,7 +204,7 @@ impl str::FromStr for OtpCommand { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum OtpAlgorithm { Hotp, Totp, @@ -525,6 +525,7 @@ fn otp(args: Vec<String>) -> Result<()> { fn otp_get(args: Vec<String>) -> Result<()> { let mut slot: u8 = 0; let mut algorithm = OtpAlgorithm::Totp; + let mut time: Option<u64> = None; let mut parser = argparse::ArgumentParser::new(); parser.set_description("Generates a one-time password"); let _ = @@ -537,10 +538,15 @@ fn otp_get(args: Vec<String>) -> Result<()> { argparse::Store, "The OTP algorithm to use (hotp|totp)", ); + let _ = parser.refer(&mut time).add_option( + &["-t", "--time"], + argparse::StoreOption, + "The time to use for TOTP generation (Unix timestamp, default: system time)", + ); parse(&parser, args)?; drop(parser); - commands::otp_get(slot, algorithm) + commands::otp_get(slot, algorithm, time) } /// Configure a one-time password slot on the Nitrokey device. diff --git a/nitrocli/src/commands.rs b/nitrocli/src/commands.rs index 17426cd..47a955d 100644 --- a/nitrocli/src/commands.rs +++ b/nitrocli/src/commands.rs @@ -19,6 +19,7 @@ use std::fmt; use std::result; +use std::time; use nitrokey::ConfigureOtp; use nitrokey::Device; @@ -338,9 +339,28 @@ fn get_otp<T: GenerateOtp>(slot: u8, algorithm: args::OtpAlgorithm, device: &T) .map_err(|err| get_error("Could not generate OTP", &err)) } +fn get_unix_timestamp() -> Result<u64> { + time::SystemTime::now() + .duration_since(time::UNIX_EPOCH) + .or_else(|_| { + Err(Error::Error( + "Current system time is before the Unix epoch".to_string(), + )) + }) + .map(|duration| duration.as_secs()) +} + /// Generate a one-time password on the Nitrokey device. -pub fn otp_get(slot: u8, algorithm: args::OtpAlgorithm) -> Result<()> { +pub fn otp_get(slot: u8, algorithm: args::OtpAlgorithm, time: Option<u64>) -> Result<()> { let device = get_device()?; + if algorithm == args::OtpAlgorithm::Totp { + device + .set_time(match time { + Some(time) => time, + None => get_unix_timestamp()?, + }) + .map_err(|err| get_error("Could not set time", &err))?; + } let config = device .get_config() .map_err(|err| get_error("Could not get device configuration", &err))?; |