yubikey-cli v0.4.0 (#284)
This commit is contained in:
committed by
GitHub
parent
01e5bba33f
commit
224d346f09
@@ -1,13 +1,11 @@
|
||||
//! Print device status
|
||||
|
||||
use crate::terminal::STDOUT;
|
||||
use crate::terminal::{print_cert_info, STDOUT};
|
||||
use gumdrop::Options;
|
||||
use std::io::{self, Write};
|
||||
use termcolor::{ColorSpec, StandardStreamLock, WriteColor};
|
||||
use yubikey::{piv::*, YubiKey};
|
||||
|
||||
use crate::print_cert_info;
|
||||
|
||||
// String to use for `None`
|
||||
const NONE_STR: &str = "<none>";
|
||||
|
||||
|
||||
+6
-85
@@ -1,92 +1,13 @@
|
||||
//! `yubikey` command-line utility.
|
||||
//!
|
||||
//! The goal of this tool is to provide functionality similar to `yubico-piv-tool`
|
||||
//! but implemented in pure Rust.
|
||||
//!
|
||||
//! It also serves as a demonstration/example of how to use the `yubikey` crate.
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
#![warn(
|
||||
missing_docs,
|
||||
rust_2018_idioms,
|
||||
unused_lifetimes,
|
||||
unused_qualifications
|
||||
)]
|
||||
#![warn(missing_docs, rust_2018_idioms, unused_qualifications)]
|
||||
|
||||
#[macro_use]
|
||||
pub mod terminal;
|
||||
|
||||
pub mod commands;
|
||||
|
||||
use log::debug;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::io::{self, Write};
|
||||
use std::str;
|
||||
use subtle_encoding::hex;
|
||||
use termcolor::{ColorSpec, StandardStreamLock, WriteColor};
|
||||
use x509_parser::parse_x509_certificate;
|
||||
use yubikey::{certificate::Certificate, piv::*, YubiKey};
|
||||
|
||||
/// Write information about certificate found in slot a la yubico-piv-tool output.
|
||||
pub fn print_cert_info(
|
||||
yubikey: &mut YubiKey,
|
||||
slot: SlotId,
|
||||
stream: &mut StandardStreamLock<'_>,
|
||||
) -> io::Result<()> {
|
||||
let cert = match Certificate::read(yubikey, slot) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
debug!("error reading certificate in slot {:?}: {}", slot, e);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let buf = cert.into_buffer();
|
||||
|
||||
if !buf.is_empty() {
|
||||
let fingerprint = Sha256::digest(&buf);
|
||||
let slot_id: u8 = slot.into();
|
||||
print_cert_attr(stream, "Slot", format!("{:x}", slot_id))?;
|
||||
match parse_x509_certificate(&buf) {
|
||||
Ok((_rem, cert)) => {
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Algorithm",
|
||||
cert.tbs_certificate.subject_pki.algorithm.algorithm,
|
||||
)?;
|
||||
|
||||
print_cert_attr(stream, "Subject", cert.tbs_certificate.subject)?;
|
||||
print_cert_attr(stream, "Issuer", cert.tbs_certificate.issuer)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Fingerprint",
|
||||
str::from_utf8(hex::encode(fingerprint).as_slice()).unwrap(),
|
||||
)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Not Before",
|
||||
cert.tbs_certificate.validity.not_before.to_rfc2822(),
|
||||
)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Not After",
|
||||
cert.tbs_certificate.validity.not_after.to_rfc2822(),
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
println!("Failed to parse certificate");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Print a status attribute
|
||||
fn print_cert_attr(
|
||||
stream: &mut StandardStreamLock<'_>,
|
||||
name: &str,
|
||||
value: impl ToString,
|
||||
) -> io::Result<()> {
|
||||
stream.set_color(ColorSpec::new().set_bold(true))?;
|
||||
write!(stream, "{:>12}:", name)?;
|
||||
stream.reset()?;
|
||||
writeln!(stream, " {}", value.to_string())?;
|
||||
stream.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+80
-3
@@ -1,9 +1,17 @@
|
||||
//! Status messages
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
use std::io::{self, Write};
|
||||
use std::sync::Mutex;
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
|
||||
use log::debug;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
str,
|
||||
sync::Mutex,
|
||||
};
|
||||
use subtle_encoding::hex;
|
||||
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, StandardStreamLock, WriteColor};
|
||||
use x509_parser::parse_x509_certificate;
|
||||
use yubikey::{certificate::Certificate, piv::*, YubiKey};
|
||||
|
||||
/// Print a success status message (in green if colors are enabled)
|
||||
#[macro_export]
|
||||
@@ -163,3 +171,72 @@ impl Status {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Write information about certificate found in slot a la yubico-piv-tool output.
|
||||
pub fn print_cert_info(
|
||||
yubikey: &mut YubiKey,
|
||||
slot: SlotId,
|
||||
stream: &mut StandardStreamLock<'_>,
|
||||
) -> io::Result<()> {
|
||||
let cert = match Certificate::read(yubikey, slot) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
debug!("error reading certificate in slot {:?}: {}", slot, e);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
let buf = cert.into_buffer();
|
||||
|
||||
if !buf.is_empty() {
|
||||
let fingerprint = Sha256::digest(&buf);
|
||||
let slot_id: u8 = slot.into();
|
||||
print_cert_attr(stream, "Slot", format!("{:x}", slot_id))?;
|
||||
match parse_x509_certificate(&buf) {
|
||||
Ok((_rem, cert)) => {
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Algorithm",
|
||||
cert.tbs_certificate.subject_pki.algorithm.algorithm,
|
||||
)?;
|
||||
|
||||
print_cert_attr(stream, "Subject", cert.tbs_certificate.subject)?;
|
||||
print_cert_attr(stream, "Issuer", cert.tbs_certificate.issuer)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Fingerprint",
|
||||
str::from_utf8(hex::encode(fingerprint).as_slice()).unwrap(),
|
||||
)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Not Before",
|
||||
cert.tbs_certificate.validity.not_before.to_rfc2822(),
|
||||
)?;
|
||||
print_cert_attr(
|
||||
stream,
|
||||
"Not After",
|
||||
cert.tbs_certificate.validity.not_after.to_rfc2822(),
|
||||
)?;
|
||||
}
|
||||
_ => {
|
||||
println!("Failed to parse certificate");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Print a status attribute
|
||||
fn print_cert_attr(
|
||||
stream: &mut StandardStreamLock<'_>,
|
||||
name: &str,
|
||||
value: impl ToString,
|
||||
) -> io::Result<()> {
|
||||
stream.set_color(ColorSpec::new().set_bold(true))?;
|
||||
write!(stream, "{:>12}:", name)?;
|
||||
stream.reset()?;
|
||||
writeln!(stream, " {}", value.to_string())?;
|
||||
stream.flush()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user