From a23c692dc38fe95b1a584663166fd3c9ed251326 Mon Sep 17 00:00:00 2001 From: Daniel Mueller Date: Sun, 9 Apr 2017 20:21:39 -0700 Subject: Detect wrong password during 'open' command When a wrong password is entered when attempting to open the encrypted volume the nitrokey will report that in the form of an error. In such a case we should retry the operation after asking the user for the corrected password. This change implements this logic. Note that because we use gpg-agent for the PIN inquiry and because it caches passwords by default we must make sure to clear the cache before retrying. --- nitrocli/src/pinentry.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'nitrocli/src/pinentry.rs') diff --git a/nitrocli/src/pinentry.rs b/nitrocli/src/pinentry.rs index 3fb533a..8de788f 100644 --- a/nitrocli/src/pinentry.rs +++ b/nitrocli/src/pinentry.rs @@ -69,6 +69,29 @@ pub fn inquire_passphrase() -> Result, Error> { } +fn parse_pinentry_response(response: Vec) -> Result<(), Error> { + let string = String::from_utf8(response)?; + let lines: Vec<&str> = string.lines().collect(); + + if lines.len() == 1 && lines[0] == "OK" { + // We got the only valid answer we accept. + return Ok(()); + } + return Err(Error::Error("Unexpected response: ".to_string() + &string)); +} + + +/// Clear the cached passphrase. +pub fn clear_passphrase() -> Result<(), Error> { + let command = "CLEAR_PASSPHRASE ".to_string() + CACHE_ID; + let output = process::Command::new("gpg-connect-agent").arg(command) + .arg("/bye") + .output()?; + + return parse_pinentry_response(output.stdout); +} + + #[cfg(test)] mod tests { use super::*; @@ -109,4 +132,30 @@ mod tests { panic!("Unexpected result"); } } + + #[test] + fn parse_pinentry_response_ok() { + let response = "OK\n".to_string().into_bytes(); + assert!(parse_pinentry_response(response).is_ok()) + } + + #[test] + fn parse_pinentry_response_ok_no_newline() { + let response = "OK".to_string().into_bytes(); + assert!(parse_pinentry_response(response).is_ok()) + } + + #[test] + fn parse_pinentry_response_unexpected() { + let response = "ERR 42"; + let expected = "Unexpected response: ".to_string() + response; + + let error = parse_pinentry_response(response.to_string().into_bytes()); + + if let Error::Error(ref e) = error.err().unwrap() { + assert_eq!(e, &expected); + } else { + panic!("Unexpected result"); + } + } } -- cgit v1.2.1