diff --git a/COPYING b/COPYING
index 7fcf4e0..41eb622 100644
--- a/COPYING
+++ b/COPYING
@@ -1,3 +1,6 @@
+Copyright (c) 2014-2019 Yubico AB, Tony Arcieri
+All rights reserved.
+
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
diff --git a/src/apdu.rs b/src/apdu.rs
new file mode 100644
index 0000000..5a86c06
--- /dev/null
+++ b/src/apdu.rs
@@ -0,0 +1,66 @@
+//! Application Protocol Data Unit (APDU)
+
+use zeroize::Zeroize;
+
+/// Application Protocol Data Unit (APDU).
+///
+/// These messages are packets used to communicate with the YubiKey using the
+/// Chip Card Interface Device (CCID) protocol.
+#[derive(Clone)]
+pub struct APDU {
+ /// Instruction class - indicates the type of command, e.g. interindustry or proprietary
+ pub cla: u8,
+
+ /// Instruction code - indicates the specific command, e.g. "write data"
+ pub ins: u8,
+
+ /// Instruction parameter 1 for the command, e.g. offset into file at which to write the data
+ pub p1: u8,
+
+ /// Instruction parameter 2 for the command
+ pub p2: u8,
+
+ /// Length of command - encodes the number of bytes of command data to follow
+ pub lc: u8,
+
+ /// Command data
+ pub data: [u8; 255],
+}
+
+impl APDU {
+ /// Get a const pointer to this APDU
+ // TODO(tarcieri): eliminate pointers and use all safe references
+ pub(crate) fn as_ptr(&self) -> *const APDU {
+ self
+ }
+
+ /// Get a mut pointer to this APDU
+ // TODO(tarcieri): eliminate pointers and use all safe references
+ pub(crate) fn as_mut_ptr(&mut self) -> *mut APDU {
+ self
+ }
+}
+
+impl Default for APDU {
+ fn default() -> Self {
+ Self {
+ cla: 0,
+ ins: 0,
+ p1: 0,
+ p2: 0,
+ lc: 0,
+ data: [0u8; 255],
+ }
+ }
+}
+
+impl Zeroize for APDU {
+ fn zeroize(&mut self) {
+ self.cla.zeroize();
+ self.ins.zeroize();
+ self.p1.zeroize();
+ self.p2.zeroize();
+ self.lc.zeroize();
+ self.data.zeroize();
+ }
+}
diff --git a/src/consts.rs b/src/consts.rs
new file mode 100644
index 0000000..adfe961
--- /dev/null
+++ b/src/consts.rs
@@ -0,0 +1,218 @@
+//! Constant values
+// TODO(tarcieri): refactor these into enums!
+
+// Adapted from yubico-piv-tool:
+//
+//
+// Copyright (c) 2014-2016 Yubico AB
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// TODO(tarcieri): document these!
+#![allow(missing_docs, non_upper_case_globals)]
+
+pub const szLOG_SOURCE: &str = "yubikey-piv.rs";
+
+pub const CB_OBJ_MAX: usize = 3063;
+
+pub const CB_OBJ_TAG_MIN: usize = 2; // 1 byte tag + 1 byte len
+pub const CB_OBJ_TAG_MAX: usize = (CB_OBJ_TAG_MIN + 2); // 1 byte tag + 3 bytes len
+
+pub const CB_PIN_MAX: usize = 8;
+pub const CB_ECC_POINTP256: usize = 65;
+pub const CB_ECC_POINTP384: usize = 97;
+
+pub const CHUID_GUID_OFFS: usize = 29;
+
+pub const CHREF_ACT_CHANGE_PIN: i32 = 0;
+pub const CHREF_ACT_UNBLOCK_PIN: i32 = 1;
+pub const CHREF_ACT_CHANGE_PUK: i32 = 2;
+
+pub const DES_TYPE_3DES: u8 = 1;
+
+pub const DES_LEN_DES: usize = 8;
+pub const DES_LEN_3DES: usize = DES_LEN_DES * 3;
+
+// device types
+
+pub const DEVTYPE_UNKNOWN: u32 = 0x0000_0000;
+pub const DEVTYPE_NEO: u32 = 0x4E45_0000; //"NE"
+pub const DEVTYPE_YK: u32 = 0x594B_0000; //"YK"
+pub const DEVTYPE_NEOr3: u32 = (DEVTYPE_NEO | 0x0000_7233); //"r3"
+pub const DEVTYPE_YK4: u32 = (DEVTYPE_YK | 0x0000_0034); // "4"
+pub const DEVYTPE_YK5: u32 = (DEVTYPE_YK | 0x0000_0035); // "5"
+
+// sw is status words, see NIST special publication 800-73-4, section 5.6
+
+pub const SW_SUCCESS: i32 = 0x9000;
+pub const SW_ERR_SECURITY_STATUS: i32 = 0x6982;
+pub const SW_ERR_AUTH_BLOCKED: i32 = 0x6983;
+pub const SW_ERR_INCORRECT_PARAM: i32 = 0x6a80;
+
+// this is a custom sw for yubikey
+
+pub const SW_ERR_INCORRECT_SLOT: i32 = 0x6b00;
+pub const SW_ERR_NOT_SUPPORTED: i32 = 0x6d00;
+
+pub const TAG_CERT: u8 = 0x70;
+pub const TAG_CERT_COMPRESS: u8 = 0x71;
+pub const TAG_CERT_LRC: u8 = 0xFE;
+pub const TAG_ADMIN: u8 = 0x80;
+pub const TAG_ADMIN_FLAGS_1: u8 = 0x81;
+pub const TAG_ADMIN_SALT: u8 = 0x82;
+pub const TAG_ADMIN_TIMESTAMP: u8 = 0x83;
+pub const TAG_PROTECTED: u8 = 0x88;
+pub const TAG_PROTECTED_FLAGS_1: u8 = 0x81;
+pub const TAG_PROTECTED_MGM: u8 = 0x89;
+pub const TAG_MSCMAP: u8 = 0x81;
+pub const TAG_MSROOTS_END: u8 = 0x82;
+pub const TAG_MSROOTS_MID: u8 = 0x83;
+
+pub const TAG_RSA_MODULUS: u8 = 0x81;
+pub const TAG_RSA_EXP: u8 = 0x82;
+pub const TAG_ECC_POINT: u8 = 0x86;
+
+pub const YKPIV_ALGO_TAG: u8 = 0x80;
+pub const YKPIV_ALGO_3DES: u8 = 0x03;
+pub const YKPIV_ALGO_RSA1024: u8 = 0x06;
+pub const YKPIV_ALGO_RSA2048: u8 = 0x07;
+pub const YKPIV_ALGO_ECCP256: u8 = 0x11;
+pub const YKPIV_ALGO_ECCP384: u8 = 0x14;
+
+pub const YKPIV_ATR_NEO_R3: &[u8] = b";\xFC\x13\0\0\x811\xFE\x15YubikeyNEOr3\xE1\0";
+
+pub const YKPIV_CARDID_SIZE: usize = 16;
+
+pub const YKPIV_CCCID_SIZE: usize = 14;
+
+pub const YKPIV_CERTINFO_UNCOMPRESSED: u8 = 0;
+pub const YKPIV_CERTINFO_GZIP: u8 = 1;
+
+pub const YKPIV_INS_VERIFY: u8 = 0x20;
+pub const YKPIV_INS_CHANGE_REFERENCE: u8 = 0x24;
+pub const YKPIV_INS_RESET_RETRY: u8 = 0x2c;
+pub const YKPIV_INS_GENERATE_ASYMMETRIC: u8 = 0x47;
+pub const YKPIV_INS_AUTHENTICATE: u8 = 0x87;
+pub const YKPIV_INS_GET_DATA: u8 = 0xcb;
+pub const YKPIV_INS_PUT_DATA: u8 = 0xdb;
+pub const YKPIV_INS_SELECT_APPLICATION: u8 = 0xa4;
+pub const YKPIV_INS_GET_RESPONSE_APDU: u8 = 0xc0;
+
+// Yubico vendor specific instructions
+pub const YKPIV_INS_SET_MGMKEY: u8 = 0xff;
+pub const YKPIV_INS_IMPORT_KEY: u8 = 0xfe;
+pub const YKPIV_INS_GET_VERSION: u8 = 0xfd;
+pub const YKPIV_INS_RESET: u8 = 0xfb;
+pub const YKPIV_INS_SET_PIN_RETRIES: u8 = 0xfa;
+pub const YKPIV_INS_ATTEST: u8 = 0xf9;
+pub const YKPIV_INS_GET_SERIAL: u8 = 0xf8;
+
+pub const YKPIV_KEY_AUTHENTICATION: u8 = 0x9a;
+pub const YKPIV_KEY_CARDMGM: u8 = 0x9b;
+pub const YKPIV_KEY_SIGNATURE: u8 = 0x9c;
+pub const YKPIV_KEY_KEYMGM: u8 = 0x9d;
+pub const YKPIV_KEY_CARDAUTH: u8 = 0x9e;
+pub const YKPIV_KEY_RETIRED1: u8 = 0x82;
+pub const YKPIV_KEY_RETIRED2: u8 = 0x83;
+pub const YKPIV_KEY_RETIRED3: u8 = 0x84;
+pub const YKPIV_KEY_RETIRED4: u8 = 0x85;
+pub const YKPIV_KEY_RETIRED5: u8 = 0x86;
+pub const YKPIV_KEY_RETIRED6: u8 = 0x87;
+pub const YKPIV_KEY_RETIRED7: u8 = 0x88;
+pub const YKPIV_KEY_RETIRED8: u8 = 0x89;
+pub const YKPIV_KEY_RETIRED9: u8 = 0x8a;
+pub const YKPIV_KEY_RETIRED10: u8 = 0x8b;
+pub const YKPIV_KEY_RETIRED11: u8 = 0x8c;
+pub const YKPIV_KEY_RETIRED12: u8 = 0x8d;
+pub const YKPIV_KEY_RETIRED13: u8 = 0x8e;
+pub const YKPIV_KEY_RETIRED14: u8 = 0x8f;
+pub const YKPIV_KEY_RETIRED15: u8 = 0x90;
+pub const YKPIV_KEY_RETIRED16: u8 = 0x91;
+pub const YKPIV_KEY_RETIRED17: u8 = 0x92;
+pub const YKPIV_KEY_RETIRED18: u8 = 0x93;
+pub const YKPIV_KEY_RETIRED19: u8 = 0x94;
+pub const YKPIV_KEY_RETIRED20: u8 = 0x95;
+pub const YKPIV_KEY_ATTESTATION: u8 = 0xf9;
+
+pub const YKPIV_OBJ_CAPABILITY: u32 = 0x005f_c107;
+pub const YKPIV_OBJ_CHUID: u32 = 0x005f_c102;
+pub const YKPIV_OBJ_AUTHENTICATION: u32 = 0x005f_c105; // cert for 9a key
+pub const YKPIV_OBJ_FINGERPRINTS: u32 = 0x005f_c103;
+pub const YKPIV_OBJ_SECURITY: u32 = 0x005f_c106;
+pub const YKPIV_OBJ_FACIAL: u32 = 0x005f_c108;
+pub const YKPIV_OBJ_PRINTED: u32 = 0x005f_c109;
+pub const YKPIV_OBJ_SIGNATURE: u32 = 0x005f_c10a; // cert for 9c key
+pub const YKPIV_OBJ_KEY_MANAGEMENT: u32 = 0x005f_c10b; // cert for 9d key
+pub const YKPIV_OBJ_CARD_AUTH: u32 = 0x005f_c101; // cert for 9e key
+pub const YKPIV_OBJ_DISCOVERY: u32 = 0x7e;
+pub const YKPIV_OBJ_KEY_HISTORY: u32 = 0x005f_c10c;
+pub const YKPIV_OBJ_IRIS: u32 = 0x005f_c121;
+
+pub const YKPIV_OBJ_RETIRED1: u32 = 0x005f_c10d;
+pub const YKPIV_OBJ_RETIRED2: u32 = 0x005f_c10e;
+pub const YKPIV_OBJ_RETIRED3: u32 = 0x005f_c10f;
+pub const YKPIV_OBJ_RETIRED4: u32 = 0x005f_c110;
+pub const YKPIV_OBJ_RETIRED5: u32 = 0x005f_c111;
+pub const YKPIV_OBJ_RETIRED6: u32 = 0x005f_c112;
+pub const YKPIV_OBJ_RETIRED7: u32 = 0x005f_c113;
+pub const YKPIV_OBJ_RETIRED8: u32 = 0x005f_c114;
+pub const YKPIV_OBJ_RETIRED9: u32 = 0x005f_c115;
+pub const YKPIV_OBJ_RETIRED10: u32 = 0x005f_c116;
+pub const YKPIV_OBJ_RETIRED11: u32 = 0x005f_c117;
+pub const YKPIV_OBJ_RETIRED12: u32 = 0x005f_c118;
+pub const YKPIV_OBJ_RETIRED13: u32 = 0x005f_c119;
+pub const YKPIV_OBJ_RETIRED14: u32 = 0x005f_c11a;
+pub const YKPIV_OBJ_RETIRED15: u32 = 0x005f_c11b;
+pub const YKPIV_OBJ_RETIRED16: u32 = 0x005f_c11c;
+pub const YKPIV_OBJ_RETIRED17: u32 = 0x005f_c11d;
+pub const YKPIV_OBJ_RETIRED18: u32 = 0x005f_c11e;
+pub const YKPIV_OBJ_RETIRED19: u32 = 0x005f_c11f;
+pub const YKPIV_OBJ_RETIRED20: u32 = 0x005f_c120;
+
+// Internal object IDs
+
+pub const YKPIV_OBJ_ADMIN_DATA: u32 = 0x005f_ff00;
+pub const YKPIV_OBJ_ATTESTATION: u32 = 0x005f_ff01;
+pub const YKPIV_OBJ_MSCMAP: u32 = 0x005f_ff10;
+pub const YKPIV_OBJ_MSROOTS1: u32 = 0x005f_ff11;
+pub const YKPIV_OBJ_MSROOTS2: u32 = 0x005f_ff12;
+pub const YKPIV_OBJ_MSROOTS3: u32 = 0x005f_ff13;
+pub const YKPIV_OBJ_MSROOTS4: u32 = 0x005f_ff14;
+pub const YKPIV_OBJ_MSROOTS5: u32 = 0x005f_ff15;
+
+pub const YKPIV_OBJ_MAX_SIZE: usize = 3072;
+
+pub const YKPIV_PINPOLICY_TAG: u8 = 0xaa;
+pub const YKPIV_PINPOLICY_DEFAULT: u8 = 0;
+pub const YKPIV_PINPOLICY_NEVER: u8 = 1;
+pub const YKPIV_PINPOLICY_ONCE: u8 = 2;
+pub const YKPIV_PINPOLICY_ALWAYS: u8 = 3;
+
+pub const YKPIV_TOUCHPOLICY_TAG: u8 = 0xab;
+pub const YKPIV_TOUCHPOLICY_DEFAULT: u8 = 0;
+pub const YKPIV_TOUCHPOLICY_NEVER: u8 = 1;
+pub const YKPIV_TOUCHPOLICY_ALWAYS: u8 = 2;
+pub const YKPIV_TOUCHPOLICY_CACHED: u8 = 3;
diff --git a/src/error.rs b/src/error.rs
index e8e5d7a..b867c98 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -1,3 +1,5 @@
+//! Error types
+
// Adapted from yubico-piv-tool:
//
//
@@ -30,73 +32,109 @@
use std::fmt;
+/// Kinds of errors
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[repr(i32)]
-#[allow(non_camel_case_types)]
pub enum ErrorKind {
- YKPIV_OK = 0,
- YKPIV_MEMORY_ERROR = -1,
- YKPIV_PCSC_ERROR = -2,
- YKPIV_SIZE_ERROR = -3,
- YKPIV_APPLET_ERROR = -4,
- YKPIV_AUTHENTICATION_ERROR = -5,
- YKPIV_RANDOMNESS_ERROR = -6,
- YKPIV_GENERIC_ERROR = -7,
- YKPIV_KEY_ERROR = -8,
- YKPIV_PARSE_ERROR = -9,
- YKPIV_WRONG_PIN = -10,
- YKPIV_INVALID_OBJECT = -11,
- YKPIV_ALGORITHM_ERROR = -12,
- YKPIV_PIN_LOCKED = -13,
- YKPIV_ARGUMENT_ERROR = -14,
- YKPIV_RANGE_ERROR = -15,
- YKPIV_NOT_SUPPORTED = -16,
+ /// OK
+ // TODO(tarcieri): replace this with proper result types
+ Ok,
+
+ /// Memory error
+ MemoryError,
+
+ /// PCSC error
+ PcscError,
+
+ /// Size error
+ SizeError,
+
+ /// Applet error
+ AppletError,
+
+ /// Authentication error
+ AuthenticationError,
+
+ /// Randomness error
+ RandomnessError,
+
+ /// Generic error
+ GenericError,
+
+ /// Key error
+ KeyError,
+
+ /// Parse error
+ ParseError,
+
+ /// Wrong PIN
+ WrongPin,
+
+ /// Invalid object
+ InvalidObject,
+
+ /// Algorithm error
+ AlgorithmError,
+
+ /// PIN locked
+ PinLocked,
+
+ /// Argument error
+ ArgumentError,
+
+ /// Range error
+ RangeError,
+
+ /// Not supported
+ NotSupported,
}
impl ErrorKind {
- /// Name of the error
+ /// Name of the error.
+ ///
+ /// These names map to the legacy names from the Yubico C library, to
+ /// assist in web searches for relevant information for these errors.
pub fn name(self) -> &'static str {
match self {
- ErrorKind::YKPIV_OK => "YKPIV_OK",
- ErrorKind::YKPIV_MEMORY_ERROR => "YKPIV_MEMORY_ERROR",
- ErrorKind::YKPIV_PCSC_ERROR => "YKPIV_PCSC_ERROR",
- ErrorKind::YKPIV_SIZE_ERROR => "YKPIV_SIZE_ERROR",
- ErrorKind::YKPIV_APPLET_ERROR => "YKPIV_APPLET_ERROR",
- ErrorKind::YKPIV_AUTHENTICATION_ERROR => "YKPIV_AUTHENTICATION_ERROR",
- ErrorKind::YKPIV_RANDOMNESS_ERROR => "YKPIV_RANDOMNESS_ERROR",
- ErrorKind::YKPIV_GENERIC_ERROR => "YKPIV_GENERIC_ERROR",
- ErrorKind::YKPIV_KEY_ERROR => "YKPIV_KEY_ERROR",
- ErrorKind::YKPIV_PARSE_ERROR => "YKPIV_PARSE_ERROR",
- ErrorKind::YKPIV_WRONG_PIN => "YKPIV_WRONG_PIN",
- ErrorKind::YKPIV_INVALID_OBJECT => "YKPIV_INVALID_OBJECT",
- ErrorKind::YKPIV_ALGORITHM_ERROR => "YKPIV_ALGORITHM_ERROR",
- ErrorKind::YKPIV_PIN_LOCKED => "YKPIV_PIN_LOCKED",
- ErrorKind::YKPIV_ARGUMENT_ERROR => "YKPIV_ARGUMENT_ERROR",
- ErrorKind::YKPIV_RANGE_ERROR => "YKPIV_RANGE_ERROR",
- ErrorKind::YKPIV_NOT_SUPPORTED => "YKPIV_NOT_SUPPORTED",
+ ErrorKind::Ok => "YKPIV_OK",
+ ErrorKind::MemoryError => "YKPIV_MEMORY_ERROR",
+ ErrorKind::PcscError => "YKPIV_PCSC_ERROR",
+ ErrorKind::SizeError => "YKPIV_SIZE_ERROR",
+ ErrorKind::AppletError => "YKPIV_APPLET_ERROR",
+ ErrorKind::AuthenticationError => "YKPIV_AUTHENTICATION_ERROR",
+ ErrorKind::RandomnessError => "YKPIV_RANDOMNESS_ERROR",
+ ErrorKind::GenericError => "YKPIV_GENERIC_ERROR",
+ ErrorKind::KeyError => "YKPIV_KEY_ERROR",
+ ErrorKind::ParseError => "YKPIV_PARSE_ERROR",
+ ErrorKind::WrongPin => "YKPIV_WRONG_PIN",
+ ErrorKind::InvalidObject => "YKPIV_INVALID_OBJECT",
+ ErrorKind::AlgorithmError => "YKPIV_ALGORITHM_ERROR",
+ ErrorKind::PinLocked => "YKPIV_PIN_LOCKED",
+ ErrorKind::ArgumentError => "YKPIV_ARGUMENT_ERROR",
+ ErrorKind::RangeError => "YKPIV_RANGE_ERROR",
+ ErrorKind::NotSupported => "YKPIV_NOT_SUPPORTED",
}
}
/// Error message
pub fn msg(self) -> &'static str {
match self {
- ErrorKind::YKPIV_OK => "OK",
- ErrorKind::YKPIV_MEMORY_ERROR => "memory error",
- ErrorKind::YKPIV_PCSC_ERROR => "PCSC error",
- ErrorKind::YKPIV_SIZE_ERROR => "size error",
- ErrorKind::YKPIV_APPLET_ERROR => "applet error",
- ErrorKind::YKPIV_AUTHENTICATION_ERROR => "authentication error",
- ErrorKind::YKPIV_RANDOMNESS_ERROR => "randomness error",
- ErrorKind::YKPIV_GENERIC_ERROR => "generic error",
- ErrorKind::YKPIV_KEY_ERROR => "key error",
- ErrorKind::YKPIV_PARSE_ERROR => "parse error",
- ErrorKind::YKPIV_WRONG_PIN => "wrong pin",
- ErrorKind::YKPIV_INVALID_OBJECT => "invalid object",
- ErrorKind::YKPIV_ALGORITHM_ERROR => "algorithm error",
- ErrorKind::YKPIV_PIN_LOCKED => "PIN locked",
- ErrorKind::YKPIV_ARGUMENT_ERROR => "argument error",
- ErrorKind::YKPIV_RANGE_ERROR => "range error",
- ErrorKind::YKPIV_NOT_SUPPORTED => "not supported",
+ ErrorKind::Ok => "OK",
+ ErrorKind::MemoryError => "memory error",
+ ErrorKind::PcscError => "PCSC error",
+ ErrorKind::SizeError => "size error",
+ ErrorKind::AppletError => "applet error",
+ ErrorKind::AuthenticationError => "authentication error",
+ ErrorKind::RandomnessError => "randomness error",
+ ErrorKind::GenericError => "generic error",
+ ErrorKind::KeyError => "key error",
+ ErrorKind::ParseError => "parse error",
+ ErrorKind::WrongPin => "wrong pin",
+ ErrorKind::InvalidObject => "invalid object",
+ ErrorKind::AlgorithmError => "algorithm error",
+ ErrorKind::PinLocked => "PIN locked",
+ ErrorKind::ArgumentError => "argument error",
+ ErrorKind::RangeError => "range error",
+ ErrorKind::NotSupported => "not supported",
}
}
}
@@ -109,24 +147,14 @@ impl fmt::Display for ErrorKind {
impl std::error::Error for ErrorKind {}
-#[derive(Copy)]
-#[repr(C)]
-pub struct Error {
- pub rc: ErrorKind,
- pub name: *const u8,
- pub description: *const u8,
-}
-
-impl Clone for Error {
- fn clone(&self) -> Self {
- *self
- }
-}
-
+/// Get a string representation of this error
+// TODO(tarcieri): completely replace this with `Display`
pub fn ykpiv_strerror(err: ErrorKind) -> &'static str {
err.msg()
}
+/// Get the name of this error
+// TODO(tarcieri): completely replace this with debug
pub fn ykpiv_strerror_name(err: ErrorKind) -> &'static str {
err.name()
}
diff --git a/src/internal.rs b/src/internal.rs
index 264d1f6..689bb07 100644
--- a/src/internal.rs
+++ b/src/internal.rs
@@ -1,3 +1,9 @@
+//! Internal functions (mostly 3DES)
+
+// TODO(tarcieri): replace OpenSSL extern "C" invocations with `des` crate
+// - crate: https://crates.io/crates/des
+// - docs: https://docs.rs/des/0
+
// Adapted from yubico-piv-tool:
//
//
@@ -28,23 +34,32 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// TODO(tarcieri): investigate and remove dead code
+#![allow(non_upper_case_globals, dead_code)]
+#![allow(clippy::missing_safety_doc)]
+
+use crate::consts::*;
use libc::{
- c_char, c_int, fclose, feof, fgets, fopen, free, getenv, malloc, memcpy, memset, strcasecmp,
- strcmp, strlen,
+ c_char, c_int, fclose, feof, fgets, fopen, free, getenv, malloc, memcpy, memset, sscanf,
+ strcasecmp, strcmp,
+};
+use std::{
+ ffi::{CStr, CString},
+ mem,
+ os::raw::c_void,
};
-use std::ptr;
extern "C" {
fn DES_ecb3_encrypt(
input: *mut [u8; 8],
output: *mut [u8; 8],
- ks1: *mut DES_ks,
- ks2: *mut DES_ks,
- ks3: *mut DES_ks,
+ ks1: *mut DesSubKey,
+ ks2: *mut DesSubKey,
+ ks3: *mut DesSubKey,
enc: i32,
);
fn DES_is_weak_key(key: *mut [u8; 8]) -> i32;
- fn DES_set_key_unchecked(key: *mut [u8; 8], schedule: *mut DES_ks);
+ fn DES_set_key_unchecked(key: *mut [u8; 8], schedule: *mut DesSubKey);
fn PKCS5_PBKDF2_HMAC_SHA1(
pass: *const u8,
passlen: i32,
@@ -55,432 +70,211 @@ extern "C" {
out: *mut u8,
) -> i32;
fn RAND_bytes(buf: *mut u8, num: i32) -> i32;
- static mut _DefaultRuneLocale: Struct1;
- fn __maskrune(arg1: i32, arg2: usize) -> i32;
- fn __tolower(arg1: i32) -> i32;
- fn __toupper(arg1: i32) -> i32;
- fn snprintf(__str: *mut u8, __size: usize, __format: *const u8, ...) -> i32;
- fn sscanf(arg1: *const u8, arg2: *const u8, ...) -> i32;
}
-pub fn isascii(mut _c: i32) -> i32 {
- (_c & !0x7fi32 == 0i32) as (i32)
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct3 {
- pub __min: i32,
- pub __max: i32,
- pub __map: i32,
- pub __types: *mut u32,
-}
-
-impl Clone for Struct3 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct2 {
- pub __nranges: i32,
- pub __ranges: *mut Struct3,
-}
-
-impl Clone for Struct2 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct4 {
- pub __name: [u8; 14],
- pub __mask: u32,
-}
-
-impl Clone for Struct4 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct1 {
- pub __magic: [u8; 8],
- pub __encoding: [u8; 32],
- pub __sgetrune: unsafe extern "C" fn(*const u8, usize, *mut *const u8) -> i32,
- pub __sputrune: unsafe extern "C" fn(i32, *mut u8, usize, *mut *mut u8) -> i32,
- pub __invalid_rune: i32,
- pub __runetype: [u32; 256],
- pub __maplower: [i32; 256],
- pub __mapupper: [i32; 256],
- pub __runetype_ext: Struct2,
- pub __maplower_ext: Struct2,
- pub __mapupper_ext: Struct2,
- pub __variable: *mut ::std::os::raw::c_void,
- pub __variable_len: i32,
- pub __ncharclasses: i32,
- pub __charclasses: *mut Struct4,
-}
-
-impl Clone for Struct1 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn __istype(mut _c: i32, mut _f: usize) -> i32 {
- if isascii(_c) != 0 {
- !(_DefaultRuneLocale.__runetype[_c as (usize)] as (usize) & _f == 0) as (i32)
- } else {
- !(__maskrune(_c, _f) == 0) as (i32)
- }
-}
-
-pub fn __isctype(mut _c: i32, mut _f: usize) -> i32 {
- if _c < 0i32 || _c >= 256i32 {
- 0i32
- } else {
- !(_DefaultRuneLocale.__runetype[_c as (usize)] as (usize) & _f == 0) as (i32)
- }
-}
-
-pub fn __wcwidth(mut _c: i32) -> i32 {
- let mut _x: u32;
- if _c == 0i32 {
- 0i32
- } else {
- _x = __maskrune(_c, 0xe0000000usize | 0x40000usize) as (u32);
- (if _x as (usize) & 0xe0000000usize != 0usize {
- ((_x as (usize) & 0xe0000000usize) >> 30i32) as (i32)
- } else if _x as (usize) & 0x40000usize != 0usize {
- 1i32
- } else {
- -1i32
- })
- }
-}
-
-pub fn isalnum(mut _c: i32) -> i32 {
- __istype(_c, (0x100isize | 0x400isize) as (usize))
-}
-
-pub fn isalpha(mut _c: i32) -> i32 {
- __istype(_c, 0x100usize)
-}
-
-pub fn isblank(mut _c: i32) -> i32 {
- __istype(_c, 0x20000usize)
-}
-
-pub fn iscntrl(mut _c: i32) -> i32 {
- __istype(_c, 0x200usize)
-}
-
-pub fn isdigit(mut _c: i32) -> i32 {
- __isctype(_c, 0x400usize)
-}
-
-pub fn isgraph(mut _c: i32) -> i32 {
- __istype(_c, 0x800usize)
-}
-
-pub fn islower(mut _c: i32) -> i32 {
- __istype(_c, 0x1000usize)
-}
-
-pub fn isprint(mut _c: i32) -> i32 {
- __istype(_c, 0x40000usize)
-}
-
-pub fn ispunct(mut _c: i32) -> i32 {
- __istype(_c, 0x2000usize)
-}
-
-pub fn isspace(mut _c: i32) -> i32 {
- __istype(_c, 0x4000usize)
-}
-
-pub fn isupper(mut _c: i32) -> i32 {
- __istype(_c, 0x8000usize)
-}
-
-pub fn isxdigit(mut _c: i32) -> i32 {
- __isctype(_c, 0x10000usize)
-}
-
-pub fn toascii(mut _c: i32) -> i32 {
- _c & 0x7fi32
-}
-
-pub fn tolower(mut _c: i32) -> i32 {
- __tolower(_c)
-}
-
-pub fn toupper(mut _c: i32) -> i32 {
- __toupper(_c)
-}
-
-pub fn digittoint(mut _c: i32) -> i32 {
- __maskrune(_c, 0xfusize)
-}
-
-pub fn ishexnumber(mut _c: i32) -> i32 {
- __istype(_c, 0x10000usize)
-}
-
-pub fn isideogram(mut _c: i32) -> i32 {
- __istype(_c, 0x80000usize)
-}
-
-pub fn isnumber(mut _c: i32) -> i32 {
- __istype(_c, 0x400usize)
-}
-
-pub fn isphonogram(mut _c: i32) -> i32 {
- __istype(_c, 0x200000usize)
-}
-
-pub fn isrune(mut _c: i32) -> i32 {
- __istype(_c, 0xfffffff0usize)
-}
-
-pub fn isspecial(mut _c: i32) -> i32 {
- __istype(_c, 0x100000usize)
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct __sbuf {
- pub _base: *mut u8,
- pub _size: i32,
-}
-
-impl Clone for __sbuf {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub static mut szLOG_SOURCE: *const u8 = (*b"YubiKey PIV Library\0").as_ptr();
-
-#[derive(Clone, Copy)]
-#[repr(i32)]
+/// DES-related errors
#[allow(non_camel_case_types)]
-pub enum Enum5 {
- DES_OK = 0i32,
- DES_INVALID_PARAMETER = -1i32,
- DES_BUFFER_TOO_SMALL = -2i32,
- DES_MEMORY_ERROR = -3i32,
- DES_GENERAL_ERROR = -4i32,
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[repr(i32)]
+pub enum DesErrorKind {
+ /// Ok
+ Ok = 0,
+
+ /// Invalid parameter
+ InvalidParameter = -1,
+
+ /// Buffer too small
+ BufferTooSmall = -2,
+
+ /// Memory error
+ MemoryError = -3,
+
+ /// General error
+ GeneralError = -4,
}
-#[derive(Copy)]
+/// 3DES subkeys
+#[derive(Copy, Clone)]
#[repr(C)]
-pub struct DES_ks {
- pub ks: [u8; 16],
-}
+pub struct DesSubKey([u8; 16]);
-impl Clone for DES_ks {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
+/// 3DES keys
+#[derive(Copy, Clone)]
pub struct DesKey {
- pub ks1: DES_ks,
- pub ks2: DES_ks,
- pub ks3: DES_ks,
+ /// subkey 1
+ pub ks1: DesSubKey,
+
+ /// subkey 2
+ pub ks2: DesSubKey,
+
+ /// subkey 3
+ pub ks3: DesSubKey,
}
-impl Clone for DesKey {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn des_import_key(
- type_: i32,
- mut keyraw: *const u8,
+/// Import DES key
+pub unsafe fn des_import_key(
+ key_type: i32,
+ keyraw: *const u8,
keyrawlen: usize,
- mut key: *mut *mut DesKey,
-) -> Enum5 {
- let mut _currentBlock;
- let mut rc: Enum5 = Enum5::DES_OK;
- let mut cb_expectedkey: usize = (8i32 * 3i32) as (usize);
- let mut key_tmp: [u8; 8];
- let mut cb_keysize: usize = 8usize;
- if type_ == 1i32 {
- cb_expectedkey = (8i32 * 3i32) as (usize);
- cb_keysize = 8usize;
- if cb_keysize > ::std::mem::size_of::<[u8; 8]>() {
- rc = Enum5::DES_MEMORY_ERROR;
- _currentBlock = 15;
- } else if keyraw.is_null() {
- rc = Enum5::DES_INVALID_PARAMETER;
- _currentBlock = 15;
- } else if keyrawlen != cb_expectedkey {
- rc = Enum5::DES_INVALID_PARAMETER;
- _currentBlock = 15;
- } else if key.is_null() {
- rc = Enum5::DES_INVALID_PARAMETER;
- _currentBlock = 15;
- } else if {
- *key = malloc(::std::mem::size_of::()) as (*mut DesKey);
- *key
- }
- .is_null()
- {
- rc = Enum5::DES_MEMORY_ERROR;
- _currentBlock = 15;
- } else {
- memset(
- *key as (*mut ::std::os::raw::c_void),
- 0i32,
- ::std::mem::size_of::(),
- );
- memcpy(
- key_tmp.as_mut_ptr() as (*mut ::std::os::raw::c_void),
- keyraw as (*const ::std::os::raw::c_void),
- cb_keysize,
- );
- DES_set_key_unchecked(
- &mut key_tmp as (*mut [u8; 8]),
- &mut (**key).ks1 as (*mut DES_ks),
- );
- memcpy(
- key_tmp.as_mut_ptr() as (*mut ::std::os::raw::c_void),
- keyraw.offset(cb_keysize as (isize)) as (*const ::std::os::raw::c_void),
- cb_keysize,
- );
- DES_set_key_unchecked(
- &mut key_tmp as (*mut [u8; 8]),
- &mut (**key).ks2 as (*mut DES_ks),
- );
- memcpy(
- key_tmp.as_mut_ptr() as (*mut ::std::os::raw::c_void),
- keyraw.offset(2usize.wrapping_mul(cb_keysize) as (isize))
- as (*const ::std::os::raw::c_void),
- cb_keysize,
- );
- DES_set_key_unchecked(
- &mut key_tmp as (*mut [u8; 8]),
- &mut (**key).ks3 as (*mut DES_ks),
- );
- _currentBlock = 17;
- }
- } else {
- rc = Enum5::DES_INVALID_PARAMETER;
- _currentBlock = 15;
+ key: *mut *mut DesKey,
+) -> DesErrorKind {
+ let mut key_tmp = [0u8; 8];
+ let cb_expectedkey: usize;
+ let cb_keysize: usize;
+
+ if key_type != DES_TYPE_3DES as i32 {
+ return DesErrorKind::InvalidParameter;
}
- if _currentBlock == 15 {
- if !key.is_null() {
- des_destroy_key(*key);
- *key = 0i32 as (*mut ::std::os::raw::c_void) as (*mut DesKey);
- }
+
+ cb_expectedkey = (8i32 * 3i32) as (usize);
+ cb_keysize = 8usize;
+
+ if cb_keysize > 8 {
+ return DesErrorKind::MemoryError;
}
- rc
+
+ if key.is_null() || keyraw.is_null() || keyrawlen != cb_expectedkey {
+ return DesErrorKind::InvalidParameter;
+ }
+
+ *key = malloc(mem::size_of::()) as (*mut DesKey);
+
+ if (*key).is_null() {
+ return DesErrorKind::MemoryError;
+ }
+
+ memset(*key as (*mut c_void), 0i32, mem::size_of::());
+
+ memcpy(
+ key_tmp.as_mut_ptr() as (*mut c_void),
+ keyraw as (*const c_void),
+ cb_keysize,
+ );
+
+ DES_set_key_unchecked(&mut key_tmp, &mut (**key).ks1);
+
+ memcpy(
+ key_tmp.as_mut_ptr() as (*mut c_void),
+ keyraw.add(cb_keysize) as (*const c_void),
+ cb_keysize,
+ );
+
+ DES_set_key_unchecked(&mut key_tmp, &mut (**key).ks2);
+
+ memcpy(
+ key_tmp.as_mut_ptr() as (*mut c_void),
+ keyraw.add(2usize.wrapping_mul(cb_keysize)) as (*const c_void),
+ cb_keysize,
+ );
+
+ DES_set_key_unchecked(&mut key_tmp, &mut (**key).ks3);
+
+ DesErrorKind::Ok
}
-pub fn des_destroy_key(mut key: *mut DesKey) -> Enum5 {
+/// Destroy DES key
+pub unsafe fn des_destroy_key(key: *mut DesKey) -> DesErrorKind {
if !key.is_null() {
- free(key as (*mut ::std::os::raw::c_void));
+ free(key as (*mut c_void));
}
- Enum5::DES_OK
+
+ DesErrorKind::Ok
}
-pub fn des_encrypt(
- mut key: *mut DesKey,
- mut in_: *const u8,
+/// Encrypt with DES key
+pub unsafe fn des_encrypt(
+ key: *mut DesKey,
+ input: *const u8,
+ inputlen: usize,
+ out: *mut u8,
+ outlen: *mut usize,
+) -> DesErrorKind {
+ if key.is_null() || outlen.is_null() || *outlen < inputlen || input.is_null() || out.is_null() {
+ return DesErrorKind::InvalidParameter;
+ }
+
+ DES_ecb3_encrypt(
+ input as *mut [u8; 8],
+ out as *mut [u8; 8],
+ &mut (*key).ks1,
+ &mut (*key).ks2,
+ &mut (*key).ks3,
+ 1,
+ );
+
+ DesErrorKind::Ok
+}
+
+/// Decrypt with DES key
+pub unsafe fn des_decrypt(
+ key: *mut DesKey,
+ in_: *const u8,
inlen: usize,
- mut out: *mut u8,
- mut outlen: *mut usize,
-) -> Enum5 {
- let mut rc: Enum5 = Enum5::DES_OK;
+ out: *mut u8,
+ outlen: *mut usize,
+) -> DesErrorKind {
if key.is_null() || outlen.is_null() || *outlen < inlen || in_.is_null() || out.is_null() {
- rc = Enum5::DES_INVALID_PARAMETER;
- } else {
- DES_ecb3_encrypt(
- in_ as (*mut [u8; 8]),
- out as (*mut [u8; 8]),
- &mut (*key).ks1 as (*mut DES_ks),
- &mut (*key).ks2 as (*mut DES_ks),
- &mut (*key).ks3 as (*mut DES_ks),
- 1i32,
- );
+ return DesErrorKind::InvalidParameter;
}
- rc
+
+ DES_ecb3_encrypt(
+ in_ as *mut [u8; 8],
+ out as *mut [u8; 8],
+ &mut (*key).ks1,
+ &mut (*key).ks2,
+ &mut (*key).ks3,
+ 0,
+ );
+
+ DesErrorKind::Ok
}
-pub fn des_decrypt(
- mut key: *mut DesKey,
- mut in_: *const u8,
- inlen: usize,
- mut out: *mut u8,
- mut outlen: *mut usize,
-) -> Enum5 {
- let mut rc: Enum5 = Enum5::DES_OK;
- if key.is_null() || outlen.is_null() || *outlen < inlen || in_.is_null() || out.is_null() {
- rc = Enum5::DES_INVALID_PARAMETER;
- } else {
- DES_ecb3_encrypt(
- in_ as (*mut [u8; 8]),
- out as (*mut [u8; 8]),
- &mut (*key).ks1 as (*mut DES_ks),
- &mut (*key).ks2 as (*mut DES_ks),
- &mut (*key).ks3 as (*mut DES_ks),
- 0i32,
- );
- }
- rc
-}
-
-pub fn yk_des_is_weak_key(mut key: *const u8, cb_key: usize) -> bool {
- cb_key;
+/// Is the given DES key weak?
+pub unsafe fn yk_des_is_weak_key(key: *const u8, _cb_key: usize) -> bool {
DES_is_weak_key(key as (*mut [u8; 8])) != 0
}
-#[derive(Clone, Copy)]
+/// PRNG errors/results
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(i32)]
-#[allow(non_camel_case_types)]
-pub enum Enum7 {
- PRNG_OK = 0i32,
- PRNG_GENERAL_ERROR = -1i32,
+pub enum PRngErrorKind {
+ /// Ok
+ Ok = 0,
+
+ /// General error
+ GeneralError = -1,
}
-pub fn _ykpiv_prng_generate(mut buffer: *mut u8, cb_req: usize) -> Enum7 {
- let mut rc: Enum7 = Enum7::PRNG_OK;
- if -1i32 == RAND_bytes(buffer, cb_req as (i32)) {
- rc = Enum7::PRNG_GENERAL_ERROR;
+/// Generate bytes with the PRNG
+pub unsafe fn _ykpiv_prng_generate(buffer: *mut u8, cb_req: usize) -> PRngErrorKind {
+ if RAND_bytes(buffer, cb_req as (i32)) != -1 {
+ PRngErrorKind::Ok
+ } else {
+ PRngErrorKind::GeneralError
}
- rc
}
-#[derive(Clone, Copy)]
+/// PKCS#5 error types
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(i32)]
-#[allow(non_camel_case_types)]
-pub enum Enum8 {
- PKCS5_OK = 0i32,
- PKCS5_GENERAL_ERROR = -1i32,
+pub enum Pkcs5ErrorKind {
+ /// OK
+ Ok = 0,
+
+ /// General error
+ GeneralError = -1,
}
-pub fn pkcs5_pbkdf2_sha1(
- mut password: *const u8,
+/// Decrypt a PKCS#5 key
+pub unsafe fn pkcs5_pbkdf2_sha1(
+ password: *const u8,
cb_password: usize,
- mut salt: *const u8,
+ salt: *const u8,
cb_salt: usize,
- mut iterations: usize,
- mut key: *const u8,
+ iterations: usize,
+ key: *const u8,
cb_key: usize,
-) -> Enum8 {
- let mut rc: Enum8 = Enum8::PKCS5_OK;
+) -> Pkcs5ErrorKind {
PKCS5_PBKDF2_HMAC_SHA1(
password,
cb_password as (i32),
@@ -490,70 +284,55 @@ pub fn pkcs5_pbkdf2_sha1(
cb_key as (i32),
key as (*mut u8),
);
- rc
+
+ Pkcs5ErrorKind::Ok
}
-pub fn _strip_ws(mut sz: *mut c_char) -> *mut c_char {
- let mut psz_head: *mut c_char = sz;
- let mut psz_tail: *mut c_char = sz
- .offset(strlen(sz as *const c_char) as (isize))
- .offset(-1isize);
- 'loop1: loop {
- if isspace(*psz_head as i32) == 0 {
- break;
- }
- psz_head = psz_head.offset(1isize);
- }
- 'loop2: loop {
- if !(psz_tail >= psz_head && (isspace(*psz_tail as (i32)) != 0)) {
- break;
- }
- *{
- let _old = psz_tail;
- psz_tail = psz_tail.offset(-1isize);
- _old
- } = 0;
- }
- psz_head
+/// Strip whitespace
+// TODO(tarcieri): implement this
+pub unsafe fn _strip_ws(sz: *mut c_char) -> *mut c_char {
+ sz
}
+/// Source of how a setting was configured
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[allow(non_camel_case_types)]
pub enum SettingSource {
- SETTING_SOURCE_USER,
- SETTING_SOURCE_ADMIN,
- SETTING_SOURCE_DEFAULT,
+ /// User-specified setting
+ User,
+
+ /// Admin-specified setting
+ Admin,
+
+ /// Default setting
+ Default,
}
-#[derive(Copy)]
+/// Setting booleans
+#[derive(Copy, Clone, Debug)]
pub struct SettingBool {
+ /// Boolean value
pub value: bool,
+
+ /// Source of the configuration setting (user/admin/default)
pub source: SettingSource,
}
-impl Clone for SettingBool {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub unsafe fn _get_bool_config(mut sz_setting: *const c_char) -> SettingBool {
+/// Get a boolean config value
+pub unsafe fn _get_bool_config(sz_setting: *const c_char) -> SettingBool {
let mut setting: SettingBool = SettingBool {
value: false,
- source: SettingSource::SETTING_SOURCE_DEFAULT,
+ source: SettingSource::Default,
};
let mut sz_line = [0u8; 256];
- let mut psz_name: *mut c_char = ptr::null_mut();
- let mut psz_value: *mut c_char = ptr::null_mut();
+ let mut psz_name: *mut c_char;
+ let mut psz_value: *mut c_char;
let mut sz_name = [0u8; 256];
let mut sz_value = [0u8; 256];
- let mut pf = unsafe {
- fopen(
- b"/etc/yubico/yubikeypiv.conf\0".as_ptr() as *const c_char,
- b"r\0".as_ptr() as *const c_char,
- )
- };
+ let pf = fopen(
+ b"/etc/yubico/yubikeypiv.conf\0".as_ptr() as *const c_char,
+ b"r\0".as_ptr() as *const c_char,
+ );
if pf.is_null() {
return setting;
@@ -582,78 +361,65 @@ pub unsafe fn _get_bool_config(mut sz_setting: *const c_char) -> SettingBool {
continue;
}
- if !(sscanf(
- sz_line.as_mut_ptr(),
- (*b"%255[^=]=%255s\0").as_ptr(),
+ if sscanf(
+ sz_line.as_ptr() as *const c_char,
+ b"%255[^=]=%255s\0".as_ptr() as *const c_char,
sz_name.as_mut_ptr(),
sz_value.as_mut_ptr(),
- ) == 2)
+ ) != 2
{
continue;
}
psz_name = _strip_ws(sz_name.as_mut_ptr() as *mut c_char);
- if !(strcasecmp(psz_name as *const c_char, sz_setting as *const c_char) == 0) {
+ if strcasecmp(psz_name, sz_setting) != 0 {
continue;
}
psz_value = _strip_ws(sz_value.as_mut_ptr() as *mut c_char);
- setting.source = SettingSource::SETTING_SOURCE_ADMIN;
- setting.value = strcmp(psz_value as *const c_char, b"1\0".as_ptr() as *const c_char) == 0
- || strcasecmp(
- psz_value as *const c_char,
- b"true\0".as_ptr() as *const c_char,
- ) == 0;
+ setting.source = SettingSource::Admin;
+ setting.value = strcmp(psz_value, b"1\0".as_ptr() as *const c_char) == 0
+ || strcasecmp(psz_value, b"true\0".as_ptr() as *const c_char) == 0;
}
fclose(pf);
setting
}
-pub fn _get_bool_env(mut sz_setting: *const c_char) -> SettingBool {
+/// Get a setting boolean from an environment variable
+pub unsafe fn _get_bool_env(sz_setting: *const c_char) -> SettingBool {
let mut setting: SettingBool = SettingBool {
value: false,
- source: SettingSource::SETTING_SOURCE_DEFAULT,
+ source: SettingSource::Default,
};
- let mut psz_value: *mut c_char = ptr::null_mut();
- let mut sz_name = [0u8; 256];
- snprintf(
- sz_name.as_mut_ptr(),
- ::std::mem::size_of::<[u8; 256]>().wrapping_sub(1usize),
- b"%s%s\0".as_ptr(),
- b"YUBIKEY_PIV_\0".as_ptr(),
- sz_setting,
- );
+ let sz_name = CString::new(format!(
+ "YUBIKEY_PIV_{}",
+ CStr::from_ptr(sz_setting).to_string_lossy()
+ ))
+ .unwrap();
- psz_value = getenv(sz_name.as_mut_ptr() as *const c_char);
+ let psz_value = getenv(sz_name.as_ptr());
if !psz_value.is_null() {
- setting.source = SettingSource::SETTING_SOURCE_USER;
- setting.value = strcmp(psz_value as *const c_char, b"1\0".as_ptr() as *const c_char) == 0
- || strcasecmp(
- psz_value as *const c_char,
- b"true\0".as_ptr() as *const c_char,
- ) == 0;
+ setting.source = SettingSource::User;
+ setting.value = strcmp(psz_value, b"1\0".as_ptr() as *const c_char) == 0
+ || strcasecmp(psz_value, b"true\0".as_ptr() as *const c_char) == 0;
}
setting
}
-pub fn setting_get_bool(mut sz_setting: *const c_char, mut def: bool) -> SettingBool {
- let mut setting: SettingBool = SettingBool {
- value: def,
- source: SettingSource::SETTING_SOURCE_DEFAULT,
- };
+/// Get a setting boolean
+pub unsafe fn setting_get_bool(sz_setting: *const c_char, def: bool) -> SettingBool {
+ let mut setting = _get_bool_config(sz_setting);
- setting = _get_bool_config(sz_setting);
-
- if setting.source == SettingSource::SETTING_SOURCE_DEFAULT {
+ if setting.source == SettingSource::Default {
setting = _get_bool_env(sz_setting);
}
- if setting.source == SettingSource::SETTING_SOURCE_DEFAULT {
+ if setting.source == SettingSource::Default {
setting.value = def;
}
diff --git a/src/lib.rs b/src/lib.rs
index 4f01133..3db2980 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,47 @@
+//! [YubiKey][1] PIV: [Personal Identity Verification][2] support for
+//! [Yubico][3] devices using the Chip Card Interface Device ([CCID][4])
+//! protocol.
+//!
+//! **PIV** is a [NIST][5] standard for both *signing* and *encryption*
+//! using SmartCards and SmartCard-based hardware tokens like YubiKeys.
+//!
+//! This library natively implements the CCID protocol used to manage and
+//! utilize PIV encryption and signing keys which can be generated, imported,
+//! and stored on YubiKey devices.
+//!
+//! Supported algorithms:
+//!
+//! - **Authentication**: `3DES`
+//! - **Encryption**: `RSA1024`, `RSA2048`, `ECCP256`, `ECCP384`
+//! - **Signatures**:
+//! - RSASSA-PKCS#1v1.5: `RSA1024`, `RSA2048`
+//! - ECDSA: `ECCP256`, `ECCP384`
+//!
+//! ## Status
+//!
+//! This library is a work-in-progress translation and is not yet usable.
+//! Check back later for updates.
+//!
+//! ## History
+//!
+//! This library is a Rust translation of the [yubico-piv-tool][6] utility by
+//! Yubico, which was originally written in C. It was mechanically translated
+//! from C into Rust using [Corrode][7], and then subsequently heavily
+//! refactored into safer, more idiomatic Rust.
+//!
+//! For more information on `yubico-piv-tool` and background information on how
+//! the YubiKey implementation of PIV works in general, see the
+//! [Yubico PIV Tool Command Line Guide][8].
+//!
+//! [1]: https://www.yubico.com/products/yubikey-hardware/
+//! [2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-73-4.pdf
+//! [3]: https://www.yubico.com/
+//! [4]: https://en.wikipedia.org/wiki/CCID_(protocol)
+//! [5]: https://www.nist.gov/
+//! [6]: https://github.com/Yubico/yubico-piv-tool/
+//! [7]: https://github.com/jameysharp/corrode
+//! [8]: https://www.yubico.com/wp-content/uploads/2016/05/Yubico_PIV_Tool_Command_Line_Guide_en.pdf
+
// Adapted from yubico-piv-tool:
//
//
@@ -28,3138 +72,20 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#![warn(
+ missing_docs,
+ rust_2018_idioms,
+ trivial_casts,
+ trivial_numeric_casts,
+ unused_lifetimes,
+ unused_qualifications
+)]
+
+mod apdu;
+pub mod consts;
pub mod error;
-pub mod internal;
+mod internal;
pub mod util;
+pub mod yubikey;
-use self::{error::ErrorKind, internal::DesKey};
-use std::{convert::TryInto, ffi::CStr, mem, os::raw::c_void, ptr};
-use zeroize::Zeroize;
-
-use crate::error::ykpiv_strerror;
-use libc::{
- c_char, calloc, free, malloc, memcmp, memcpy, memmove, memset, realloc, strchr, strlen,
- strncasecmp, strnlen,
-};
-
-extern "C" {
- fn SCardBeginTransaction(hCard: i32) -> i32;
- fn SCardConnect(
- hContext: i32,
- szReader: *const c_char,
- dwShareMode: u32,
- dwPreferredProtocols: u32,
- phCard: *mut i32,
- pdwActiveProtocol: *mut u32,
- ) -> i32;
- fn SCardDisconnect(hCard: i32, dwDisposition: u32) -> i32;
- fn SCardEndTransaction(hCard: i32, dwDisposition: u32) -> i32;
- fn SCardEstablishContext(
- dwScope: u32,
- pvReserved1: *const c_void,
- pvReserved2: *const c_void,
- phContext: *mut i32,
- ) -> i32;
- fn SCardIsValidContext(hContext: i32) -> i32;
- fn SCardListReaders(
- hContext: i32,
- mszGroups: *const c_char,
- mszReaders: *mut c_char,
- pcchReaders: *mut u32,
- ) -> i32;
- fn SCardReconnect(
- hCard: i32,
- dwShareMode: u32,
- dwPreferredProtocols: u32,
- dwInitialization: u32,
- pdwActiveProtocol: *mut u32,
- ) -> i32;
- fn SCardReleaseContext(hContext: i32) -> i32;
- fn SCardStatus(
- hCard: i32,
- mszReaderNames: *mut u8,
- pcchReaderLen: *mut u32,
- pdwState: *mut u32,
- pdwProtocol: *mut u32,
- pbAtr: *mut u8,
- pcbAtrLen: *mut u32,
- ) -> i32;
- static mut _DefaultRuneLocale: Struct1;
- fn __maskrune(arg1: i32, arg2: usize) -> i32;
- fn __tolower(arg1: i32) -> i32;
- fn __toupper(arg1: i32) -> i32;
- fn des_destroy_key(key: *mut DesKey) -> Enum6;
- fn des_encrypt(
- key: *mut DesKey,
- in_: *const u8,
- inlen: usize,
- out: *mut u8,
- outlen: *mut usize,
- ) -> Enum6;
- fn des_import_key(
- type_: i32,
- keyraw: *const u8,
- keyrawlen: usize,
- key: *mut *mut DesKey,
- ) -> Enum6;
- fn memset_s(__s: *mut c_void, __smax: usize, __c: i32, __n: usize) -> i32;
- fn snprintf(__str: *mut u8, __size: usize, __format: *const u8, ...) -> i32;
- fn yk_des_is_weak_key(key: *const u8, cb_key: usize) -> bool;
-}
-
-pub const DES_TYPE_3DES: u8 = 1;
-
-pub const DES_LEN_DES: usize = 8;
-pub const DES_LEN_3DES: usize = DES_LEN_DES * 3;
-
-pub const YKPIV_ALGO_TAG: u8 = 0x80;
-pub const YKPIV_ALGO_3DES: u8 = 0x03;
-pub const YKPIV_ALGO_RSA1024: u8 = 0x06;
-pub const YKPIV_ALGO_RSA2048: u8 = 0x07;
-pub const YKPIV_ALGO_ECCP256: u8 = 0x11;
-pub const YKPIV_ALGO_ECCP384: u8 = 0x14;
-
-pub const YKPIV_KEY_AUTHENTICATION: u8 = 0x9a;
-pub const YKPIV_KEY_CARDMGM: u8 = 0x9b;
-pub const YKPIV_KEY_SIGNATURE: u8 = 0x9c;
-pub const YKPIV_KEY_KEYMGM: u8 = 0x9d;
-pub const YKPIV_KEY_CARDAUTH: u8 = 0x9e;
-pub const YKPIV_KEY_RETIRED1: u8 = 0x82;
-pub const YKPIV_KEY_RETIRED2: u8 = 0x83;
-pub const YKPIV_KEY_RETIRED3: u8 = 0x84;
-pub const YKPIV_KEY_RETIRED4: u8 = 0x85;
-pub const YKPIV_KEY_RETIRED5: u8 = 0x86;
-pub const YKPIV_KEY_RETIRED6: u8 = 0x87;
-pub const YKPIV_KEY_RETIRED7: u8 = 0x88;
-pub const YKPIV_KEY_RETIRED8: u8 = 0x89;
-pub const YKPIV_KEY_RETIRED9: u8 = 0x8a;
-pub const YKPIV_KEY_RETIRED10: u8 = 0x8b;
-pub const YKPIV_KEY_RETIRED11: u8 = 0x8c;
-pub const YKPIV_KEY_RETIRED12: u8 = 0x8d;
-pub const YKPIV_KEY_RETIRED13: u8 = 0x8e;
-pub const YKPIV_KEY_RETIRED14: u8 = 0x8f;
-pub const YKPIV_KEY_RETIRED15: u8 = 0x90;
-pub const YKPIV_KEY_RETIRED16: u8 = 0x91;
-pub const YKPIV_KEY_RETIRED17: u8 = 0x92;
-pub const YKPIV_KEY_RETIRED18: u8 = 0x93;
-pub const YKPIV_KEY_RETIRED19: u8 = 0x94;
-pub const YKPIV_KEY_RETIRED20: u8 = 0x95;
-pub const YKPIV_KEY_ATTESTATION: u8 = 0xf9;
-
-pub const YKPIV_INS_VERIFY: u8 = 0x20;
-pub const YKPIV_INS_CHANGE_REFERENCE: u8 = 0x24;
-pub const YKPIV_INS_RESET_RETRY: u8 = 0x2c;
-pub const YKPIV_INS_GENERATE_ASYMMETRIC: u8 = 0x47;
-pub const YKPIV_INS_AUTHENTICATE: u8 = 0x87;
-pub const YKPIV_INS_GET_DATA: u8 = 0xcb;
-pub const YKPIV_INS_PUT_DATA: u8 = 0xdb;
-pub const YKPIV_INS_SELECT_APPLICATION: u8 = 0xa4;
-pub const YKPIV_INS_GET_RESPONSE_APDU: u8 = 0xc0;
-
-// Yubico vendor specific instructions
-pub const YKPIV_INS_SET_MGMKEY: u8 = 0xff;
-pub const YKPIV_INS_IMPORT_KEY: u8 = 0xfe;
-pub const YKPIV_INS_GET_VERSION: u8 = 0xfd;
-pub const YKPIV_INS_RESET: u8 = 0xfb;
-pub const YKPIV_INS_SET_PIN_RETRIES: u8 = 0xfa;
-pub const YKPIV_INS_ATTEST: u8 = 0xf9;
-pub const YKPIV_INS_GET_SERIAL: u8 = 0xf8;
-
-/// Application Protocol Data Unit
-#[derive(Clone)]
-pub struct APDU {
- /// Instruction class - indicates the type of command, e.g. interindustry or proprietary
- pub cla: u8,
-
- /// Instruction code - indicates the specific command, e.g. "write data"
- pub ins: u8,
-
- /// Instruction parameter 1 for the command, e.g. offset into file at which to write the data
- pub p1: u8,
-
- /// Instruction parameter 2 for the command
- pub p2: u8,
-
- /// Length of command - encodes the number of bytes of command data to follow
- pub lc: u8,
-
- /// Command data
- pub data: [u8; 255],
-}
-
-impl Default for APDU {
- fn default() -> Self {
- Self {
- cla: 0,
- ins: 0,
- p1: 0,
- p2: 0,
- lc: 0,
- data: [0u8; 255],
- }
- }
-}
-
-impl Zeroize for APDU {
- fn zeroize(&mut self) {
- self.cla.zeroize();
- self.ins.zeroize();
- self.p1.zeroize();
- self.p2.zeroize();
- self.lc.zeroize();
- self.data.zeroize();
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct __sbuf {
- pub _base: *mut u8,
- pub _size: i32,
-}
-
-impl Clone for __sbuf {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn isascii(mut _c: i32) -> i32 {
- (_c & !0x7fi32 == 0i32) as (i32)
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct3 {
- pub __min: i32,
- pub __max: i32,
- pub __map: i32,
- pub __types: *mut u32,
-}
-
-impl Clone for Struct3 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct2 {
- pub __nranges: i32,
- pub __ranges: *mut Struct3,
-}
-
-impl Clone for Struct2 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct4 {
- pub __name: [u8; 14],
- pub __mask: u32,
-}
-
-impl Clone for Struct4 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct1 {
- pub __magic: [u8; 8],
- pub __encoding: [u8; 32],
- pub __sgetrune: unsafe fn(*const u8, usize, *mut *const u8) -> i32,
- pub __sputrune: unsafe fn(i32, *mut u8, usize, *mut *mut u8) -> i32,
- pub __invalid_rune: i32,
- pub __runetype: [u32; 256],
- pub __maplower: [i32; 256],
- pub __mapupper: [i32; 256],
- pub __runetype_ext: Struct2,
- pub __maplower_ext: Struct2,
- pub __mapupper_ext: Struct2,
- pub __variable: *mut c_void,
- pub __variable_len: i32,
- pub __ncharclasses: i32,
- pub __charclasses: *mut Struct4,
-}
-
-impl Clone for Struct1 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn __istype(mut _c: i32, mut _f: usize) -> i32 {
- if isascii(_c) != 0 {
- !(_DefaultRuneLocale.__runetype[_c as (usize)] as (usize) & _f == 0) as (i32)
- } else {
- !(__maskrune(_c, _f) == 0) as (i32)
- }
-}
-
-pub fn __isctype(mut _c: i32, mut _f: usize) -> i32 {
- if _c < 0i32 || _c >= 256i32 {
- 0i32
- } else {
- !(_DefaultRuneLocale.__runetype[_c as (usize)] as (usize) & _f == 0) as (i32)
- }
-}
-
-pub fn __wcwidth(mut _c: i32) -> i32 {
- let mut _x: u32;
- if _c == 0i32 {
- 0i32
- } else {
- _x = __maskrune(_c, 0xe0000000usize | 0x40000usize) as (u32);
- (if _x as (usize) & 0xe0000000usize != 0usize {
- ((_x as (usize) & 0xe0000000usize) >> 30i32) as (i32)
- } else if _x as (usize) & 0x40000usize != 0usize {
- 1i32
- } else {
- -1i32
- })
- }
-}
-
-pub fn isalnum(mut _c: i32) -> i32 {
- __istype(_c, (0x100isize | 0x400isize) as (usize))
-}
-
-pub fn isalpha(mut _c: i32) -> i32 {
- __istype(_c, 0x100usize)
-}
-
-pub fn isblank(mut _c: i32) -> i32 {
- __istype(_c, 0x20000usize)
-}
-
-pub fn iscntrl(mut _c: i32) -> i32 {
- __istype(_c, 0x200usize)
-}
-
-pub fn isdigit(mut _c: i32) -> i32 {
- __isctype(_c, 0x400usize)
-}
-
-pub fn isgraph(mut _c: i32) -> i32 {
- __istype(_c, 0x800usize)
-}
-
-pub fn islower(mut _c: i32) -> i32 {
- __istype(_c, 0x1000usize)
-}
-
-pub fn isprint(mut _c: i32) -> i32 {
- __istype(_c, 0x40000usize)
-}
-
-pub fn ispunct(mut _c: i32) -> i32 {
- __istype(_c, 0x2000usize)
-}
-
-pub fn isspace(mut _c: i32) -> i32 {
- __istype(_c, 0x4000usize)
-}
-
-pub fn isupper(mut _c: i32) -> i32 {
- __istype(_c, 0x8000usize)
-}
-
-pub fn isxdigit(mut _c: i32) -> i32 {
- __isctype(_c, 0x10000usize)
-}
-
-pub fn toascii(mut _c: i32) -> i32 {
- _c & 0x7fi32
-}
-
-pub fn tolower(mut _c: i32) -> i32 {
- __tolower(_c)
-}
-
-pub fn toupper(mut _c: i32) -> i32 {
- __toupper(_c)
-}
-
-pub fn digittoint(mut _c: i32) -> i32 {
- __maskrune(_c, 0xfusize)
-}
-
-pub fn ishexnumber(mut _c: i32) -> i32 {
- __istype(_c, 0x10000usize)
-}
-
-pub fn isideogram(mut _c: i32) -> i32 {
- __istype(_c, 0x80000usize)
-}
-
-pub fn isnumber(mut _c: i32) -> i32 {
- __istype(_c, 0x400usize)
-}
-
-pub fn isphonogram(mut _c: i32) -> i32 {
- __istype(_c, 0x200000usize)
-}
-
-pub fn isrune(mut _c: i32) -> i32 {
- __istype(_c, 0xfffffff0usize)
-}
-
-pub fn isspecial(mut _c: i32) -> i32 {
- __istype(_c, 0x100000usize)
-}
-
-static mut aid: *const u8 = 0xa0i32 as (*const u8);
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct ykpiv_allocator {
- pub pfn_alloc: unsafe fn(*mut c_void, usize) -> *mut c_void,
- pub pfn_realloc: unsafe fn(*mut c_void, *mut c_void, usize) -> *mut c_void,
- pub pfn_free: unsafe fn(*mut c_void, *mut c_void),
- pub alloc_data: *mut c_void,
-}
-
-impl Clone for ykpiv_allocator {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-unsafe fn _default_alloc(mut data: *mut c_void, mut cb: usize) -> *mut c_void {
- data;
- calloc(cb, 1usize)
-}
-
-unsafe fn _default_realloc(
- mut data: *mut c_void,
- mut p: *mut c_void,
- mut cb: usize,
-) -> *mut c_void {
- data;
- realloc(p, cb)
-}
-
-unsafe fn _default_free(mut data: *mut c_void, mut p: *mut c_void) {
- data;
- free(p);
-}
-
-pub static mut _default_allocator: ykpiv_allocator = ykpiv_allocator {
- pfn_alloc: _default_alloc,
- pfn_realloc: _default_realloc,
- pfn_free: _default_free,
- alloc_data: 0i32 as (*mut c_void),
-};
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct _ykpiv_version_t {
- pub major: u8,
- pub minor: u8,
- pub patch: u8,
-}
-
-impl Clone for _ykpiv_version_t {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct ykpiv_state {
- pub context: i32,
- pub card: i32,
- pub verbose: i32,
- pub pin: *mut u8,
- pub allocator: ykpiv_allocator,
- pub isNEO: bool,
- pub ver: _ykpiv_version_t,
- pub serial: u32,
-}
-
-impl Clone for ykpiv_state {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn _ykpiv_set_length(mut buffer: *mut u8, mut length: usize) -> u32 {
- if length < 0x80usize {
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = length as (u8);
- 1u32
- } else if length < 0x100usize {
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = 0x81u8;
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = length as (u8);
- 2u32
- } else {
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = 0x82u8;
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = (length >> 8i32 & 0xffusize) as (u8);
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = (length as (u8) as (i32) & 0xffi32) as (u8);
- 3u32
- }
-}
-
-pub fn _ykpiv_get_length(mut buffer: *const u8, mut len: *mut usize) -> u32 {
- if *buffer.offset(0isize) as (i32) < 0x81i32 {
- *len = *buffer.offset(0isize) as (usize);
- 1u32
- } else if *buffer as (i32) & 0x7fi32 == 1i32 {
- *len = *buffer.offset(1isize) as (usize);
- 2u32
- } else if *buffer as (i32) & 0x7fi32 == 2i32 {
- let mut tmp: usize = *buffer.offset(1isize) as (usize);
- *len = (tmp << 8i32).wrapping_add(*buffer.offset(2isize) as (usize));
- 3u32
- } else {
- 0u32
- }
-}
-
-pub fn _ykpiv_has_valid_length(mut buffer: *const u8, mut len: usize) -> bool {
- if *buffer.offset(0isize) as (i32) < 0x81i32 && (len > 0usize) {
- true
- } else if *buffer as (i32) & 0x7fi32 == 1i32 && (len > 1usize) {
- true
- } else if *buffer as (i32) & 0x7fi32 == 2i32 && (len > 2usize) {
- true
- } else {
- false
- }
-}
-
-pub fn ykpiv_init_with_allocator(
- mut state: *mut *mut ykpiv_state,
- mut verbose: i32,
- mut allocator: *const ykpiv_allocator,
-) -> ErrorKind {
- let mut s: *mut ykpiv_state;
- if 0i32 as (*mut c_void) as (*mut *mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- s = malloc(mem::size_of::()) as (*mut ykpiv_state);
-
- (if 0i32 as (*mut c_void) as (*mut ykpiv_state) == s {
- ErrorKind::YKPIV_MEMORY_ERROR
- } else {
- memset(s as (*mut c_void), 0i32, mem::size_of::());
- (*s).pin = 0i32 as (*mut c_void) as (*mut u8);
- (*s).allocator = *allocator;
- (*s).verbose = verbose;
- (*s).context = -1i32;
- *state = s;
- ErrorKind::YKPIV_OK
- })
- }
-}
-
-pub fn ykpiv_init(mut state: *mut *mut ykpiv_state, mut verbose: i32) -> ErrorKind {
- ykpiv_init_with_allocator(
- state,
- verbose,
- &mut _default_allocator as (*mut ykpiv_allocator) as (*const ykpiv_allocator),
- )
-}
-
-unsafe fn _ykpiv_done(mut state: *mut ykpiv_state, mut disconnect: bool) -> ErrorKind {
- if disconnect {
- ykpiv_disconnect(state);
- }
-
- _cache_pin(state, ptr::null(), 0usize);
- free(state as *mut c_void);
- ErrorKind::YKPIV_OK
-}
-
-pub fn ykpiv_done_with_external_card(mut state: *mut ykpiv_state) -> ErrorKind {
- _ykpiv_done(state, false)
-}
-
-pub fn ykpiv_done(mut state: *mut ykpiv_state) -> ErrorKind {
- _ykpiv_done(state, true)
-}
-
-pub fn ykpiv_disconnect(mut state: *mut ykpiv_state) -> ErrorKind {
- if (*state).card != 0 {
- SCardDisconnect((*state).card, 0x1u32);
- (*state).card = 0i32;
- }
- if SCardIsValidContext((*state).context) == 0x0i32 {
- SCardReleaseContext((*state).context);
- (*state).context = -1i32;
- }
- ErrorKind::YKPIV_OK
-}
-
-pub fn _ykpiv_select_application(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut apdu: APDU;
- let mut data: [u8; 255];
- let mut recv_len: u32 = mem::size_of::<[u8; 255]>() as (u32);
- let mut sw: i32;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
-
- // FIXME(tarcieri): translate APDU construction
- /*
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
- apdu.st.p1 = 0x04;
- apdu.st.lc = sizeof(aid);
- memcpy(apdu.st.data, aid, sizeof(aid));
- */
-
- if {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed communicating with card: \'{}\'",
- ykpiv_strerror(res)
- );
- }
- res
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed selecting application: {:04x}", sw);
- }
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- res = _ykpiv_get_version(state, 0i32 as (*mut c_void) as (*mut _ykpiv_version_t));
- if res as (i32) != ErrorKind::YKPIV_OK as (i32) {
- if (*state).verbose != 0 {
- eprintln!("Failed to retrieve version: \'{}\'", ykpiv_strerror(res));
- }
- }
- res = _ykpiv_get_serial(state, 0i32 as (*mut c_void) as (*mut u32), false);
- if res as (i32) != ErrorKind::YKPIV_OK as (i32) {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed to retrieve serial number: \'{}\'",
- ykpiv_strerror(res)
- );
- }
- res = ErrorKind::YKPIV_OK;
- }
- res
- }
-}
-
-pub fn _ykpiv_ensure_application_selected(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- state;
- res
-}
-
-unsafe fn _ykpiv_connect(
- mut state: *mut ykpiv_state,
- mut context: usize,
- mut card: usize,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if context != (*state).context as (usize)
- && (0x0i32 != SCardIsValidContext(context as (i32)))
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if card != (*state).card as (usize) {
- let mut reader: [u8; 3072];
- let mut reader_len: u32 = mem::size_of::<[u8; 3072]>() as (u32);
- let mut atr: [u8; 33];
- let mut atr_len: u32 = mem::size_of::<[u8; 33]>() as (u32);
- if 0x0i32
- != SCardStatus(
- card as (i32),
- reader.as_mut_ptr(),
- &mut reader_len as (*mut u32),
- 0i32 as (*mut c_void) as (*mut u32),
- 0i32 as (*mut c_void) as (*mut u32),
- atr.as_mut_ptr(),
- &mut atr_len as (*mut u32),
- )
- {
- return ErrorKind::YKPIV_PCSC_ERROR;
- } else {
- (*state).isNEO = mem::size_of::<[u8; 23]>().wrapping_sub(1usize)
- == atr_len as (usize)
- && (0i32
- == memcmp(
- (*b";\xFC\x13\0\0\x811\xFE\x15YubikeyNEOr3\xE1\0").as_ptr()
- as (*const c_void),
- atr.as_mut_ptr() as (*const c_void),
- atr_len as (usize),
- ));
- }
- }
- (*state).context = context as (i32);
- (*state).card = card as (i32);
- res
- }
-}
-
-pub fn ykpiv_connect_with_external_card(
- mut state: *mut ykpiv_state,
- mut context: usize,
- mut card: usize,
-) -> ErrorKind {
- _ykpiv_connect(state, context, card)
-}
-
-pub fn ykpiv_connect(mut state: *mut ykpiv_state, mut wanted: *const c_char) -> ErrorKind {
- let mut _currentBlock;
- let mut active_protocol: u32;
- let mut reader_buf: [c_char; 2048];
- let mut num_readers: usize = mem::size_of::<[u8; 2048]>();
- let mut rc: isize;
- let mut reader_ptr: *mut c_char;
- let mut card: i32 = -1i32;
- let mut ret: ErrorKind = ykpiv_list_readers(
- state,
- reader_buf.as_mut_ptr(),
- &mut num_readers as (*mut usize),
- );
- if ret as (i32) != ErrorKind::YKPIV_OK as (i32) {
- ret
- } else {
- reader_ptr = reader_buf.as_mut_ptr();
- 'loop2: loop {
- if !(*reader_ptr as (i32) != b'\0' as (i32)) {
- _currentBlock = 3;
- break;
- }
- if !wanted.is_null() {
- let mut ptr = reader_ptr as *const c_char;
- let mut found: bool = false;
- 'loop10: loop {
- if strlen(ptr) < strlen(wanted) {
- _currentBlock = 14;
- break;
- }
- if strncasecmp(ptr, wanted, strlen(wanted)) == 0i32 {
- _currentBlock = 13;
- break;
- }
- if *{
- let _old = ptr;
- ptr = ptr.offset(1isize);
- _old
- } == 0
- {
- _currentBlock = 14;
- break;
- }
- }
- if _currentBlock == 13 {
- found = true;
- }
- if found as (i32) == 0i32 {
- if (*state).verbose != 0 {
- eprintln!(
- "skipping reader \'{}\' since it doesn\'t match \'{}\'.",
- CStr::from_ptr(reader_ptr).to_string_lossy(),
- CStr::from_ptr(wanted).to_string_lossy()
- );
- _currentBlock = 26;
- } else {
- _currentBlock = 26;
- }
- } else {
- _currentBlock = 15;
- }
- } else {
- _currentBlock = 15;
- }
- if _currentBlock == 15 {
- if (*state).verbose != 0 {
- eprintln!(
- "trying to connect to reader \'{}\'.",
- CStr::from_ptr(reader_ptr).to_string_lossy()
- );
- }
- rc = SCardConnect(
- (*state).context,
- reader_ptr as *const c_char,
- 0x2u32,
- 0x2u32,
- &mut card as (*mut i32),
- &mut active_protocol as (*mut u32),
- ) as (isize);
- if rc != 0x0isize {
- if (*state).verbose != 0 {
- eprintln!("SCardConnect failed, rc={}", rc);
- }
- } else if ErrorKind::YKPIV_OK as (i32)
- == _ykpiv_connect(state, (*state).context as (usize), card as (usize)) as (i32)
- {
- _currentBlock = 19;
- break;
- }
- }
- reader_ptr = reader_ptr.offset(strlen(reader_ptr).wrapping_add(1usize) as (isize));
- }
- (if _currentBlock == 3 {
- (if *reader_ptr as (i32) == b'\0' as (i32) {
- if (*state).verbose != 0 {
- eprintln!("error: no usable reader found.");
- }
- SCardReleaseContext((*state).context);
- (*state).context = -1i32;
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- ErrorKind::YKPIV_GENERIC_ERROR
- })
- } else if ErrorKind::YKPIV_OK as (i32) != {
- ret = _ykpiv_begin_transaction(state);
- ret
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- ret = _ykpiv_select_application(state);
- _ykpiv_end_transaction(state);
- ret
- })
- }
-}
-
-pub fn ykpiv_list_readers(
- mut state: *mut ykpiv_state,
- mut readers: *mut c_char,
- mut len: *mut usize,
-) -> ErrorKind {
- let mut num_readers: u32 = 0u32;
- let mut rc: isize;
- if SCardIsValidContext((*state).context) != 0x0i32 {
- rc = SCardEstablishContext(
- 0x2u32,
- 0i32 as (*mut c_void) as (*const c_void),
- 0i32 as (*mut c_void) as (*const c_void),
- &mut (*state).context as (*mut i32),
- ) as (isize);
- if rc != 0x0isize {
- if (*state).verbose != 0 {
- eprintln!("error: SCardEstablishContext failed, rc={}", rc);
- }
- return ErrorKind::YKPIV_PCSC_ERROR;
- }
- }
- rc = SCardListReaders(
- (*state).context,
- ptr::null(),
- ptr::null_mut(),
- &mut num_readers as (*mut u32),
- ) as (isize);
- if rc != 0x0isize {
- if (*state).verbose != 0 {
- eprintln!("error: SCardListReaders failed, rc={}", rc);
- }
- SCardReleaseContext((*state).context);
- (*state).context = -1i32;
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if num_readers as (usize) > *len {
- num_readers = *len as (u32);
- } else if num_readers as (usize) < *len {
- *len = num_readers as (usize);
- }
- rc = SCardListReaders(
- (*state).context,
- ptr::null(),
- readers,
- &mut num_readers as (*mut u32),
- ) as (isize);
- (if rc != 0x0isize {
- if (*state).verbose != 0 {
- eprintln!("error: SCardListReaders failed, rc={}", rc);
- }
- SCardReleaseContext((*state).context);
- (*state).context = -1i32;
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- *len = num_readers as (usize);
- ErrorKind::YKPIV_OK
- })
- }
-}
-
-unsafe fn reconnect(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut active_protocol: u32 = 0u32;
- let mut rc: isize;
- let mut res: ErrorKind;
- let mut tries: i32;
- if (*state).verbose != 0 {
- eprintln!("trying to reconnect to current reader.");
- }
- rc = SCardReconnect(
- (*state).card,
- 0x2u32,
- 0x2u32,
- 0x1u32,
- &mut active_protocol as (*mut u32),
- ) as (isize);
- if rc != 0x0isize {
- if (*state).verbose != 0 {
- eprintln!("SCardReconnect failed, rc={}", rc);
- }
- ErrorKind::YKPIV_PCSC_ERROR
- } else if {
- res = _ykpiv_select_application(state);
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- res
- } else if !(*state).pin.is_null() {
- ykpiv_verify(
- state,
- (*state).pin as *const c_char,
- &mut tries as (*mut i32),
- )
- } else {
- ErrorKind::YKPIV_OK
- }
-}
-
-pub fn _ykpiv_begin_transaction(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut rc: isize;
- rc = SCardBeginTransaction((*state).card) as (isize);
- if (rc as (usize) & 0xffffffffusize) as (isize) as (usize) == 0x80100068usize {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- if {
- res = reconnect(state);
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- return res;
- } else {
- rc = SCardBeginTransaction((*state).card) as (isize);
- }
- }
- if rc != 0x0isize {
- if (*state).verbose != 0 {
- eprintln!("error: Failed to begin pcsc transaction, rc={}", rc);
- }
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- ErrorKind::YKPIV_OK
- }
-}
-
-pub fn _ykpiv_end_transaction(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut rc: isize = SCardEndTransaction((*state).card, 0x0u32) as (isize);
- if rc != 0x0isize && ((*state).verbose != 0) {
- eprintln!("error: Failed to end pcsc transaction, rc={}", rc);
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- ErrorKind::YKPIV_OK
- }
-}
-
-pub fn _ykpiv_transfer_data(
- mut state: *mut ykpiv_state,
- mut templ: *const u8,
- mut in_data: *const u8,
- mut in_len: isize,
- mut out_data: *mut u8,
- mut out_len: *mut usize,
- mut sw: *mut i32,
-) -> ErrorKind {
- let mut _currentBlock;
- let mut in_ptr: *const u8 = in_data;
- let mut max_out: usize = *out_len;
- let mut res: ErrorKind;
- let mut recv_len: u32;
- *out_len = 0usize;
- 'loop1: loop {
- let mut this_size: usize = 0xffusize;
- let mut data: [u8; 261];
- recv_len = mem::size_of::<[u8; 261]>() as (u32);
- let mut apdu = APDU::default();
- apdu.cla = *templ;
- apdu.ins = *templ.offset(1);
- apdu.p1 = *templ.offset(2);
- apdu.p2 = *templ.offset(3);
-
- if in_ptr.offset(0xff) < in_data.offset(in_len) {
- apdu.cla = 0x10;
- } else {
- this_size = in_data.offset(in_len) as usize - in_ptr as usize;
- }
-
- if (*state).verbose > 2i32 {
- eprintln!("Going to send {} bytes in this go.", this_size);
- }
-
- apdu.lc = this_size.try_into().unwrap();
- memcpy(
- apdu.data.as_mut_ptr() as *mut c_void,
- in_ptr as *const c_void,
- this_size,
- );
-
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- sw,
- );
- if res as (i32) != ErrorKind::YKPIV_OK as (i32) {
- _currentBlock = 24;
- break;
- }
- if *sw != 0x9000i32 && (*sw >> 8i32 != 0x61i32) {
- _currentBlock = 24;
- break;
- }
- if (*out_len)
- .wrapping_add(recv_len as (usize))
- .wrapping_sub(2usize)
- > max_out
- {
- _currentBlock = 21;
- break;
- }
- if !out_data.is_null() {
- memcpy(
- out_data as (*mut c_void),
- data.as_mut_ptr() as (*const c_void),
- recv_len.wrapping_sub(2u32) as (usize),
- );
- out_data = out_data.offset(recv_len.wrapping_sub(2u32) as (isize));
- *out_len = (*out_len).wrapping_add(recv_len.wrapping_sub(2u32) as (usize));
- }
- in_ptr = in_ptr.offset(this_size as (isize));
- if !(in_ptr < in_data.offset(in_len)) {
- _currentBlock = 10;
- break;
- }
- }
- if _currentBlock == 10 {
- 'loop10: loop {
- if !(*sw >> 8i32 == 0x61i32) {
- _currentBlock = 24;
- break;
- }
- let mut data: [u8; 261];
- recv_len = mem::size_of::<[u8; 261]>() as (u32);
- if (*state).verbose > 2i32 {
- eprintln!(
- "The card indicates there is {} bytes more data for us.",
- *sw & 0xffi32
- );
- }
-
- let mut apdu = APDU::default();
- apdu.ins = YKPIV_INS_GET_RESPONSE_APDU;
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- sw,
- );
- if res as (i32) != ErrorKind::YKPIV_OK as (i32) {
- _currentBlock = 24;
- break;
- }
- if *sw != 0x9000i32 && (*sw >> 8i32 != 0x61i32) {
- _currentBlock = 24;
- break;
- }
- if (*out_len)
- .wrapping_add(recv_len as (usize))
- .wrapping_sub(2usize)
- > max_out
- {
- _currentBlock = 18;
- break;
- }
- if out_data.is_null() {
- continue;
- }
- memcpy(
- out_data as (*mut c_void),
- data.as_mut_ptr() as (*const c_void),
- recv_len.wrapping_sub(2u32) as (usize),
- );
- out_data = out_data.offset(recv_len.wrapping_sub(2u32) as (isize));
- *out_len = (*out_len).wrapping_add(recv_len.wrapping_sub(2u32) as (usize));
- }
- if _currentBlock == 24 {
- } else {
- if (*state).verbose != 0 {
- eprintln!(
- "Output buffer to small, wanted to write {}, max was {}.",
- (*out_len)
- .wrapping_add(recv_len as (usize))
- .wrapping_sub(2usize),
- max_out
- );
- }
- res = ErrorKind::YKPIV_SIZE_ERROR;
- }
- } else if _currentBlock == 21 {
- if (*state).verbose != 0 {
- eprintln!(
- "Output buffer to small, wanted to write {}, max was {}.",
- (*out_len)
- .wrapping_add(recv_len as (usize))
- .wrapping_sub(2usize),
- max_out
- );
- }
- res = ErrorKind::YKPIV_SIZE_ERROR;
- }
- res
-}
-
-pub fn ykpiv_transfer_data(
- mut state: *mut ykpiv_state,
- mut templ: *const u8,
- mut in_data: *const u8,
- mut in_len: isize,
- mut out_data: *mut u8,
- mut out_len: *mut usize,
- mut sw: *mut i32,
-) -> ErrorKind {
- let mut res: ErrorKind;
- if {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- *out_len = 0usize;
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- res = _ykpiv_transfer_data(state, templ, in_data, in_len, out_data, out_len, sw);
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-unsafe fn dump_hex(mut buf: *const u8, mut len: u32) {
- let mut i: u32;
- i = 0u32;
- 'loop1: loop {
- if !(i < len) {
- break;
- }
- eprintln!("{:02x} ", *buf.offset(i as (isize)) as (i32));
- i = i.wrapping_add(1u32);
- }
-}
-
-pub fn _send_data(
- mut state: *mut ykpiv_state,
- mut apdu: *mut APDU,
- mut data: *mut u8,
- mut recv_len: *mut u32,
- mut sw: *mut i32,
-) -> ErrorKind {
- let mut rc: isize;
- // FIXME(tarcieri): `send_len` is NOT supposed to be 0. Translate C code
- let mut send_len: u32 = 0u32; // (unsigned int)apdu->st.lc + 5;
- let mut tmp_len: u32 = *recv_len;
-
- // FIXME(tarcieri): Translate C code below
- /*
- if(state->verbose > 1) {
- fprintf(stderr, "> ");
- dump_hex(apdu->raw, send_len);
- fprintf(stderr, "\n");
- }
-
- rc = SCardTransmit(state->card, SCARD_PCI_T1, apdu->raw, send_len, NULL, data, &tmp_len);
- if(rc != SCARD_S_SUCCESS) {
- if(state->verbose) {
- fprintf (stderr, "error: SCardTransmit failed, rc=%08lx\n", rc);
- }
- return YKPIV_PCSC_ERROR;
- }
- */
-
- *recv_len = tmp_len;
- if (*state).verbose > 1i32 {
- eprint!("< ");
- dump_hex(data as (*const u8), *recv_len);
- eprintln!();
- }
- if *recv_len >= 2u32 {
- *sw = *data.offset((*recv_len).wrapping_sub(2u32) as (isize)) as (i32) << 8i32
- | *data.offset((*recv_len).wrapping_sub(1u32) as (isize)) as (i32);
- } else {
- *sw = 0i32;
- }
- ErrorKind::YKPIV_OK
-}
-
-#[derive(Clone, Copy)]
-#[repr(i32)]
-#[allow(non_camel_case_types)]
-pub enum Enum6 {
- DES_OK = 0i32,
- DES_INVALID_PARAMETER = -1i32,
- DES_BUFFER_TOO_SMALL = -2i32,
- DES_MEMORY_ERROR = -3i32,
- DES_GENERAL_ERROR = -4i32,
-}
-
-pub fn ykpiv_authenticate(mut state: *mut ykpiv_state, mut key: *const u8) -> ErrorKind {
- let mut apdu: APDU;
- let mut data: [u8; 261];
- let mut challenge: [u8; 8];
- let mut recv_len: u32 = mem::size_of::<[u8; 261]>() as (u32);
- let mut sw: i32;
- let mut res: ErrorKind;
- let mut drc: Enum6 = Enum6::DES_OK;
- let mut mgm_key: *mut DesKey = 0i32 as (*mut c_void) as (*mut DesKey);
- let mut out_len: usize = 0usize;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if 0i32 as (*mut c_void) as (*const u8) == key {
- key = (*b"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\0").as_ptr(
- );
- }
- if Enum6::DES_OK as (i32)
- != des_import_key(
- 1i32,
- key,
- (8i32 * 3i32) as (usize),
- &mut mgm_key as (*mut *mut DesKey),
- ) as (i32)
- {
- res = ErrorKind::YKPIV_ALGORITHM_ERROR;
- } else {
- // get a challenge from the card
- // FIXME(tarcieri): Translate C code below
- /*
- {
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_AUTHENTICATE;
- apdu.st.p1 = YKPIV_ALGO_3DES; // triple des
- apdu.st.p2 = YKPIV_KEY_CARDMGM; // management key
- apdu.st.lc = 0x04;
- apdu.st.data[0] = 0x7c;
- apdu.st.data[1] = 0x02;
- apdu.st.data[2] = 0x80;
- if ((res = _send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) {
- goto Cleanup;
- }
- else if (sw != SW_SUCCESS) {
- res = YKPIV_AUTHENTICATION_ERROR;
- goto Cleanup;
- }
- memcpy(challenge, data + 4, 8);
- }
- */
-
- // send a response to the cards challenge and a challenge of our own.
- // FIXME(tarcieri): Translate C code below
- /*
- {
- unsigned char *dataptr = apdu.st.data;
- unsigned char response[8];
- out_len = sizeof(response);
- drc = des_decrypt(mgm_key, challenge, sizeof(challenge), response, &out_len);
-
- if (drc != DES_OK) {
- res = YKPIV_AUTHENTICATION_ERROR;
- goto Cleanup;
- }
-
- recv_len = sizeof(data);
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_AUTHENTICATE;
- apdu.st.p1 = YKPIV_ALGO_3DES; // triple des
- apdu.st.p2 = YKPIV_KEY_CARDMGM; // management key
- *dataptr++ = 0x7c;
- *dataptr++ = 20; // 2 + 8 + 2 +8
- *dataptr++ = 0x80;
- *dataptr++ = 8;
- memcpy(dataptr, response, 8);
- dataptr += 8;
- *dataptr++ = 0x81;
- *dataptr++ = 8;
- if (PRNG_GENERAL_ERROR == _ykpiv_prng_generate(dataptr, 8)) {
- if (state->verbose) {
- fprintf(stderr, "Failed getting randomness for authentication.\n");
- }
- res = YKPIV_RANDOMNESS_ERROR;
- goto Cleanup;
- }
- memcpy(challenge, dataptr, 8);
- dataptr += 8;
- apdu.st.lc = (unsigned char)(dataptr - apdu.st.data);
- if ((res = _send_data(state, &apdu, data, &recv_len, &sw)) != YKPIV_OK) {
- goto Cleanup;
- }
- else if (sw != SW_SUCCESS) {
- res = YKPIV_AUTHENTICATION_ERROR;
- goto Cleanup;
- }
- }
- */
- let mut response: [u8; 8];
- out_len = mem::size_of::<[u8; 8]>();
- drc = des_encrypt(
- mgm_key,
- challenge.as_mut_ptr() as (*const u8),
- mem::size_of::<[u8; 8]>(),
- response.as_mut_ptr(),
- &mut out_len as (*mut usize),
- );
- if drc as (i32) != Enum6::DES_OK as (i32) {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- } else if memcmp(
- response.as_mut_ptr() as (*const c_void),
- data.as_mut_ptr().offset(4isize) as (*const c_void),
- 8usize,
- ) == 0i32
- {
- res = ErrorKind::YKPIV_OK;
- } else {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- }
- }
- }
- if !mgm_key.is_null() {
- des_destroy_key(mgm_key);
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn ykpiv_set_mgmkey(mut state: *mut ykpiv_state, mut new_key: *const u8) -> ErrorKind {
- ykpiv_set_mgmkey2(state, new_key, 0u8)
-}
-
-pub fn ykpiv_set_mgmkey2(
- mut state: *mut ykpiv_state,
- mut new_key: *const u8,
- touch: u8,
-) -> ErrorKind {
- let mut data: [u8; 261];
- let mut recv_len: u32 = mem::size_of::<[u8; 261]>() as (u32);
- let mut sw: i32;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut apdu = APDU::default();
-
- if _ykpiv_begin_transaction(state) != ErrorKind::YKPIV_OK {
- return ErrorKind::YKPIV_PCSC_ERROR;
- }
-
- if _ykpiv_ensure_application_selected(state) == ErrorKind::YKPIV_OK {
- if yk_des_is_weak_key(new_key, (8i32 * 3i32) as (usize)) {
- if (*state).verbose != 0 {
- // TODO(tarcieri): format string
- eprint!("Won\'t set new key \'");
- dump_hex(new_key, DES_LEN_3DES as u32);
- eprintln!("\' since it\'s weak (with odd parity).");
- }
- res = ErrorKind::YKPIV_KEY_ERROR;
- apdu.ins = YKPIV_INS_SET_MGMKEY;
- apdu.p1 = 0xff;
-
- apdu.p2 = match touch {
- 0 => 0xff,
- 1 => 0xfe,
- _ => {
- _ykpiv_end_transaction(state);
- return ErrorKind::YKPIV_GENERIC_ERROR;
- }
- };
-
- apdu.lc = DES_LEN_3DES as u8 + 3;
- apdu.data[0] = YKPIV_ALGO_3DES;
- apdu.data[1] = YKPIV_KEY_CARDMGM;
- apdu.data[2] = DES_LEN_3DES as u8;
- memcpy(
- apdu.data.as_mut_ptr().offset(3) as *mut c_void,
- new_key as *const c_void,
- DES_LEN_3DES,
- );
- } else {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
-
- if res != ErrorKind::YKPIV_OK {
- if !(sw == 0x9000i32) {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- }
- }
- }
- }
-
- apdu.zeroize();
- _ykpiv_end_transaction(state);
- res
-}
-
-const HEX_TABLE: &[u8] = b"0123456789abcdef";
-
-pub fn ykpiv_hex_decode(
- mut hex_in: *const u8,
- mut in_len: usize,
- mut hex_out: *mut u8,
- mut out_len: *mut usize,
-) -> ErrorKind {
- let mut _currentBlock;
- let mut i: usize;
- let mut first: bool = true;
-
- if *out_len < in_len.wrapping_div(2) {
- return ErrorKind::YKPIV_SIZE_ERROR;
- }
-
- if in_len.wrapping_rem(2) != 0 {
- return ErrorKind::YKPIV_SIZE_ERROR;
- }
-
- *out_len = in_len.wrapping_div(2usize);
- i = 0usize;
-
- while i < in_len {
- let mut ind_ptr: *mut c_char = strchr(
- HEX_TABLE.as_ptr() as *const c_char,
- tolower(*{
- let _old = hex_in;
- hex_in = hex_in.offset(1isize);
- _old
- } as (i32)),
- );
-
- if ind_ptr.is_null() {
- _currentBlock = 6;
- break;
- }
-
- let index = ind_ptr as usize - HEX_TABLE.as_ptr() as usize;
-
- if first {
- *hex_out = (index << 4i32) as (u8);
- } else {
- let _rhs = index;
-
- let _lhs = &mut *{
- let _old = hex_out;
- hex_out = hex_out.offset(1isize);
- _old
- };
-
- *_lhs = (*_lhs as usize | _rhs) as (u8);
- }
-
- first = !first;
- i = i.wrapping_add(1usize);
- }
-
- if _currentBlock == 4 {
- ErrorKind::YKPIV_OK
- } else {
- ErrorKind::YKPIV_PARSE_ERROR
- }
-}
-
-unsafe fn _general_authenticate(
- mut state: *mut ykpiv_state,
- mut sign_in: *const u8,
- mut in_len: usize,
- mut out: *mut u8,
- mut out_len: *mut usize,
- mut algorithm: u8,
- mut key: u8,
- mut decipher: bool,
-) -> ErrorKind {
- let mut _currentBlock;
- let mut indata: [u8; 1024];
- let mut dataptr: *mut u8 = indata.as_mut_ptr();
- let mut data: [u8; 1024];
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut recv_len: usize = mem::size_of::<[u8; 1024]>();
- let mut key_len: usize = 0usize;
- let mut sw: i32 = 0i32;
- let mut bytes: usize;
- let mut len: usize = 0usize;
- let mut res: ErrorKind;
- if algorithm as (i32) == 0x14i32 {
- _currentBlock = 12;
- } else if algorithm as (i32) == 0x11i32 {
- key_len = 32usize;
- _currentBlock = 12;
- } else {
- if !(algorithm as (i32) == 0x7i32) {
- if algorithm as (i32) == 0x6i32 {
- key_len = 128usize;
- } else {
- return ErrorKind::YKPIV_ALGORITHM_ERROR;
- }
- }
- if key_len == 0usize {
- key_len = 256usize;
- }
- if in_len != key_len {
- return ErrorKind::YKPIV_SIZE_ERROR;
- } else {
- _currentBlock = 16;
- }
- }
- if _currentBlock == 12 {
- if key_len == 0usize {
- key_len = 48usize;
- }
- if !decipher && (in_len > key_len) {
- return ErrorKind::YKPIV_SIZE_ERROR;
- } else if decipher && (in_len != key_len.wrapping_mul(2usize).wrapping_add(1usize)) {
- return ErrorKind::YKPIV_SIZE_ERROR;
- }
- }
- if in_len < 0x80usize {
- bytes = 1usize;
- } else if in_len < 0xffusize {
- bytes = 2usize;
- } else {
- bytes = 3usize;
- }
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 0x7cu8;
- dataptr = dataptr
- .offset(
- _ykpiv_set_length(dataptr, in_len.wrapping_add(bytes).wrapping_add(3usize)) as (isize),
- );
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 0x82u8;
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 0x0u8;
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = if (algorithm as (i32) == 0x11i32 || algorithm as (i32) == 0x14i32) && decipher {
- 0x85i32
- } else {
- 0x81i32
- } as (u8);
- dataptr = dataptr.offset(_ykpiv_set_length(dataptr, in_len) as (isize));
- memcpy(dataptr as (*mut c_void), sign_in as (*const c_void), in_len);
- dataptr = dataptr.offset(in_len as (isize));
- if {
- res = ykpiv_transfer_data(
- state,
- templ as (*const u8),
- indata.as_mut_ptr() as (*const u8),
- (dataptr as (isize)).wrapping_sub(indata.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize),
- data.as_mut_ptr(),
- &mut recv_len as (*mut usize),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("Sign command failed to communicate.");
- }
- res
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed sign command with code {:x}.\n\0", sw);
- }
- (if sw == 0x6982i32 {
- ErrorKind::YKPIV_AUTHENTICATION_ERROR
- } else {
- ErrorKind::YKPIV_GENERIC_ERROR
- })
- } else if data[0usize] as (i32) != 0x7ci32 {
- if (*state).verbose != 0 {
- eprintln!("Failed parsing signature reply.");
- }
- ErrorKind::YKPIV_PARSE_ERROR
- } else {
- dataptr = data.as_mut_ptr().offset(1isize);
- dataptr = dataptr.offset(_ykpiv_get_length(dataptr, &mut len as (*mut usize)) as (isize));
- (if *dataptr as (i32) != 0x82i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed parsing signature reply.");
- }
- ErrorKind::YKPIV_PARSE_ERROR
- } else {
- dataptr = dataptr.offset(1isize);
- dataptr =
- dataptr.offset(_ykpiv_get_length(dataptr, &mut len as (*mut usize)) as (isize));
- (if len > *out_len {
- if (*state).verbose != 0 {
- eprintln!("Wrong size on output buffer.");
- }
- ErrorKind::YKPIV_SIZE_ERROR
- } else {
- *out_len = len;
- memcpy(out as (*mut c_void), dataptr as (*const c_void), len);
- ErrorKind::YKPIV_OK
- })
- })
- }
-}
-
-pub fn ykpiv_sign_data(
- mut state: *mut ykpiv_state,
- mut raw_in: *const u8,
- mut in_len: usize,
- mut sign_out: *mut u8,
- mut out_len: *mut usize,
- mut algorithm: u8,
- mut key: u8,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- res = _general_authenticate(
- state, raw_in, in_len, sign_out, out_len, algorithm, key, false,
- );
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn ykpiv_decipher_data(
- mut state: *mut ykpiv_state,
- mut in_: *const u8,
- mut in_len: usize,
- mut out: *mut u8,
- mut out_len: *mut usize,
- mut algorithm: u8,
- mut key: u8,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- res = _general_authenticate(state, in_, in_len, out, out_len, algorithm, key, true);
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-unsafe fn _ykpiv_get_version(
- mut state: *mut ykpiv_state,
- mut p_version: *mut _ykpiv_version_t,
-) -> ErrorKind {
- let mut apdu: APDU;
- let mut data: [u8; 261];
- let mut recv_len: u32 = mem::size_of::<[u8; 261]>() as (u32);
- let mut sw: i32;
- let mut res: ErrorKind;
- if state.is_null() {
- ErrorKind::YKPIV_ARGUMENT_ERROR
- } else if (*state).ver.major != 0 || (*state).ver.minor != 0 || (*state).ver.patch != 0 {
- if !p_version.is_null() {
- memcpy(
- p_version as (*mut c_void),
- &mut (*state).ver as (*mut _ykpiv_version_t) as (*const c_void),
- mem::size_of::<_ykpiv_version_t>(),
- );
- }
- ErrorKind::YKPIV_OK
- // get version from device
- // FIXME(tarcieri): Translate C code below (should go after the else clause)
- /*
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_GET_VERSION;
- */
- } else if {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- res
- } else {
- if sw == 0x9000i32 {
- if recv_len < 3u32 {
- return ErrorKind::YKPIV_SIZE_ERROR;
- } else {
- (*state).ver.major = data[0usize];
- (*state).ver.minor = data[1usize];
- (*state).ver.patch = data[2usize];
- if !p_version.is_null() {
- memcpy(
- p_version as (*mut c_void),
- &mut (*state).ver as (*mut _ykpiv_version_t) as (*const c_void),
- mem::size_of::<_ykpiv_version_t>(),
- );
- }
- }
- } else {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- }
- res
- }
-}
-
-pub fn ykpiv_get_version(
- mut state: *mut ykpiv_state,
- mut version: *mut u8,
- mut len: usize,
-) -> ErrorKind {
- let mut res: ErrorKind;
- let mut result: i32 = 0i32;
- let mut ver: _ykpiv_version_t = _ykpiv_version_t {
- major: 0u8,
- minor: 0u8,
- patch: 0u8,
- };
- if {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- < ErrorKind::YKPIV_OK as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !({
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32)
- < ErrorKind::YKPIV_OK as (i32))
- {
- if {
- res = _ykpiv_get_version(state, &mut ver as (*mut _ykpiv_version_t));
- res
- } as (i32)
- >= ErrorKind::YKPIV_OK as (i32)
- {
- result = snprintf(
- version,
- len,
- (*b"%d.%d.%d\0").as_ptr(),
- ver.major as (i32),
- ver.minor as (i32),
- ver.patch as (i32),
- );
- if result < 0i32 {
- res = ErrorKind::YKPIV_SIZE_ERROR;
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-unsafe fn _ykpiv_get_serial(
- mut state: *mut ykpiv_state,
- mut p_serial: *mut u32,
- mut f_force: bool,
-) -> ErrorKind {
- let mut _currentBlock;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut apdu: APDU;
- let mut yk_applet: *const u8 = 0xa0i32 as (*const u8);
- let mut data: [u8; 255];
- let mut recv_len: u32 = mem::size_of::<[u8; 255]>() as (u32);
- let mut sw: i32;
- let mut p_temp: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- if state.is_null() {
- ErrorKind::YKPIV_ARGUMENT_ERROR
- } else if !f_force && ((*state).serial != 0u32) {
- if !p_serial.is_null() {
- *p_serial = (*state).serial;
- }
- ErrorKind::YKPIV_OK
- } else {
- if (*state).ver.major as (i32) < 5i32 {
- let mut temp: [u8; 255];
- recv_len = mem::size_of::<[u8; 255]>() as (u32);
- // FIXME(tarcieri): Translate C code below
- /*
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
- apdu.st.p1 = 0x04;
- apdu.st.lc = sizeof(yk_applet);
- memcpy(apdu.st.data, yk_applet, sizeof(yk_applet));
- */
- if {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- temp.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- < ErrorKind::YKPIV_OK as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed communicating with card: \'{}\'",
- ykpiv_strerror(res)
- );
- _currentBlock = 37;
- } else {
- _currentBlock = 37;
- }
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed selecting yk application: {:04x}", sw);
- }
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- _currentBlock = 37;
- } else {
- recv_len = mem::size_of::<[u8; 255]>() as (u32);
- // FIXME(tarcieri): Translate C code below
- /*
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = 0x01;
- apdu.st.p1 = 0x10;
- apdu.st.lc = 0x00;
- */
- if {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- < ErrorKind::YKPIV_OK as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed communicating with card: \'{}\'",
- ykpiv_strerror(res)
- );
- _currentBlock = 37;
- } else {
- _currentBlock = 37;
- }
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed retrieving serial number: {:04x}", sw);
- }
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- _currentBlock = 37;
- } else {
- recv_len = mem::size_of::<[u8; 255]>() as (u32);
- // FIXME(tarcieri): Translate C code below
- /*
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
- apdu.st.p1 = 0x04;
- apdu.st.lc = (unsigned char)sizeof(aid);
- memcpy(apdu.st.data, aid, sizeof(aid));
- */
- if {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- temp.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- < ErrorKind::YKPIV_OK as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed communicating with card: \'{}\'",
- ykpiv_strerror(res)
- );
- }
- return res;
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed selecting application: {:04x}", sw);
- }
- return ErrorKind::YKPIV_GENERIC_ERROR;
- }
- _currentBlock = 17;
- }
- }
- } else {
- // get serial from yk5 and later devices using the f8 command
- // FIXME(tarcieri): Translate C code below
- /*
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_GET_SERIAL;
- */
-
- if {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed communicating with card: \'{}\'",
- ykpiv_strerror(res)
- );
- }
- return res;
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed retrieving serial number: {:04x}", sw);
- }
- return ErrorKind::YKPIV_GENERIC_ERROR;
- }
- _currentBlock = 17;
- }
- if _currentBlock == 17 {
- if recv_len < 4u32 {
- return ErrorKind::YKPIV_SIZE_ERROR;
- } else {
- p_temp = &mut (*state).serial as (*mut u32) as (*mut u8);
- *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- } = data[3usize];
- *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- } = data[2usize];
- *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- } = data[1usize];
- *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- } = data[0usize];
- if !p_serial.is_null() {
- *p_serial = (*state).serial;
- }
- }
- }
- res
- }
-}
-
-pub fn ykpiv_get_serial(mut state: *mut ykpiv_state, mut p_serial: *mut u32) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- if {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !({
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32))
- {
- res = _ykpiv_get_serial(state, p_serial, false);
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-unsafe fn _cache_pin(
- mut state: *mut ykpiv_state,
- mut pin: *const c_char,
- mut len: usize,
-) -> ErrorKind {
- if state.is_null() {
- return ErrorKind::YKPIV_ARGUMENT_ERROR;
- }
-
- if !pin.is_null() && ((*state).pin as *const c_char == pin) {
- return ErrorKind::YKPIV_OK;
- }
-
- if !(*state).pin.is_null() {
- memset_s(
- (*state).pin as (*mut c_void),
- strnlen((*state).pin as *const c_char, 8),
- 0,
- strnlen((*state).pin as *const c_char, 8),
- );
- free((*state).pin as (*mut c_void));
- (*state).pin = ptr::null_mut();
- }
- if !pin.is_null() && (len > 0) {
- (*state).pin = malloc(len + 1) as (*mut u8);
- if (*state).pin == 0i32 as (*mut c_void) as (*mut u8) {
- return ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- memcpy((*state).pin as (*mut c_void), pin as (*const c_void), len);
- *(*state).pin.offset(len as (isize)) = 0u8;
- }
- }
-
- ErrorKind::YKPIV_OK
-}
-
-pub fn ykpiv_verify(
- mut state: *mut ykpiv_state,
- mut pin: *const c_char,
- mut tries: *mut i32,
-) -> ErrorKind {
- ykpiv_verify_select(
- state,
- pin,
- if !pin.is_null() { strlen(pin) } else { 0 },
- tries,
- false,
- )
-}
-
-unsafe fn _verify(
- mut state: *mut ykpiv_state,
- mut pin: *const c_char,
- pin_len: usize,
- mut tries: *mut i32,
-) -> ErrorKind {
- let mut apdu: APDU;
- let mut data: [u8; 261];
- let mut recv_len: u32 = mem::size_of::<[u8; 261]>() as (u32);
- let mut sw: i32;
- let mut res: ErrorKind;
- if pin_len > 8usize {
- ErrorKind::YKPIV_SIZE_ERROR
- } else {
- // FIXME(tarcieri): Translate C code below
- /*
- memset(apdu.raw, 0, sizeof(apdu.raw));
- apdu.st.ins = YKPIV_INS_VERIFY;
- apdu.st.p1 = 0x00;
- apdu.st.p2 = 0x80;
- apdu.st.lc = pin ? 0x08 : 0;
- if (pin) {
- memcpy(apdu.st.data, pin, pin_len);
- if (pin_len < CB_PIN_MAX) {
- memset(apdu.st.data + pin_len, 0xff, CB_PIN_MAX - pin_len);
- }
- }
- */
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- memset_s(
- &mut apdu as (*mut APDU) as (*mut c_void),
- mem::size_of::(),
- 0i32,
- mem::size_of::(),
- );
- (if res as (i32) != ErrorKind::YKPIV_OK as (i32) {
- res
- } else if sw == 0x9000i32 {
- if !pin.is_null() && (pin_len != 0) {
- _cache_pin(state, pin, pin_len);
- }
- if !tries.is_null() {
- *tries = sw & 0xfi32;
- }
- ErrorKind::YKPIV_OK
- } else if sw >> 8i32 == 0x63i32 {
- if !tries.is_null() {
- *tries = sw & 0xfi32;
- }
- ErrorKind::YKPIV_WRONG_PIN
- } else if sw == 0x6983i32 {
- if !tries.is_null() {
- *tries = 0i32;
- }
- ErrorKind::YKPIV_WRONG_PIN
- } else {
- ErrorKind::YKPIV_GENERIC_ERROR
- })
- }
-}
-
-pub fn ykpiv_verify_select(
- mut state: *mut ykpiv_state,
- mut pin: *const c_char,
- pin_len: usize,
- mut tries: *mut i32,
- mut force_select: bool,
-) -> ErrorKind {
- let mut _currentBlock;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if force_select {
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32)
- {
- _currentBlock = 4;
- } else {
- _currentBlock = 3;
- }
- } else {
- _currentBlock = 3;
- }
- if _currentBlock == 3 {
- res = _verify(state, pin, pin_len, tries);
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn ykpiv_get_pin_retries(mut state: *mut ykpiv_state, mut tries: *mut i32) -> ErrorKind {
- let mut res: ErrorKind;
- let mut ykrc: ErrorKind;
-
- if state.is_null() || tries.is_null() {
- return ErrorKind::YKPIV_ARGUMENT_ERROR;
- }
-
- res = _ykpiv_select_application(state);
-
- if res != ErrorKind::YKPIV_OK {
- return res;
- }
-
- ykrc = ykpiv_verify(state, ptr::null(), tries);
-
- if ykrc == ErrorKind::YKPIV_WRONG_PIN {
- ErrorKind::YKPIV_OK
- } else {
- ykrc
- }
-}
-
-pub fn ykpiv_set_pin_retries(
- mut state: *mut ykpiv_state,
- mut pin_tries: i32,
- mut puk_tries: i32,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut data: [u8; 255];
- let mut recv_len: usize = mem::size_of::<[u8; 255]>();
- let mut sw: i32 = 0i32;
- if pin_tries == 0i32 || puk_tries == 0i32 {
- ErrorKind::YKPIV_OK
- } else if pin_tries > 0xffi32 || puk_tries > 0xffi32 || pin_tries < 1i32 || puk_tries < 1i32 {
- ErrorKind::YKPIV_RANGE_ERROR
- } else {
- *templ.offset(2isize) = pin_tries as (u8);
- *templ.offset(3isize) = puk_tries as (u8);
- (if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- res = ykpiv_transfer_data(
- state,
- templ as (*const u8),
- 0i32 as (*mut c_void) as (*const u8),
- 0isize,
- data.as_mut_ptr(),
- &mut recv_len as (*mut usize),
- &mut sw as (*mut i32),
- );
- if ErrorKind::YKPIV_OK as (i32) == res as (i32) {
- if !(0x9000i32 == sw) {
- if sw == 0x6983i32 {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- } else if sw == 0x6982i32 {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- } else {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- }
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
- })
- }
-}
-
-unsafe fn _ykpiv_change_pin(
- mut state: *mut ykpiv_state,
- mut action: i32,
- mut current_pin: *const c_char,
- mut current_pin_len: usize,
- mut new_pin: *const c_char,
- mut new_pin_len: usize,
- mut tries: *mut i32,
-) -> ErrorKind {
- let mut sw: i32;
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut indata: [u8; 16];
- let mut data: [u8; 255];
- let mut recv_len: usize = mem::size_of::<[u8; 255]>();
- let mut res: ErrorKind;
- if current_pin_len > 8usize {
- ErrorKind::YKPIV_SIZE_ERROR
- } else if new_pin_len > 8usize {
- ErrorKind::YKPIV_SIZE_ERROR
- } else {
- if action == 1i32 {
- *templ.offset(1isize) = 0x2cu8;
- } else if action == 2i32 {
- *templ.offset(3isize) = 0x81u8;
- }
- memcpy(
- indata.as_mut_ptr() as (*mut c_void),
- current_pin as (*const c_void),
- current_pin_len,
- );
- if current_pin_len < 8usize {
- memset(
- indata.as_mut_ptr().offset(current_pin_len as (isize)) as (*mut c_void),
- 0xffi32,
- 8usize.wrapping_sub(current_pin_len),
- );
- }
- memcpy(
- indata.as_mut_ptr().offset(8isize) as (*mut c_void),
- new_pin as (*const c_void),
- new_pin_len,
- );
- if new_pin_len < 8usize {
- memset(
- indata
- .as_mut_ptr()
- .offset(8isize)
- .offset(new_pin_len as (isize)) as (*mut c_void),
- 0xffi32,
- 8usize.wrapping_sub(new_pin_len),
- );
- }
- res = ykpiv_transfer_data(
- state,
- templ as (*const u8),
- indata.as_mut_ptr() as (*const u8),
- mem::size_of::<[u8; 16]>() as (isize),
- data.as_mut_ptr(),
- &mut recv_len as (*mut usize),
- &mut sw as (*mut i32),
- );
- memset_s(
- indata.as_mut_ptr() as (*mut c_void),
- mem::size_of::<[u8; 16]>(),
- 0i32,
- mem::size_of::<[u8; 16]>(),
- );
- (if res as (i32) != ErrorKind::YKPIV_OK as (i32) {
- res
- } else if sw != 0x9000i32 {
- (if sw >> 8i32 == 0x63i32 {
- if !tries.is_null() {
- *tries = sw & 0xfi32;
- }
- ErrorKind::YKPIV_WRONG_PIN
- } else if sw == 0x6983i32 {
- ErrorKind::YKPIV_PIN_LOCKED
- } else {
- if (*state).verbose != 0 {
- eprintln!("Failed changing pin, token response code: {:x}.", sw);
- }
- ErrorKind::YKPIV_GENERIC_ERROR
- })
- } else {
- ErrorKind::YKPIV_OK
- })
- }
-}
-
-pub fn ykpiv_change_pin(
- mut state: *mut ykpiv_state,
- mut current_pin: *const c_char,
- mut current_pin_len: usize,
- mut new_pin: *const c_char,
- mut new_pin_len: usize,
- mut tries: *mut i32,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_GENERIC_ERROR;
-
- if _ykpiv_begin_transaction(state) != ErrorKind::YKPIV_OK {
- return ErrorKind::YKPIV_PCSC_ERROR;
- }
-
- if _ykpiv_ensure_application_selected(state) == ErrorKind::YKPIV_OK {
- res = _ykpiv_change_pin(
- state,
- 0i32,
- current_pin,
- current_pin_len,
- new_pin,
- new_pin_len,
- tries,
- );
-
- if res == ErrorKind::YKPIV_OK && !new_pin.is_null() {
- _cache_pin(state, new_pin, new_pin_len);
- }
- }
-
- _ykpiv_end_transaction(state);
- res
-}
-
-pub fn ykpiv_change_puk(
- mut state: *mut ykpiv_state,
- mut current_puk: *const c_char,
- mut current_puk_len: usize,
- mut new_puk: *const c_char,
- mut new_puk_len: usize,
- mut tries: *mut i32,
-) -> ErrorKind {
- let mut res = ErrorKind::YKPIV_GENERIC_ERROR;
-
- if _ykpiv_begin_transaction(state) != ErrorKind::YKPIV_OK {
- return ErrorKind::YKPIV_PCSC_ERROR;
- }
-
- if _ykpiv_ensure_application_selected(state) == ErrorKind::YKPIV_OK {
- res = _ykpiv_change_pin(
- state,
- 2,
- current_puk,
- current_puk_len,
- new_puk,
- new_puk_len,
- tries,
- );
- }
-
- _ykpiv_end_transaction(state);
- res
-}
-
-pub fn ykpiv_unblock_pin(
- mut state: *mut ykpiv_state,
- mut puk: *const c_char,
- mut puk_len: usize,
- mut new_pin: *const c_char,
- mut new_pin_len: usize,
- mut tries: *mut i32,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_GENERIC_ERROR;
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- res = _ykpiv_change_pin(state, 1i32, puk, puk_len, new_pin, new_pin_len, tries);
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn ykpiv_fetch_object(
- mut state: *mut ykpiv_state,
- mut object_id: i32,
- mut data: *mut u8,
- mut len: *mut usize,
-) -> ErrorKind {
- let mut res: ErrorKind;
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- res = _ykpiv_fetch_object(state, object_id, data, len);
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-unsafe fn set_object(mut object_id: i32, mut buffer: *mut u8) -> *mut u8 {
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = 0x5cu8;
- if object_id == 0x7ei32 {
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = 1u8;
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = 0x7eu8;
- } else if object_id > 0xffffi32 && (object_id <= 0xffffffi32) {
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = 3u8;
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = (object_id >> 16i32 & 0xffi32) as (u8);
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = (object_id >> 8i32 & 0xffi32) as (u8);
- *{
- let _old = buffer;
- buffer = buffer.offset(1isize);
- _old
- } = (object_id & 0xffi32) as (u8);
- }
- buffer
-}
-
-pub fn _ykpiv_fetch_object(
- mut state: *mut ykpiv_state,
- mut object_id: i32,
- mut data: *mut u8,
- mut len: *mut usize,
-) -> ErrorKind {
- let mut sw: i32;
- let mut indata: [u8; 5];
- let mut inptr: *mut u8 = indata.as_mut_ptr();
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut res: ErrorKind;
- inptr = set_object(object_id, inptr);
- if inptr == 0i32 as (*mut c_void) as (*mut u8) {
- ErrorKind::YKPIV_INVALID_OBJECT
- } else if {
- res = ykpiv_transfer_data(
- state,
- templ as (*const u8),
- indata.as_mut_ptr() as (*const u8),
- (inptr as (isize)).wrapping_sub(indata.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize),
- data,
- len,
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- res
- } else if sw == 0x9000i32 {
- let mut outlen: usize = 0usize;
- let mut offs: u32 = 0u32;
- (if *len < 2usize
- || !_ykpiv_has_valid_length(
- data.offset(1isize) as (*const u8),
- (*len).wrapping_sub(1usize),
- )
- {
- ErrorKind::YKPIV_SIZE_ERROR
- } else {
- offs = _ykpiv_get_length(
- data.offset(1isize) as (*const u8),
- &mut outlen as (*mut usize),
- );
- (if offs == 0u32 {
- ErrorKind::YKPIV_SIZE_ERROR
- } else if outlen.wrapping_add(offs as (usize)).wrapping_add(1usize) != *len {
- if (*state).verbose != 0 {
- eprintln!(
- "Invalid length indicated in object, total objlen is {}, indicated length is {}.",
- *len,
- outlen
- );
- }
- ErrorKind::YKPIV_SIZE_ERROR
- } else {
- memmove(
- data as (*mut c_void),
- data.offset(1isize).offset(offs as (isize)) as (*const c_void),
- outlen,
- );
- *len = outlen;
- ErrorKind::YKPIV_OK
- })
- })
- } else {
- ErrorKind::YKPIV_GENERIC_ERROR
- }
-}
-
-pub fn ykpiv_save_object(
- mut state: *mut ykpiv_state,
- mut object_id: i32,
- mut indata: *mut u8,
- mut len: usize,
-) -> ErrorKind {
- let mut res: ErrorKind;
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- res = _ykpiv_save_object(state, object_id, indata, len);
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn _ykpiv_save_object(
- mut state: *mut ykpiv_state,
- mut object_id: i32,
- mut indata: *mut u8,
- mut len: usize,
-) -> ErrorKind {
- let mut data: [u8; 3072];
- let mut dataptr: *mut u8 = data.as_mut_ptr();
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut sw: i32;
- let mut res: ErrorKind;
- let mut outlen: usize = 0usize;
- if len > mem::size_of::<[u8; 3072]>().wrapping_sub(9usize) {
- ErrorKind::YKPIV_SIZE_ERROR
- } else {
- dataptr = set_object(object_id, dataptr);
- (if dataptr == 0i32 as (*mut c_void) as (*mut u8) {
- ErrorKind::YKPIV_INVALID_OBJECT
- } else {
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 0x53u8;
- dataptr = dataptr.offset(_ykpiv_set_length(dataptr, len) as (isize));
- memcpy(dataptr as (*mut c_void), indata as (*const c_void), len);
- dataptr = dataptr.offset(len as (isize));
- (if {
- res = _ykpiv_transfer_data(
- state,
- templ as (*const u8),
- data.as_mut_ptr() as (*const u8),
- (dataptr as (isize)).wrapping_sub(data.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize),
- 0i32 as (*mut c_void) as (*mut u8),
- &mut outlen as (*mut usize),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32)
- {
- res
- } else if 0x9000i32 == sw {
- ErrorKind::YKPIV_OK
- } else if 0x6982i32 == sw {
- ErrorKind::YKPIV_AUTHENTICATION_ERROR
- } else {
- ErrorKind::YKPIV_GENERIC_ERROR
- })
- })
- }
-}
-
-pub fn ykpiv_import_private_key(
- mut state: *mut ykpiv_state,
- key: u8,
- mut algorithm: u8,
- mut p: *const u8,
- mut p_len: usize,
- mut q: *const u8,
- mut q_len: usize,
- mut dp: *const u8,
- mut dp_len: usize,
- mut dq: *const u8,
- mut dq_len: usize,
- mut qinv: *const u8,
- mut qinv_len: usize,
- mut ec_data: *const u8,
- mut ec_data_len: u8,
- pin_policy: u8,
- touch_policy: u8,
-) -> ErrorKind {
- let mut _currentBlock;
- let mut key_data: [u8; 1024];
- let mut in_ptr: *mut u8 = key_data.as_mut_ptr();
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut data: [u8; 256];
- let mut recv_len: usize = mem::size_of::<[u8; 256]>();
- let mut elem_len: u32;
- let mut sw: i32;
- let mut params: [*const u8; 5];
- let mut lens: [usize; 5];
- let mut padding: usize;
- let mut n_params: u8;
- let mut i: i32;
- let mut param_tag: i32;
- let mut res: ErrorKind;
- if state == 0i32 as (*mut c_void) as (*mut ykpiv_state) {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if key as (i32) == 0x9bi32
- || key as (i32) < 0x82i32
- || key as (i32) > 0x95i32 && (key as (i32) < 0x9ai32)
- || key as (i32) > 0x9ei32 && (key as (i32) != 0xf9i32)
- {
- ErrorKind::YKPIV_KEY_ERROR
- } else if pin_policy as (i32) != 0i32
- && (pin_policy as (i32) != 1i32)
- && (pin_policy as (i32) != 2i32)
- && (pin_policy as (i32) != 3i32)
- {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if touch_policy as (i32) != 0i32
- && (touch_policy as (i32) != 1i32)
- && (touch_policy as (i32) != 2i32)
- && (touch_policy as (i32) != 3i32)
- {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- if algorithm as (i32) == 0x6i32 || algorithm as (i32) == 0x7i32 {
- if p_len
- .wrapping_add(q_len)
- .wrapping_add(dp_len)
- .wrapping_add(dq_len)
- .wrapping_add(qinv_len)
- >= mem::size_of::<[u8; 1024]>()
- {
- return ErrorKind::YKPIV_SIZE_ERROR;
- } else {
- if algorithm as (i32) == 0x6i32 {
- elem_len = 64u32;
- }
- if algorithm as (i32) == 0x7i32 {
- elem_len = 128u32;
- }
- if p == 0i32 as (*mut c_void) as (*const u8)
- || q == 0i32 as (*mut c_void) as (*const u8)
- || dp == 0i32 as (*mut c_void) as (*const u8)
- || dq == 0i32 as (*mut c_void) as (*const u8)
- || qinv == 0i32 as (*mut c_void) as (*const u8)
- {
- return ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- params[0usize] = p;
- lens[0usize] = p_len;
- params[1usize] = q;
- lens[1usize] = q_len;
- params[2usize] = dp;
- lens[2usize] = dp_len;
- params[3usize] = dq;
- lens[3usize] = dq_len;
- params[4usize] = qinv;
- lens[4usize] = qinv_len;
- param_tag = 0x1i32;
- n_params = 5u8;
- }
- }
- } else if algorithm as (i32) == 0x11i32 || algorithm as (i32) == 0x14i32 {
- if ec_data_len as (usize) >= mem::size_of::<[u8; 1024]>() {
- return ErrorKind::YKPIV_SIZE_ERROR;
- } else {
- if algorithm as (i32) == 0x11i32 {
- elem_len = 32u32;
- }
- if algorithm as (i32) == 0x14i32 {
- elem_len = 48u32;
- }
- if ec_data == 0i32 as (*mut c_void) as (*const u8) {
- return ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- params[0usize] = ec_data;
- lens[0usize] = ec_data_len as (usize);
- param_tag = 0x6i32;
- n_params = 1u8;
- }
- }
- } else {
- return ErrorKind::YKPIV_ALGORITHM_ERROR;
- }
- i = 0i32;
- 'loop24: loop {
- if !(i < n_params as (i32)) {
- _currentBlock = 25;
- break;
- }
- let mut remaining: usize;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = (param_tag + i) as (u8);
- in_ptr = in_ptr.offset(_ykpiv_set_length(in_ptr, elem_len as (usize)) as (isize));
- padding = (elem_len as (usize)).wrapping_sub(lens[i as (usize)]);
- remaining = (key_data.as_mut_ptr() as (usize))
- .wrapping_add(mem::size_of::<[u8; 1024]>())
- .wrapping_sub(in_ptr as (usize));
- if padding > remaining {
- _currentBlock = 39;
- break;
- }
- memset(in_ptr as (*mut c_void), 0i32, padding);
- in_ptr = in_ptr.offset(padding as (isize));
- memcpy(
- in_ptr as (*mut c_void),
- params[i as (usize)] as (*const c_void),
- lens[i as (usize)],
- );
- in_ptr = in_ptr.offset(lens[i as (usize)] as (isize));
- i = i + 1;
- }
- if _currentBlock == 25 {
- if pin_policy as (i32) != 0i32 {
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0xaau8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0x1u8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = pin_policy;
- }
- if touch_policy as (i32) != 0i32 {
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0xabu8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0x1u8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = touch_policy;
- }
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- return ErrorKind::YKPIV_PCSC_ERROR;
- } else if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if !({
- res = ykpiv_transfer_data(
- state,
- templ as (*const u8),
- key_data.as_mut_ptr() as (*const u8),
- (in_ptr as (isize)).wrapping_sub(key_data.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize),
- data.as_mut_ptr(),
- &mut recv_len as (*mut usize),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- != ErrorKind::YKPIV_OK as (i32))
- {
- if 0x9000i32 != sw {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- if sw == 0x6982i32 {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- }
- }
- }
- }
- } else {
- res = ErrorKind::YKPIV_ALGORITHM_ERROR;
- }
- memset_s(
- key_data.as_mut_ptr() as (*mut c_void),
- mem::size_of::<[u8; 1024]>(),
- 0i32,
- mem::size_of::<[u8; 1024]>(),
- );
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn ykpiv_attest(
- mut state: *mut ykpiv_state,
- key: u8,
- mut data: *mut u8,
- mut data_len: *mut usize,
-) -> ErrorKind {
- let mut res = ErrorKind::YKPIV_GENERIC_ERROR;
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut sw: i32;
- let mut ul_data_len: usize;
- if state.is_null() || data.is_null() || data_len.is_null() {
- return ErrorKind::YKPIV_ARGUMENT_ERROR;
- }
-
- ul_data_len = *data_len;
-
- if _ykpiv_begin_transaction(state) != ErrorKind::YKPIV_OK {
- return ErrorKind::YKPIV_PCSC_ERROR;
- }
-
- if _ykpiv_ensure_application_selected(state) == ErrorKind::YKPIV_OK {
- res = ykpiv_transfer_data(
- state,
- templ as (*const u8),
- 0i32 as (*mut c_void) as (*const u8),
- 0isize,
- data,
- &mut ul_data_len as (*mut usize),
- &mut sw as (*mut i32),
- );
-
- if res == ErrorKind::YKPIV_OK {
- if 0x9000i32 != sw {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- if 0x6d00i32 == sw {
- res = ErrorKind::YKPIV_NOT_SUPPORTED;
- }
- } else if *data as i32 != 0x30 {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- *data_len = ul_data_len;
- }
- }
- }
-
- _ykpiv_end_transaction(state);
- res
-}
-
-pub fn ykpiv_auth_getchallenge(
- mut state: *mut ykpiv_state,
- mut challenge: *mut u8,
- challenge_len: usize,
-) -> ErrorKind {
- let mut res = ErrorKind::YKPIV_OK;
- let mut data = [0u8; 261];
- let mut recv_len: u32 = mem::size_of::<[u8; 261]>() as (u32);
- let mut sw: i32 = 0i32;
-
- if state.is_null() || challenge.is_null() {
- return ErrorKind::YKPIV_GENERIC_ERROR;
- }
-
- if challenge_len != 8 {
- return ErrorKind::YKPIV_SIZE_ERROR;
- }
-
- if _ykpiv_begin_transaction(state) != ErrorKind::YKPIV_OK {
- return ErrorKind::YKPIV_PCSC_ERROR;
- }
-
- if _ykpiv_ensure_application_selected(state) == ErrorKind::YKPIV_OK {
- let mut apdu = APDU::default();
- apdu.ins = YKPIV_INS_AUTHENTICATE;
- apdu.p1 = YKPIV_ALGO_3DES; // triple des
- apdu.p2 = YKPIV_KEY_CARDMGM; // management key
- apdu.lc = 0x04;
- apdu.data[0] = 0x7c;
- apdu.data[1] = 0x02;
- apdu.data[2] = 0x81; //0x80;
-
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
-
- if res != ErrorKind::YKPIV_OK {
- if sw != 0x9000i32 {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- } else {
- memcpy(
- challenge as (*mut c_void),
- data.as_mut_ptr().offset(4isize) as (*const c_void),
- 8usize,
- );
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
-}
-
-pub fn ykpiv_auth_verifyresponse(
- mut state: *mut ykpiv_state,
- mut response: *mut u8,
- response_len: usize,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut data = [0u8; 261];
- let mut recv_len = data.len() as u32;
- let mut sw: i32 = 0i32;
- let mut apdu = APDU::default();
-
- let mut dataptr = apdu.data.as_mut_ptr();
-
- if state.is_null() || response.is_null() {
- return ErrorKind::YKPIV_GENERIC_ERROR;
- }
-
- if response_len != 8 {
- return ErrorKind::YKPIV_SIZE_ERROR;
- }
-
- if _ykpiv_begin_transaction(state) != ErrorKind::YKPIV_OK {
- return ErrorKind::YKPIV_PCSC_ERROR;
- }
-
- // send the response to the card and a challenge of our own.
- apdu.ins = YKPIV_INS_AUTHENTICATE;
- apdu.p1 = YKPIV_ALGO_3DES; // triple des
- apdu.p2 = YKPIV_KEY_CARDMGM; // management key
-
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 0x7cu8;
-
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 0xau8;
-
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 0x82u8;
-
- *{
- let _old = dataptr;
- dataptr = dataptr.offset(1isize);
- _old
- } = 8u8;
-
- memcpy(
- dataptr as *mut c_void,
- response as *const c_void,
- response_len,
- );
-
- dataptr = dataptr.offset(8isize);
- apdu.lc = (dataptr as usize - apdu.data.as_ptr() as usize)
- .try_into()
- .unwrap();
-
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len,
- &mut sw,
- );
-
- if res == ErrorKind::YKPIV_OK && sw != 0x9000i32 {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- }
-
- apdu.zeroize();
- _ykpiv_end_transaction(state);
- res
-}
-
-static mut MGMT_AID: *const u8 = 0xa0i32 as (*const u8);
-
-pub fn ykpiv_auth_deauthenticate(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut apdu: APDU;
- let mut data: [u8; 255];
- let mut recv_len: u32 = mem::size_of::<[u8; 255]>() as (u32);
- let mut sw: i32;
- if state.is_null() {
- ErrorKind::YKPIV_ARGUMENT_ERROR
- } else if {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- < ErrorKind::YKPIV_OK as (i32)
- {
- res
- } else {
- // FIXME(tarcieri): Translate C code below
- /*
- memset(apdu.raw, 0, sizeof(apdu));
- apdu.st.ins = YKPIV_INS_SELECT_APPLICATION;
- apdu.st.p1 = 0x04;
- apdu.st.lc = sizeof(MGMT_AID);
- memcpy(apdu.st.data, MGMT_AID, sizeof(MGMT_AID));
- */
- if {
- res = _send_data(
- state,
- &mut apdu as (*mut APDU),
- data.as_mut_ptr(),
- &mut recv_len as (*mut u32),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- < ErrorKind::YKPIV_OK as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed communicating with card: \'{}\'",
- ykpiv_strerror(res)
- );
- }
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed selecting mgmt application: {:04x}", sw);
- }
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
+pub use self::yubikey::YubiKey;
diff --git a/src/util.c b/src/util.c
index fb097e8..07aa15d 100644
--- a/src/util.c
+++ b/src/util.c
@@ -90,7 +90,7 @@ static ykpiv_rc _get_metadata_item(uint8_t *data, size_t cb_data, uint8_t tag, u
static ykpiv_rc _set_metadata_item(uint8_t *data, size_t *pcb_data, size_t cb_data_max, uint8_t tag, uint8_t *p_item, size_t cb_item);
static size_t _obj_size_max(ykpiv_state *state) {
- return (state && state->isNEO) ? CB_OBJ_MAX_NEO : CB_OBJ_MAX;
+ return (state && state->is_neo) ? CB_OBJ_MAX_NEO : CB_OBJ_MAX;
}
/*
@@ -215,7 +215,7 @@ ykpiv_devmodel ykpiv_util_devicemodel(ykpiv_state *state) {
if (!state || !state->context || (state->context == (uintptr_t)-1)) {
return DEVTYPE_UNKNOWN;
}
- return (state->isNEO ? DEVTYPE_NEOr3 : DEVTYPE_YK4);
+ return (state->is_neo ? DEVTYPE_NEOr3 : DEVTYPE_YK4);
}
ykpiv_rc ykpiv_util_list_keys(ykpiv_state *state, uint8_t *key_count, ykpiv_key **data, size_t *data_len) {
diff --git a/src/util.rs b/src/util.rs
index aeea831..1f13348 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,3 +1,5 @@
+//! Utility functions
+
// Adapted from yubico-piv-tool:
//
//
@@ -28,1026 +30,1565 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#![allow(non_camel_case_types)]
+#![allow(non_camel_case_types, non_snake_case)]
+#![allow(clippy::missing_safety_doc, clippy::too_many_arguments)]
-use crate::{
- error::ErrorKind,
- internal::{setting_get_bool, SettingBool, SettingSource},
-};
-use libc::{free, memcpy, memmove, time, time_t};
-use std::{ffi::CString, mem, os::raw::c_void};
+use crate::{consts::*, error::ErrorKind, internal::*, yubikey::*};
+use libc::{c_char, calloc, free, memcpy, memmove, realloc, time};
+use std::{ffi::CString, mem, os::raw::c_void, ptr};
+use zeroize::Zeroize;
-extern "C" {
- static mut _DefaultRuneLocale: Struct1;
- fn __maskrune(arg1: i32, arg2: usize) -> i32;
- fn __tolower(arg1: i32) -> i32;
- fn __toupper(arg1: i32) -> i32;
- fn _ykpiv_alloc(state: *mut ykpiv_state, size: usize) -> *mut c_void;
- fn _ykpiv_begin_transaction(state: *mut ykpiv_state) -> ErrorKind;
- fn _ykpiv_end_transaction(state: *mut ykpiv_state) -> ErrorKind;
- fn _ykpiv_ensure_application_selected(state: *mut ykpiv_state) -> ErrorKind;
- fn _ykpiv_fetch_object(
- state: *mut ykpiv_state,
- object_id: i32,
- data: *mut u8,
- len: *mut usize,
- ) -> ErrorKind;
- fn _ykpiv_free(state: *mut ykpiv_state, data: *mut c_void);
- fn _ykpiv_get_length(buffer: *const u8, len: *mut usize) -> u32;
- fn _ykpiv_has_valid_length(buffer: *const u8, len: usize) -> bool;
- fn _ykpiv_prng_generate(buffer: *mut u8, cb_req: usize) -> Enum7;
- fn _ykpiv_realloc(state: *mut ykpiv_state, address: *mut c_void, size: usize) -> *mut c_void;
- fn _ykpiv_save_object(
- state: *mut ykpiv_state,
- object_id: i32,
- indata: *mut u8,
- len: usize,
- ) -> ErrorKind;
- fn _ykpiv_set_length(buffer: *mut u8, length: usize) -> u32;
- fn _ykpiv_transfer_data(
- state: *mut ykpiv_state,
- templ: *const u8,
- in_data: *const u8,
- in_len: isize,
- out_data: *mut u8,
- out_len: *mut usize,
- sw: *mut i32,
- ) -> ErrorKind;
- fn memset_s(__s: *mut c_void, __smax: usize, __c: i32, __n: usize) -> i32;
- fn pkcs5_pbkdf2_sha1(
- password: *const u8,
- cb_password: usize,
- salt: *const u8,
- cb_salt: usize,
- iterations: usize,
- key: *const u8,
- cb_key: usize,
- ) -> Enum11;
- fn ykpiv_change_puk(
- state: *mut ykpiv_state,
- current_puk: *const u8,
- current_puk_len: usize,
- new_puk: *const u8,
- new_puk_len: usize,
- tries: *mut i32,
- ) -> ErrorKind;
- fn ykpiv_set_mgmkey(state: *mut ykpiv_state, new_key: *const u8) -> ErrorKind;
- fn ykpiv_transfer_data(
- state: *mut ykpiv_state,
- templ: *const u8,
- in_data: *const u8,
- in_len: isize,
- out_data: *mut u8,
- out_len: *mut usize,
- sw: *mut i32,
- ) -> ErrorKind;
-}
+/// Cardholder Unique Identifier (CHUID) Template
+///
+/// Format defined in SP-800-73-4, Appendix A, Table 9
+///
+/// FASC-N containing S9999F9999F999999F0F1F0000000000300001E encoded in
+/// 4-bit BCD with 1 bit parity. run through the tools/fasc.pl script to get
+/// bytes. This CHUID has an expiry of 2030-01-01.
+///
+/// Defined fields:
+///
+/// - 0x30: FASC-N (hard-coded)
+/// - 0x34: Card UUID / GUID (settable)
+/// - 0x35: Exp. Date (hard-coded)
+/// - 0x3e: Signature (hard-coded, empty)
+/// - 0xfe: Error Detection Code (hard-coded)
+pub const CHUID_TMPL: &[u8] = &[
+ 0x30, 0x19, 0xd4, 0xe7, 0x39, 0xda, 0x73, 0x9c, 0xed, 0x39, 0xce, 0x73, 0x9d, 0x83, 0x68, 0x58,
+ 0x21, 0x08, 0x42, 0x10, 0x84, 0x21, 0xc8, 0x42, 0x10, 0xc3, 0xeb, 0x34, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x08, 0x32,
+ 0x30, 0x33, 0x30, 0x30, 0x31, 0x30, 0x31, 0x3e, 0x00, 0xfe, 0x00,
+];
-#[derive(Copy)]
-#[repr(C)]
-pub struct __sbuf {
- pub _base: *mut u8,
- pub _size: i32,
-}
+/// Cardholder Capability Container (CCC) Template
+///
+/// f0: Card Identifier
+///
+/// - 0xa000000116 == GSC-IS RID
+/// - 0xff == Manufacturer ID (dummy)
+/// - 0x02 == Card type (javaCard)
+/// - next 14 bytes: card ID
+pub static mut CCC_TMPL: &[u8] = &[
+ 0xf0, 0x15, 0xa0, 0x00, 0x00, 0x01, 0x16, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x21, 0xf2, 0x01, 0x21, 0xf3, 0x00, 0xf4,
+ 0x01, 0x00, 0xf5, 0x01, 0x10, 0xf6, 0x00, 0xf7, 0x00, 0xfa, 0x00, 0xfb, 0x00, 0xfc, 0x00, 0xfd,
+ 0x00, 0xfe, 0x00,
+];
-impl Clone for __sbuf {
- fn clone(&self) -> Self {
- *self
- }
-}
+/// Card ID
+#[derive(Copy, Clone, Debug)]
+pub struct CardId([u8; 16]);
-pub fn isascii(mut _c: i32) -> i32 {
- (_c & !0x7fi32 == 0i32) as (i32)
-}
+/// Get Card ID
+pub unsafe fn ykpiv_util_get_cardid(state: *mut YubiKey, cardid: *mut CardId) -> ErrorKind {
+ let mut buf = [0u8; CB_OBJ_MAX];
+ let mut len = buf.len();
+ let mut res: ErrorKind = ErrorKind::Ok;
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct3 {
- pub __min: i32,
- pub __max: i32,
- pub __map: i32,
- pub __types: *mut u32,
-}
-
-impl Clone for Struct3 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct2 {
- pub __nranges: i32,
- pub __ranges: *mut Struct3,
-}
-
-impl Clone for Struct2 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct4 {
- pub __name: [u8; 14],
- pub __mask: u32,
-}
-
-impl Clone for Struct4 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct1 {
- pub __magic: [u8; 8],
- pub __encoding: [u8; 32],
- pub __sgetrune: unsafe fn(*const u8, usize, *mut *const u8) -> i32,
- pub __sputrune: unsafe fn(i32, *mut u8, usize, *mut *mut u8) -> i32,
- pub __invalid_rune: i32,
- pub __runetype: [u32; 256],
- pub __maplower: [i32; 256],
- pub __mapupper: [i32; 256],
- pub __runetype_ext: Struct2,
- pub __maplower_ext: Struct2,
- pub __mapupper_ext: Struct2,
- pub __variable: *mut c_void,
- pub __variable_len: i32,
- pub __ncharclasses: i32,
- pub __charclasses: *mut Struct4,
-}
-
-impl Clone for Struct1 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn __istype(mut _c: i32, mut _f: usize) -> i32 {
- if isascii(_c) != 0 {
- !(_DefaultRuneLocale.__runetype[_c as (usize)] as (usize) & _f == 0) as (i32)
- } else {
- !(__maskrune(_c, _f) == 0) as (i32)
- }
-}
-
-pub fn __isctype(mut _c: i32, mut _f: usize) -> i32 {
- if _c < 0i32 || _c >= 256i32 {
- 0i32
- } else {
- !(_DefaultRuneLocale.__runetype[_c as (usize)] as (usize) & _f == 0) as (i32)
- }
-}
-
-pub fn __wcwidth(mut _c: i32) -> i32 {
- let mut _x: u32;
- if _c == 0i32 {
- 0i32
- } else {
- _x = __maskrune(_c, 0xe0000000usize | 0x40000usize) as (u32);
- (if _x as (usize) & 0xe0000000usize != 0usize {
- ((_x as (usize) & 0xe0000000usize) >> 30i32) as (i32)
- } else if _x as (usize) & 0x40000usize != 0usize {
- 1i32
- } else {
- -1i32
- })
- }
-}
-
-pub fn isalnum(mut _c: i32) -> i32 {
- __istype(_c, (0x100isize | 0x400isize) as (usize))
-}
-
-pub fn isalpha(mut _c: i32) -> i32 {
- __istype(_c, 0x100usize)
-}
-
-pub fn isblank(mut _c: i32) -> i32 {
- __istype(_c, 0x20000usize)
-}
-
-pub fn iscntrl(mut _c: i32) -> i32 {
- __istype(_c, 0x200usize)
-}
-
-pub fn isdigit(mut _c: i32) -> i32 {
- __isctype(_c, 0x400usize)
-}
-
-pub fn isgraph(mut _c: i32) -> i32 {
- __istype(_c, 0x800usize)
-}
-
-pub fn islower(mut _c: i32) -> i32 {
- __istype(_c, 0x1000usize)
-}
-
-pub fn isprint(mut _c: i32) -> i32 {
- __istype(_c, 0x40000usize)
-}
-
-pub fn ispunct(mut _c: i32) -> i32 {
- __istype(_c, 0x2000usize)
-}
-
-pub fn isspace(mut _c: i32) -> i32 {
- __istype(_c, 0x4000usize)
-}
-
-pub fn isupper(mut _c: i32) -> i32 {
- __istype(_c, 0x8000usize)
-}
-
-pub fn isxdigit(mut _c: i32) -> i32 {
- __isctype(_c, 0x10000usize)
-}
-
-pub fn toascii(mut _c: i32) -> i32 {
- _c & 0x7fi32
-}
-
-pub fn tolower(mut _c: i32) -> i32 {
- __tolower(_c)
-}
-
-pub fn toupper(mut _c: i32) -> i32 {
- __toupper(_c)
-}
-
-pub fn digittoint(mut _c: i32) -> i32 {
- __maskrune(_c, 0xfusize)
-}
-
-pub fn ishexnumber(mut _c: i32) -> i32 {
- __istype(_c, 0x10000usize)
-}
-
-pub fn isideogram(mut _c: i32) -> i32 {
- __istype(_c, 0x80000usize)
-}
-
-pub fn isnumber(mut _c: i32) -> i32 {
- __istype(_c, 0x400usize)
-}
-
-pub fn isphonogram(mut _c: i32) -> i32 {
- __istype(_c, 0x200000usize)
-}
-
-pub fn isrune(mut _c: i32) -> i32 {
- __istype(_c, 0xfffffff0usize)
-}
-
-pub fn isspecial(mut _c: i32) -> i32 {
- __istype(_c, 0x100000usize)
-}
-
-pub static mut CHUID_TMPL: *const u8 = 0x30i32 as (*const u8);
-
-pub static mut CCC_TMPL: *const u8 = 0xf0i32 as (*const u8);
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct6 {
- pub data: [u8; 16],
-}
-
-impl Clone for Struct6 {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn ykpiv_util_get_cardid(mut state: *mut ykpiv_state, mut cardid: *mut Struct6) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf: [u8; 3063];
- let mut len: usize = mem::size_of::<[u8; 3063]>();
if cardid.is_null() {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- res = _ykpiv_fetch_object(
- state,
- 0x5fc102i32,
- buf.as_mut_ptr(),
- &mut len as (*mut usize),
- );
- if ErrorKind::YKPIV_OK as (i32) == res as (i32) {
- if len != 59usize {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- memcpy(
- (*cardid).data.as_mut_ptr() as (*mut c_void),
- buf.as_mut_ptr().offset(29isize) as (*const c_void),
- 16usize,
- );
- }
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_fetch_object(state, YKPIV_OBJ_CHUID as i32, buf.as_mut_ptr(), &mut len);
+
+ if res == ErrorKind::Ok {
+ if len != CHUID_TMPL.len() {
+ res = ErrorKind::GenericError;
+ } else {
+ memcpy(
+ (*cardid).0.as_mut_ptr() as (*mut c_void),
+ buf.as_mut_ptr().add(CHUID_GUID_OFFS) as (*const c_void),
+ YKPIV_CARDID_SIZE,
+ );
}
}
- _ykpiv_end_transaction(state);
- res
}
+
+ _ykpiv_end_transaction(state);
+ res
}
-#[derive(Clone, Copy)]
-#[repr(i32)]
-pub enum Enum7 {
- PRNG_OK = 0i32,
- PRNG_GENERAL_ERROR = -1i32,
-}
+/// Set Card ID
+pub unsafe fn ykpiv_util_set_cardid(state: *mut YubiKey, cardid: *const CardId) -> ErrorKind {
+ let mut id = [0u8; YKPIV_CARDID_SIZE];
+ let mut buf = [0u8; CHUID_TMPL.len()];
+ let mut res = ErrorKind::Ok;
-pub fn ykpiv_util_set_cardid(mut state: *mut ykpiv_state, mut cardid: *const Struct6) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut id: [u8; 16];
- let mut buf: [u8; 59];
- let mut len: usize = 0usize;
if state.is_null() {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- if cardid.is_null() {
- if Enum7::PRNG_OK as (i32)
- != _ykpiv_prng_generate(id.as_mut_ptr(), mem::size_of::<[u8; 16]>()) as (i32)
- {
- return ErrorKind::YKPIV_RANDOMNESS_ERROR;
- }
- } else {
- memcpy(
- id.as_mut_ptr() as (*mut c_void),
- (*cardid).data.as_mut_ptr() as (*const c_void),
- mem::size_of::<[u8; 16]>(),
- );
+ return ErrorKind::GenericError;
+ }
+
+ if cardid.is_null() {
+ if _ykpiv_prng_generate(id.as_mut_ptr(), id.len()) != PRngErrorKind::Ok {
+ return ErrorKind::RandomnessError;
}
- (if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- memcpy(
- buf.as_mut_ptr() as (*mut c_void),
- CHUID_TMPL as (*const c_void),
- 59usize,
- );
- memcpy(
- buf.as_mut_ptr().offset(29isize) as (*mut c_void),
- id.as_mut_ptr() as (*const c_void),
- mem::size_of::<[u8; 16]>(),
- );
- len = 59usize;
- res = _ykpiv_save_object(state, 0x5fc102i32, buf.as_mut_ptr(), len);
- }
- _ykpiv_end_transaction(state);
- res
- })
+ } else {
+ memcpy(
+ id.as_mut_ptr() as (*mut c_void),
+ (*cardid).0.as_ptr() as (*const c_void),
+ id.len(),
+ );
}
-}
-#[derive(Copy)]
-#[repr(C)]
-pub struct Struct8 {
- pub data: [u8; 14],
-}
-
-impl Clone for Struct8 {
- fn clone(&self) -> Self {
- *self
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
}
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ memcpy(
+ buf.as_mut_ptr() as *mut c_void,
+ CHUID_TMPL.as_ptr() as *const c_void,
+ buf.len(),
+ );
+
+ memcpy(
+ buf.as_mut_ptr().add(CHUID_GUID_OFFS) as *mut c_void,
+ id.as_mut_ptr() as *const c_void,
+ id.len(),
+ );
+
+ res = _ykpiv_save_object(
+ state,
+ YKPIV_OBJ_CHUID as i32,
+ buf.as_mut_ptr(),
+ CHUID_TMPL.len(),
+ );
+ }
+
+ _ykpiv_end_transaction(state);
+ res
}
-pub fn ykpiv_util_get_cccid(mut state: *mut ykpiv_state, mut ccc: *mut Struct8) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf: [u8; 3063];
- let mut len: usize = mem::size_of::<[u8; 3063]>();
+/// Cardholder Capability Container (CCC) Identifier
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct CCCID([u8; 14]);
+
+/// Get Cardholder Capability Container (CCC) ID
+pub unsafe fn ykpiv_util_get_cccid(state: *mut YubiKey, ccc: *mut CCCID) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut buf = [0u8; CB_OBJ_MAX];
+ let mut len = buf.len();
+
if ccc.is_null() {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- res = _ykpiv_fetch_object(
- state,
- 0x5fc107i32,
- buf.as_mut_ptr(),
- &mut len as (*mut usize),
- );
- if ErrorKind::YKPIV_OK as (i32) == res as (i32) {
- if len != 51usize {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- memcpy(
- (*ccc).data.as_mut_ptr() as (*mut c_void),
- buf.as_mut_ptr().offset(9isize) as (*const c_void),
- 14usize,
- );
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
+ return ErrorKind::GenericError;
}
-}
-pub fn ykpiv_util_set_cccid(mut state: *mut ykpiv_state, mut ccc: *const Struct8) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut id: [u8; 14];
- let mut buf: [u8; 51];
- let mut len: usize = 0usize;
- if state.is_null() {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- if ccc.is_null() {
- if Enum7::PRNG_OK as (i32)
- != _ykpiv_prng_generate(id.as_mut_ptr(), mem::size_of::<[u8; 14]>()) as (i32)
- {
- return ErrorKind::YKPIV_RANDOMNESS_ERROR;
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_fetch_object(
+ state,
+ YKPIV_OBJ_CAPABILITY as i32,
+ buf.as_mut_ptr(),
+ &mut len,
+ );
+
+ if res == ErrorKind::Ok {
+ if len != CCC_TMPL.len() {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::GenericError;
}
- } else {
+
memcpy(
- id.as_mut_ptr() as (*mut c_void),
- (*ccc).data.as_mut_ptr() as (*const c_void),
- mem::size_of::<[u8; 14]>(),
+ (*ccc).0.as_mut_ptr() as (*mut c_void),
+ buf.as_mut_ptr().offset(9) as (*const c_void),
+ YKPIV_CCCID_SIZE,
);
}
- (if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- len = 51usize;
- memcpy(
- buf.as_mut_ptr() as (*mut c_void),
- CCC_TMPL as (*const c_void),
- len,
- );
- memcpy(
- buf.as_mut_ptr().offset(9isize) as (*mut c_void),
- id.as_mut_ptr() as (*const c_void),
- 14usize,
- );
- res = _ykpiv_save_object(state, 0x5fc107i32, buf.as_mut_ptr(), len);
- }
- _ykpiv_end_transaction(state);
- res
- })
}
+
+ res
}
-#[derive(Copy)]
-#[repr(C)]
-pub struct ykpiv_allocator {
- pub pfn_alloc: unsafe fn(*mut c_void, usize) -> *mut c_void,
- pub pfn_realloc: unsafe fn(*mut c_void, *mut c_void, usize) -> *mut c_void,
- pub pfn_free: unsafe fn(*mut c_void, *mut c_void),
- pub alloc_data: *mut c_void,
-}
+/// Get Cardholder Capability Container (CCC) ID
+pub unsafe fn ykpiv_util_set_cccid(state: *mut YubiKey, ccc: *const CCCID) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut id = [0u8; 14];
+ let mut buf = [0u8; 51];
+ let len: usize;
-impl Clone for ykpiv_allocator {
- fn clone(&self) -> Self {
- *self
+ if state.is_null() {
+ return ErrorKind::GenericError;
}
-}
-#[derive(Copy)]
-#[repr(C)]
-pub struct _ykpiv_version_t {
- pub major: u8,
- pub minor: u8,
- pub patch: u8,
-}
-
-impl Clone for _ykpiv_version_t {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct ykpiv_state {
- pub context: i32,
- pub card: i32,
- pub verbose: i32,
- pub pin: *mut u8,
- pub allocator: ykpiv_allocator,
- pub isNEO: bool,
- pub ver: _ykpiv_version_t,
- pub serial: u32,
-}
-
-impl Clone for ykpiv_state {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn ykpiv_util_devicemodel(mut state: *mut ykpiv_state) -> u32 {
- if state.is_null() || (*state).context == 0 || (*state).context as (usize) == -1i32 as (usize) {
- 0x0u32
+ if ccc.is_null() {
+ if _ykpiv_prng_generate(id.as_mut_ptr(), id.len()) != PRngErrorKind::Ok {
+ return ErrorKind::RandomnessError;
+ }
} else {
- (if (*state).isNEO {
- 0x4e450000i32 | 0x7233i32
- } else {
- 0x594b0000i32 | 0x34i32
- }) as (u32)
+ memcpy(
+ id.as_mut_ptr() as (*mut c_void),
+ (*ccc).0.as_ptr() as (*const c_void),
+ id.len(),
+ );
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ len = 51;
+
+ memcpy(
+ buf.as_mut_ptr() as *mut c_void,
+ CCC_TMPL.as_ptr() as *const c_void,
+ len,
+ );
+
+ memcpy(
+ buf.as_mut_ptr().offset(9) as (*mut c_void),
+ id.as_mut_ptr() as (*const c_void),
+ 14,
+ );
+
+ res = _ykpiv_save_object(state, YKPIV_OBJ_CAPABILITY as i32, buf.as_mut_ptr(), len);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Get YubiKey device model
+pub unsafe fn ykpiv_util_devicemodel(state: *mut YubiKey) -> u32 {
+ if state.is_null() || (*state).context == 0 || (*state).context == -1 {
+ DEVTYPE_UNKNOWN
+ } else if (*state).is_neo {
+ DEVTYPE_NEOr3
+ } else {
+ DEVTYPE_YK4
}
}
-#[derive(Copy)]
-#[repr(C)]
-pub struct _ykpiv_key {
- pub slot: u8,
- pub cert_len: u16,
- pub cert: [u8; 1],
+/// Personal Identity Verification (PIV) keys
+#[derive(Copy, Clone, Debug)]
+pub struct YkPivKey {
+ /// Card slot
+ slot: u8,
+
+ /// Length of cert
+ cert_len: u16,
+
+ /// Cert
+ cert: [u8; 1],
}
-impl Clone for _ykpiv_key {
- fn clone(&self) -> Self {
- *self
- }
-}
+/// Personal Identity Verification (PIV) key slots
+pub const SLOTS: [u8; 24] = [
+ YKPIV_KEY_AUTHENTICATION,
+ YKPIV_KEY_SIGNATURE,
+ YKPIV_KEY_KEYMGM,
+ YKPIV_KEY_RETIRED1,
+ YKPIV_KEY_RETIRED2,
+ YKPIV_KEY_RETIRED3,
+ YKPIV_KEY_RETIRED4,
+ YKPIV_KEY_RETIRED5,
+ YKPIV_KEY_RETIRED6,
+ YKPIV_KEY_RETIRED7,
+ YKPIV_KEY_RETIRED8,
+ YKPIV_KEY_RETIRED9,
+ YKPIV_KEY_RETIRED10,
+ YKPIV_KEY_RETIRED11,
+ YKPIV_KEY_RETIRED12,
+ YKPIV_KEY_RETIRED13,
+ YKPIV_KEY_RETIRED14,
+ YKPIV_KEY_RETIRED15,
+ YKPIV_KEY_RETIRED16,
+ YKPIV_KEY_RETIRED17,
+ YKPIV_KEY_RETIRED18,
+ YKPIV_KEY_RETIRED19,
+ YKPIV_KEY_RETIRED20,
+ YKPIV_KEY_CARDAUTH,
+];
-pub fn ykpiv_util_list_keys(
- mut state: *mut ykpiv_state,
- mut key_count: *mut u8,
- mut data: *mut *mut _ykpiv_key,
- mut data_len: *mut usize,
+/// List Personal Identity Verification (PIV) keys
+// TODO(tarcieri): fix clippy alignment warnings
+#[allow(clippy::cast_ptr_alignment)]
+pub unsafe fn ykpiv_util_list_keys(
+ state: *mut YubiKey,
+ key_count: *mut u8,
+ data: *mut *mut YkPivKey,
+ data_len: *mut usize,
) -> ErrorKind {
let mut _currentBlock;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut pKey: *mut _ykpiv_key = 0i32 as (*mut c_void) as (*mut _ykpiv_key);
- let mut pData: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut pTemp: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cbData: usize = 0usize;
- let mut offset: usize = 0usize;
- let mut buf: [u8; 3072];
- let mut cbBuf: usize = 0usize;
- let mut i: usize = 0usize;
- let mut cbRealloc: usize = 0usize;
- let CB_PAGE: usize = 4096usize;
- let mut SLOTS: *const u8 = 0x9ai32 as (*const u8);
- if 0i32 as (*mut c_void) as (*mut *mut _ykpiv_key) == data
- || 0i32 as (*mut c_void) as (*mut usize) == data_len
- || 0i32 as (*mut c_void) as (*mut u8) == key_count
- {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- *key_count = 0u8;
- *data = 0i32 as (*mut c_void) as (*mut _ykpiv_key);
- *data_len = 0usize;
- if 0i32 as (*mut c_void) as (*mut u8) == {
- pData = _ykpiv_alloc(state, CB_PAGE) as (*mut u8);
- pData
- } {
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- cbData = CB_PAGE;
- i = 0usize;
- 'loop5: loop {
- if !(i < mem::size_of::<*const u8>()) {
- _currentBlock = 6;
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut p_key: *mut YkPivKey;
+ let mut p_data: *mut u8 = ptr::null_mut();
+ let mut p_temp: *mut u8;
+ let mut cb_data: usize;
+ let mut offset: usize = 0;
+ let mut buf = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_buf: usize;
+ let mut i: usize;
+ let mut cb_realloc: usize;
+ let CB_PAGE: usize = 4096;
+
+ if data.is_null() || data_len.is_null() || key_count.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ *key_count = 0;
+ *data = ptr::null_mut();
+ *data_len = 0;
+
+ p_data = calloc(CB_PAGE, 1) as (*mut u8);
+
+ if p_data.is_null() {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::MemoryError;
+ }
+
+ cb_data = CB_PAGE;
+ i = 0;
+
+ loop {
+ if i >= mem::size_of::<*const u8>() {
+ _currentBlock = 6;
+ break;
+ }
+
+ cb_buf = buf.len();
+ res = _read_certificate(state, SLOTS[i], buf.as_mut_ptr(), &mut cb_buf);
+
+ if res == ErrorKind::Ok && (cb_buf > 0) {
+ cb_realloc = if mem::size_of::()
+ .wrapping_add(cb_buf)
+ .wrapping_sub(1)
+ > cb_data.wrapping_sub(offset)
+ {
+ (if mem::size_of::()
+ .wrapping_add(cb_buf)
+ .wrapping_sub(1)
+ .wrapping_sub(cb_data.wrapping_sub(offset))
+ > CB_PAGE
+ {
+ mem::size_of::()
+ .wrapping_add(cb_buf)
+ .wrapping_sub(1)
+ .wrapping_sub(cb_data.wrapping_sub(offset))
+ } else {
+ CB_PAGE
+ })
+ } else {
+ 0
+ };
+
+ if cb_realloc != 0 {
+ if {
+ p_temp = realloc(p_data as (*mut c_void), cb_data.wrapping_add(cb_realloc))
+ as (*mut u8);
+ p_temp
+ }
+ .is_null()
+ {
+ _currentBlock = 15;
break;
}
- cbBuf = mem::size_of::<[u8; 3072]>();
- res = _read_certificate(
- state,
- *SLOTS.offset(i as (isize)),
- buf.as_mut_ptr(),
- &mut cbBuf as (*mut usize),
- );
- if res as (i32) == ErrorKind::YKPIV_OK as (i32) && (cbBuf > 0usize) {
- cbRealloc = if mem::size_of::<_ykpiv_key>()
- .wrapping_add(cbBuf)
- .wrapping_sub(1usize)
- > cbData.wrapping_sub(offset)
- {
- (if mem::size_of::<_ykpiv_key>()
- .wrapping_add(cbBuf)
- .wrapping_sub(1usize)
- .wrapping_sub(cbData.wrapping_sub(offset))
- > CB_PAGE
- {
- mem::size_of::<_ykpiv_key>()
- .wrapping_add(cbBuf)
- .wrapping_sub(1usize)
- .wrapping_sub(cbData.wrapping_sub(offset))
- } else {
- CB_PAGE
- })
- } else {
- 0usize
- };
- if 0usize != cbRealloc {
- if {
- pTemp = _ykpiv_realloc(
- state,
- pData as (*mut c_void),
- cbData.wrapping_add(cbRealloc),
- ) as (*mut u8);
- pTemp
- }
- .is_null()
- {
- _currentBlock = 15;
- break;
- }
- pData = pTemp;
- pTemp = 0i32 as (*mut c_void) as (*mut u8);
- }
- cbData = cbData.wrapping_add(cbRealloc);
- pKey = pData.offset(offset as (isize)) as (*mut _ykpiv_key);
- (*pKey).slot = *SLOTS.offset(i as (isize));
- (*pKey).cert_len = cbBuf as (u16);
- memcpy(
- (*pKey).cert.as_mut_ptr() as (*mut c_void),
- buf.as_mut_ptr() as (*const c_void),
- cbBuf,
- );
- offset = offset.wrapping_add(
- mem::size_of::<_ykpiv_key>()
- .wrapping_add(cbBuf)
- .wrapping_sub(1usize),
- );
- *key_count = (*key_count as (i32) + 1) as (u8);
- }
- i = i.wrapping_add(1usize);
- }
- if _currentBlock == 6 {
- *data = pData as (*mut _ykpiv_key);
- pData = 0i32 as (*mut c_void) as (*mut u8);
- if !data_len.is_null() {
- *data_len = offset;
- }
- res = ErrorKind::YKPIV_OK;
- } else {
- res = ErrorKind::YKPIV_MEMORY_ERROR;
+ p_data = p_temp;
}
+
+ cb_data = cb_data.wrapping_add(cb_realloc);
+ p_key = p_data.add(offset) as *mut YkPivKey;
+ (*p_key).slot = SLOTS[i];
+ (*p_key).cert_len = cb_buf as (u16);
+
+ memcpy(
+ (*p_key).cert.as_mut_ptr() as *mut c_void,
+ buf.as_mut_ptr() as *const c_void,
+ cb_buf,
+ );
+
+ offset = offset.wrapping_add(
+ mem::size_of::()
+ .wrapping_add(cb_buf)
+ .wrapping_sub(1),
+ );
+
+ *key_count = (*key_count as i32 + 1) as u8;
}
+
+ i += 1;
}
- if !pData.is_null() {
- _ykpiv_free(state, pData as (*mut c_void));
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-pub fn ykpiv_util_free(mut _state: *mut ykpiv_state, mut data: *mut c_void) -> ErrorKind {
- if !data.is_null() {
- free(data);
- }
-
- ErrorKind::YKPIV_OK
-}
-
-pub fn ykpiv_util_read_cert(
- mut state: *mut ykpiv_state,
- mut slot: u8,
- mut data: *mut *mut u8,
- mut data_len: *mut usize,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf: [u8; 3072];
- let mut cbBuf: usize = mem::size_of::<[u8; 3072]>();
- if 0i32 as (*mut c_void) as (*mut *mut u8) == data
- || 0i32 as (*mut c_void) as (*mut usize) == data_len
- {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- *data = 0i32 as (*mut u8);
- *data_len = 0usize;
- if ErrorKind::YKPIV_OK as (i32) == {
- res = _read_certificate(state, slot, buf.as_mut_ptr(), &mut cbBuf as (*mut usize));
- res
- } as (i32)
- {
- if cbBuf == 0usize {
- *data = 0i32 as (*mut c_void) as (*mut u8);
- *data_len = 0usize;
- } else if {
- *data = _ykpiv_alloc(state, cbBuf) as (*mut u8);
- *data
- }
- .is_null()
- {
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- memcpy(
- *data as (*mut c_void),
- buf.as_mut_ptr() as (*const c_void),
- cbBuf,
- );
- *data_len = cbBuf;
- }
+ if _currentBlock == 6 {
+ *data = p_data as *mut YkPivKey;
+ p_data = ptr::null_mut();
+ if !data_len.is_null() {
+ *data_len = offset;
}
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn ykpiv_util_write_cert(
- mut state: *mut ykpiv_state,
- mut slot: u8,
- mut data: *mut u8,
- mut data_len: usize,
- mut certinfo: u8,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- res = _write_certificate(state, slot, data, data_len, certinfo);
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub fn ykpiv_util_delete_cert(mut state: *mut ykpiv_state, mut slot: u8) -> ErrorKind {
- ykpiv_util_write_cert(state, slot, 0i32 as (*mut c_void) as (*mut u8), 0usize, 0u8)
-}
-
-pub fn ykpiv_util_block_puk(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut _currentBlock;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut puk: *mut u8 = 0x30i32 as (*mut u8);
- let mut tries: i32 = -1i32;
- let mut data: [u8; 3072];
- let mut cb_data: usize = mem::size_of::<[u8; 3072]>();
- let mut p_item: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_item: usize = 0usize;
- let mut flags: u8 = 0u8;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32)
- {
- _currentBlock = 20;
+ res = ErrorKind::Ok;
} else {
- _currentBlock = 3;
+ res = ErrorKind::MemoryError;
}
- 'loop3: loop {
- if _currentBlock == 3 {
- if tries != 0i32 {
- if ErrorKind::YKPIV_OK as (i32) == {
- res = ykpiv_change_puk(
- state,
- puk as (*const u8),
- mem::size_of::<*mut u8>(),
- puk as (*const u8),
- mem::size_of::<*mut u8>(),
- &mut tries as (*mut i32),
- );
- res
- } as (i32)
- {
- let _rhs = 1;
- let _lhs = &mut *puk.offset(0isize);
- *_lhs = (*_lhs as (i32) + _rhs) as (u8);
- _currentBlock = 3;
- } else {
- if !(ErrorKind::YKPIV_PIN_LOCKED as (i32) == res as (i32)) {
- _currentBlock = 3;
- continue;
- }
- tries = 0i32;
- res = ErrorKind::YKPIV_OK;
- _currentBlock = 3;
- }
+ }
+
+ if !p_data.is_null() {
+ free(p_data as (*mut c_void));
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Read certificate
+pub unsafe fn ykpiv_util_read_cert(
+ state: *mut YubiKey,
+ slot: u8,
+ data: *mut *mut u8,
+ data_len: *mut usize,
+) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut buf = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_buf: usize = buf.len();
+
+ if data.is_null() || data_len.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ *data = ptr::null_mut();
+ *data_len = 0;
+ res = _read_certificate(state, slot, buf.as_mut_ptr(), &mut cb_buf);
+ if res == ErrorKind::Ok {
+ if cb_buf == 0 {
+ *data = ptr::null_mut();
+ *data_len = 0;
+ } else if {
+ *data = calloc(cb_buf, 1) as *mut u8;
+ *data
+ }
+ .is_null()
+ {
+ res = ErrorKind::MemoryError;
+ } else {
+ memcpy(
+ *data as (*mut c_void),
+ buf.as_mut_ptr() as (*const c_void),
+ cb_buf,
+ );
+ *data_len = cb_buf;
+ }
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Write certificate
+pub unsafe fn ykpiv_util_write_cert(
+ state: *mut YubiKey,
+ slot: u8,
+ data: *mut u8,
+ data_len: usize,
+ certinfo: u8,
+) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::Ok;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _write_certificate(state, slot, data, data_len, certinfo);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Delete certificate
+pub unsafe fn ykpiv_util_delete_cert(state: *mut YubiKey, slot: u8) -> ErrorKind {
+ ykpiv_util_write_cert(state, slot, ptr::null_mut(), 0, 0)
+}
+
+/// Block PUK
+pub unsafe fn ykpiv_util_block_puk(state: *mut YubiKey) -> ErrorKind {
+ let mut _currentBlock;
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut puk = [0x30, 0x42, 0x41, 0x44, 0x46, 0x30, 0x30, 0x44];
+ let mut tries: i32 = -1;
+ let mut data = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_data: usize = data.len();
+ let mut p_item: *mut u8 = ptr::null_mut();
+ let mut cb_item: usize = 0;
+ let mut flags: u8 = 0;
+
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ _currentBlock = 20;
+ } else {
+ _currentBlock = 3;
+ }
+
+ loop {
+ if _currentBlock == 3 {
+ if tries != 0 {
+ res = ykpiv_change_puk(
+ state,
+ puk.as_ptr(),
+ mem::size_of::<*const c_char>(),
+ puk.as_ptr(),
+ mem::size_of::<*const c_char>(),
+ &mut tries,
+ );
+
+ if res == ErrorKind::Ok {
+ let _rhs = 1;
+ let mut _lhs = &mut puk[0];
+ *_lhs += _rhs;
+ _currentBlock = 3;
} else {
- if ErrorKind::YKPIV_OK as (i32)
- == _read_metadata(
- state,
- 0x80u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- ) as (i32)
+ if res != ErrorKind::PinLocked {
+ _currentBlock = 3;
+ continue;
+ }
+ tries = 0;
+ res = ErrorKind::Ok;
+ _currentBlock = 3;
+ }
+ } else {
+ let res = _read_metadata(state, TAG_ADMIN, data.as_mut_ptr(), &mut cb_data);
+
+ if res == ErrorKind::Ok {
+ let res = _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ TAG_ADMIN_FLAGS_1,
+ &mut p_item,
+ &mut cb_item,
+ );
+
+ if res == ErrorKind::Ok {
+ if cb_item == 1 {
+ // TODO(tarcieri): get rid of memcpy and pointers, replace with slices!
+ #[allow(trivial_casts)]
+ memcpy(
+ &mut flags as *mut u8 as *mut c_void,
+ p_item as (*const c_void),
+ cb_item,
+ );
+ } else if (*state).verbose != 0 {
+ eprintln!("admin flags exist, but are incorrect size = {}", cb_item,);
+ }
+ }
+ }
+
+ flags |= 0x1;
+
+ if _set_metadata_item(
+ data.as_mut_ptr(),
+ &mut cb_data,
+ CB_OBJ_MAX,
+ TAG_ADMIN_FLAGS_1,
+ &mut flags,
+ 1,
+ ) != ErrorKind::Ok
+ {
+ if (*state).verbose == 0 {
+ _currentBlock = 20;
+ continue;
+ }
+ eprintln!("could not set admin flags");
+ _currentBlock = 20;
+ } else {
+ if _write_metadata(state, 0x80u8, data.as_mut_ptr(), cb_data) == ErrorKind::Ok {
+ _currentBlock = 20;
+ continue;
+ }
+ if (*state).verbose == 0 {
+ _currentBlock = 20;
+ continue;
+ }
+ eprintln!("could not write admin metadata");
+ _currentBlock = 20;
+ }
+ }
+ } else {
+ _ykpiv_end_transaction(state);
+ return res;
+ }
+ }
+}
+
+/// PIV container
+// TODO(tarcieri): dead code?
+#[allow(dead_code)]
+#[derive(Copy, Clone)]
+pub struct YkPivContainer {
+ /// Name
+ name: [i32; 40],
+
+ /// Card slot
+ slot: u8,
+
+ /// Key spec
+ key_spec: u8,
+
+ /// Key size in bits
+ key_size_bits: u16,
+
+ /// Flags
+ flags: u8,
+
+ /// PIN ID
+ pin_id: u8,
+
+ /// Associated ECHD container
+ associated_echd_container: u8,
+
+ /// Cert fingerprint
+ cert_fingerprint: [u8; 20],
+}
+
+/// Read mscmap
+pub unsafe fn ykpiv_util_read_mscmap(
+ state: *mut YubiKey,
+ containers: *mut *mut YkPivContainer,
+ n_containers: *mut usize,
+) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut buf = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_buf: usize = buf.len();
+ let mut len: usize = 0;
+ let mut ptr: *mut u8;
+
+ if containers.is_null() || n_containers.is_null() {
+ res = ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ *containers = ptr::null_mut();
+ *n_containers = 0;
+
+ res = _ykpiv_fetch_object(
+ state,
+ YKPIV_OBJ_MSCMAP as i32,
+ buf.as_mut_ptr(),
+ &mut cb_buf,
+ );
+
+ if res != ErrorKind::Ok {
+ _ykpiv_end_transaction(state);
+ return res;
+ }
+
+ ptr = buf.as_mut_ptr();
+
+ if cb_buf < CB_OBJ_TAG_MIN {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::Ok;
+ }
+
+ if *ptr == TAG_MSCMAP {
+ ptr = ptr.add(1);
+ ptr = ptr.add(_ykpiv_get_length(ptr, &mut len));
+
+ if len > cb_buf - (ptr as isize - buf.as_mut_ptr() as isize) as usize {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::Ok;
+ }
+
+ *containers = calloc(len, 1) as (*mut YkPivContainer);
+
+ if (*containers).is_null() {
+ res = ErrorKind::MemoryError;
+ } else {
+ memcpy(*containers as (*mut c_void), ptr as (*const c_void), len);
+ *n_containers = len.wrapping_div(mem::size_of::());
+ }
+ }
+ }
+
+ res
+}
+
+/// Get max object size
+unsafe fn _obj_size_max(state: *mut YubiKey) -> usize {
+ if !state.is_null() && (*state).is_neo {
+ 2048 - 9
+ } else {
+ CB_OBJ_MAX
+ }
+}
+
+/// Write mscmap
+pub unsafe fn ykpiv_util_write_mscmap(
+ state: *mut YubiKey,
+ containers: *mut YkPivContainer,
+ n_containers: usize,
+) -> ErrorKind {
+ let mut res = ErrorKind::Ok;
+ let mut buf = [0u8; CB_OBJ_MAX];
+ let mut offset: usize = 0;
+ let data_len: usize = n_containers.wrapping_mul(mem::size_of::());
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ if containers.is_null() || n_containers == 0 {
+ if !containers.is_null() || n_containers != 0 {
+ res = ErrorKind::GenericError;
+ } else {
+ res = _ykpiv_save_object(state, YKPIV_OBJ_MSCMAP as i32, ptr::null_mut(), 0);
+ }
+
+ _ykpiv_end_transaction(state);
+ return res;
+ }
+
+ let req_len = 1 + _ykpiv_set_length(buf.as_mut_ptr(), data_len) + data_len;
+
+ if req_len > _obj_size_max(state) {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::SizeError;
+ }
+
+ buf[offset] = 0x81;
+ offset += 1;
+ offset += _ykpiv_set_length(buf.as_mut_ptr().add(offset), data_len);
+ memcpy(
+ buf.as_mut_ptr().add(offset) as (*mut c_void),
+ containers as (*mut u8) as (*const c_void),
+ data_len,
+ );
+ offset = offset.wrapping_add(data_len);
+ res = _ykpiv_save_object(state, YKPIV_OBJ_MSCMAP as i32, buf.as_mut_ptr(), offset);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Read msroots
+pub unsafe fn ykpiv_util_read_msroots(
+ state: *mut YubiKey,
+ data: *mut *mut u8,
+ data_len: *mut usize,
+) -> ErrorKind {
+ let mut _currentBlock;
+ let mut res = ErrorKind::Ok;
+ let mut buf = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_buf: usize;
+ let mut len: usize = 0;
+ let mut ptr: *mut u8;
+ let mut object_id: i32;
+ let mut tag: u8;
+ let mut p_data: *mut u8 = ptr::null_mut();
+ let mut p_temp: *mut u8;
+ let mut cb_data: usize;
+ let mut cb_realloc: usize;
+ let mut offset: usize = 0;
+
+ if data.is_null() || data_len.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ *data = ptr::null_mut();
+ *data_len = 0;
+ cb_data = _obj_size_max(state);
+ p_data = calloc(cb_data, 1) as (*mut u8);
+
+ if p_data.is_null() {
+ res = ErrorKind::MemoryError;
+ } else {
+ object_id = YKPIV_OBJ_MSROOTS1 as i32;
+ loop {
+ if object_id > YKPIV_OBJ_MSROOTS5 as i32 {
+ _currentBlock = 15;
+ break;
+ }
+ cb_buf = buf.len();
+
+ res = _ykpiv_fetch_object(state, object_id, buf.as_mut_ptr(), &mut cb_buf);
+
+ if res != ErrorKind::Ok {
+ _currentBlock = 21;
+ break;
+ }
+
+ ptr = buf.as_mut_ptr();
+ if cb_buf < 2 {
+ _currentBlock = 19;
+ break;
+ }
+
+ tag = *{
+ let _old = ptr;
+ ptr = ptr.offset(1);
+ _old
+ };
+
+ if tag != 0x82 && (tag != 0x83 || object_id == YKPIV_OBJ_MSROOTS5 as i32) {
+ _currentBlock = 18;
+ break;
+ }
+
+ ptr = ptr.add(_ykpiv_get_length(ptr, &mut len));
+
+ if len > cb_buf - (ptr as isize - buf.as_mut_ptr() as isize) as usize {
+ _currentBlock = 17;
+ break;
+ }
+
+ cb_realloc = if len > cb_data.wrapping_sub(offset) {
+ len.wrapping_sub(cb_data.wrapping_sub(offset))
+ } else {
+ 0
+ };
+
+ if cb_realloc != 0 {
+ if {
+ p_temp = realloc(p_data as (*mut c_void), cb_data.wrapping_add(cb_realloc))
+ as (*mut u8);
+ p_temp
+ }
+ .is_null()
{
- if ErrorKind::YKPIV_OK as (i32)
- == _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x81u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- ) as (i32)
- {
- if mem::size_of::() == cb_item {
- memcpy(
- &mut flags as (*mut u8) as (*mut c_void),
- p_item as (*const c_void),
- cb_item,
- );
- } else if (*state).verbose != 0 {
- eprintln!(
- "admin flags exist, but are incorrect size = {}",
- cb_item,
- );
+ _currentBlock = 16;
+ break;
+ }
+ p_data = p_temp;
+ }
+ cb_data = cb_data.wrapping_add(cb_realloc);
+ memcpy(
+ p_data.add(offset) as (*mut c_void),
+ ptr as (*const c_void),
+ len,
+ );
+ offset = offset.wrapping_add(len);
+ if tag == 0x82 {
+ _currentBlock = 15;
+ break;
+ }
+ object_id += 1;
+ }
+ if _currentBlock == 21 {
+ } else if _currentBlock == 15 {
+ *data = p_data;
+ p_data = ptr::null_mut();
+ *data_len = offset;
+ res = ErrorKind::Ok;
+ } else if _currentBlock == 16 {
+ res = ErrorKind::MemoryError;
+ } else {
+ res = ErrorKind::Ok;
+ }
+ }
+ }
+
+ if !p_data.is_null() {
+ free(p_data as (*mut c_void));
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Write msroots
+pub unsafe fn ykpiv_util_write_msroots(
+ state: *mut YubiKey,
+ data: *mut u8,
+ data_len: usize,
+) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut buf = [0u8; CB_OBJ_MAX];
+ let mut offset: usize;
+ let mut data_offset: usize = 0;
+ let mut data_chunk: usize;
+ let n_objs: usize;
+ let cb_obj_max = _obj_size_max(state);
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ if data.is_null() || data_len == 0 {
+ if !data.is_null() || data_len != 0 {
+ res = ErrorKind::GenericError;
+ } else {
+ res = _ykpiv_save_object(state, YKPIV_OBJ_MSROOTS1 as i32, ptr::null_mut(), 0);
+ }
+
+ _ykpiv_end_transaction(state);
+ return res;
+ }
+
+ n_objs = (data_len / (cb_obj_max - 4)) + 1;
+
+ if n_objs > 5 {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::SizeError;
+ }
+
+ for i in 0..n_objs {
+ offset = 0;
+
+ data_chunk = if cb_obj_max - 4 < data_len - data_offset {
+ cb_obj_max - 4
+ } else {
+ data_len - data_offset
+ };
+
+ buf[offset] = if i == n_objs - 1 {
+ TAG_MSROOTS_END
+ } else {
+ TAG_MSROOTS_MID
+ };
+
+ offset += 1;
+ offset += _ykpiv_set_length(buf.as_mut_ptr().add(offset), data_chunk);
+
+ memcpy(
+ buf.as_mut_ptr().add(offset) as *mut c_void,
+ data.add(data_offset) as *const c_void,
+ data_chunk,
+ );
+
+ offset = offset.wrapping_add(data_chunk);
+
+ res = _ykpiv_save_object(
+ state,
+ (YKPIV_OBJ_MSROOTS1 + i as u32) as i32,
+ buf.as_mut_ptr(),
+ offset,
+ );
+
+ if res != ErrorKind::Ok {
+ break;
+ }
+
+ data_offset = data_offset.wrapping_add(data_chunk);
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+// Keygen messages
+// TODO(tarcieri): extract these into an I18N-handling type?
+const SZ_SETTING_ROCA: &str = "Enable_Unsafe_Keygen_ROCA";
+const SZ_ROCA_ALLOW_USER: &str =
+ "was permitted by an end-user configuration setting, but is not recommended.";
+const SZ_ROCA_ALLOW_ADMIN: &str =
+ "was permitted by an administrator configuration setting, but is not recommended.";
+const SZ_ROCA_BLOCK_USER: &str = "was blocked due to an end-user configuration setting.";
+const SZ_ROCA_BLOCK_ADMIN: &str = "was blocked due to an administrator configuration setting.";
+const SZ_ROCA_DEFAULT: &str = "was permitted by default, but is not recommended. The default behavior will change in a future Yubico release.";
+
+/// Generate key
+#[allow(clippy::cognitive_complexity)]
+pub unsafe fn ykpiv_util_generate_key(
+ state: *mut YubiKey,
+ slot: u8,
+ algorithm: u8,
+ pin_policy: u8,
+ touch_policy: u8,
+ modulus: *mut *mut u8,
+ modulus_len: *mut usize,
+ exp: *mut *mut u8,
+ exp_len: *mut usize,
+ point: *mut *mut u8,
+ point_len: *mut usize,
+) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut in_data = [0u8; 11];
+ let mut in_ptr = in_data.as_mut_ptr();
+ let mut data = [0u8; 1024];
+ let mut templ = [0, YKPIV_INS_GENERATE_ASYMMETRIC, 0, 0];
+ let mut recv_len = data.len();
+ let mut sw: i32 = 0;
+ let mut ptr_modulus: *mut u8 = ptr::null_mut();
+ let cb_modulus: usize;
+ let mut ptr_exp: *mut u8 = ptr::null_mut();
+ let cb_exp: usize;
+ let mut ptr_point: *mut u8 = ptr::null_mut();
+ let cb_point: usize;
+ let setting_roca: SettingBool;
+
+ if state.is_null() {
+ return ErrorKind::ArgumentError;
+ }
+
+ if ykpiv_util_devicemodel(state) == DEVTYPE_YK4
+ && (algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048)
+ && (*state).ver.major == 4
+ && ((*state).ver.minor < 3 || (*state).ver.minor == 3 && ((*state).ver.patch < 5))
+ {
+ let setting_name = CString::new(SZ_SETTING_ROCA).unwrap();
+ setting_roca = setting_get_bool(setting_name.as_ptr(), true);
+
+ let psz_msg = match setting_roca.source {
+ SettingSource::User => {
+ if setting_roca.value {
+ SZ_ROCA_ALLOW_USER
+ } else {
+ SZ_ROCA_BLOCK_USER
+ }
+ }
+ SettingSource::Admin => {
+ if setting_roca.value {
+ SZ_ROCA_ALLOW_ADMIN
+ } else {
+ SZ_ROCA_BLOCK_ADMIN
+ }
+ }
+ _ => SZ_ROCA_DEFAULT,
+ };
+
+ eprintln!(
+ "YubiKey serial number {} is affected by vulnerability CVE-2017-15361 \
+ (ROCA) and should be replaced. On-chip key generation {} See \
+ YSA-2017-01 \
+ for additional information on device replacement and mitigation assistance",
+ (*state).serial,
+ psz_msg
+ );
+
+ if !setting_roca.value {
+ return ErrorKind::NotSupported;
+ }
+ }
+
+ match algorithm {
+ YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => {
+ if point.is_null() || point_len.is_null() {
+ if (*state).verbose != 0 {
+ eprintln!("Invalid output parameter for ECC algorithm");
+ }
+ return ErrorKind::GenericError;
+ } else {
+ *point = ptr::null_mut();
+ *point_len = 0;
+ }
+ }
+ YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => {
+ if modulus.is_null() || modulus_len.is_null() || exp.is_null() || exp_len.is_null() {
+ if (*state).verbose != 0 {
+ eprintln!("Invalid output parameter for RSA algorithm",);
+ }
+ return ErrorKind::GenericError;
+ } else {
+ *modulus = ptr::null_mut();
+ *modulus_len = 0;
+ *exp = ptr::null_mut();
+ *exp_len = 0;
+ }
+ }
+ _ => {
+ if (*state).verbose != 0 {
+ eprintln!("Invalid algorithm specified");
+ }
+
+ return ErrorKind::GenericError;
+ }
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ templ[3] = slot;
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = 0xac;
+
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = 3;
+
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = YKPIV_ALGO_TAG;
+
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = 1;
+
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = algorithm;
+
+ if in_data[4] == 0 {
+ res = ErrorKind::AlgorithmError;
+ if (*state).verbose != 0 {
+ eprintln!("Unexpected algorithm.\n");
+ }
+ } else {
+ if pin_policy != YKPIV_PINPOLICY_DEFAULT {
+ let _rhs = 3;
+ let _lhs = &mut in_data[1];
+ *_lhs = (*_lhs as (i32) + _rhs) as (u8);
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = YKPIV_PINPOLICY_TAG;
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = 1u8;
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = pin_policy;
+ }
+
+ if touch_policy != YKPIV_TOUCHPOLICY_DEFAULT {
+ let _rhs = 3i32;
+ let _lhs = &mut in_data[1];
+ *_lhs = (*_lhs as (i32) + _rhs) as (u8);
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = YKPIV_TOUCHPOLICY_TAG;
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = 1u8;
+ *{
+ let _old = in_ptr;
+ in_ptr = in_ptr.offset(1);
+ _old
+ } = touch_policy;
+ }
+
+ res = _ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ in_data.as_mut_ptr(),
+ in_ptr as isize - in_data.as_mut_ptr() as isize,
+ data.as_mut_ptr(),
+ &mut recv_len,
+ &mut sw,
+ );
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!("Failed to communicate.");
+ }
+ } else if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprint!("Failed to generate new key (");
+ }
+
+ match sw {
+ SW_ERR_INCORRECT_SLOT => {
+ res = ErrorKind::KeyError;
+ if (*state).verbose != 0 {
+ eprintln!("incorrect slot)");
+ }
+ }
+ SW_ERR_INCORRECT_PARAM => {
+ res = ErrorKind::AlgorithmError;
+ if (*state).verbose != 0 {
+ if pin_policy as (i32) != 0i32 {
+ eprintln!("pin policy not supported?)",);
+ } else if touch_policy as (i32) != 0i32 {
+ eprintln!("touch policy not supported?)",);
+ } else {
+ eprintln!("algorithm not supported?)",);
}
}
}
- flags = (flags as (i32) | 0x1i32) as (u8);
- if ErrorKind::YKPIV_OK as (i32)
- != _set_metadata_item(
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- 3063usize,
- 0x81u8,
- &mut flags as (*mut u8),
- mem::size_of::(),
- ) as (i32)
- {
- if (*state).verbose == 0 {
- _currentBlock = 20;
- continue;
+ SW_ERR_SECURITY_STATUS => {
+ res = ErrorKind::AuthenticationError;
+ if (*state).verbose != 0 {
+ eprintln!("not authenticated)");
}
- eprintln!("could not set admin flags");
- _currentBlock = 20;
+ }
+ _ => {
+ res = ErrorKind::GenericError;
+ if (*state).verbose != 0 {
+ eprintln!("error {:x})", sw);
+ }
+ }
+ }
+ } else if algorithm == YKPIV_ALGO_RSA1024 || algorithm == YKPIV_ALGO_RSA2048 {
+ let mut data_ptr: *mut u8 = data.as_mut_ptr().offset(5);
+ let mut len: usize = 0;
+ if *data_ptr != TAG_RSA_MODULUS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed to parse public key structure (modulus).");
+ }
+ res = ErrorKind::ParseError;
+ } else {
+ data_ptr = data_ptr.add(1);
+ data_ptr = data_ptr.add(_ykpiv_get_length(data_ptr, &mut len));
+ cb_modulus = len;
+ ptr_modulus = calloc(cb_modulus, 1) as *mut u8;
+ if ptr_modulus.is_null() {
+ if (*state).verbose != 0 {
+ eprintln!("Failed to allocate memory for modulus.");
+ }
+ res = ErrorKind::MemoryError;
} else {
- if !(ErrorKind::YKPIV_OK as (i32)
- != _write_metadata(state, 0x80u8, data.as_mut_ptr(), cb_data) as (i32))
- {
- _currentBlock = 20;
- continue;
+ memcpy(
+ ptr_modulus as *mut c_void,
+ data_ptr as *const c_void,
+ cb_modulus,
+ );
+ data_ptr = data_ptr.add(len);
+ if *data_ptr != TAG_RSA_EXP {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed to parse public key structure (public exponent)."
+ );
+ }
+ res = ErrorKind::ParseError;
+ } else {
+ data_ptr = data_ptr.add(1);
+ data_ptr = data_ptr.add(_ykpiv_get_length(data_ptr, &mut len));
+ cb_exp = len;
+ ptr_exp = calloc(cb_exp, 1) as *mut u8;
+ if ptr_exp.is_null() {
+ if (*state).verbose != 0 {
+ eprintln!("Failed to allocate memory for public exponent.");
+ }
+ res = ErrorKind::MemoryError;
+ } else {
+ memcpy(
+ ptr_exp as (*mut c_void),
+ data_ptr as (*const c_void),
+ cb_exp,
+ );
+ *modulus = ptr_modulus;
+ ptr_modulus = ptr::null_mut();
+ *modulus_len = cb_modulus;
+ *exp = ptr_exp;
+ ptr_exp = ptr::null_mut();
+ *exp_len = cb_exp;
+ }
}
- if (*state).verbose == 0 {
- _currentBlock = 20;
- continue;
+ }
+ }
+ } else if algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384 {
+ let mut data_ptr: *mut u8 = data.as_mut_ptr().offset(3);
+
+ let len = if algorithm == YKPIV_ALGO_ECCP256 {
+ CB_ECC_POINTP256
+ } else {
+ CB_ECC_POINTP384
+ };
+
+ if *{
+ let _old = data_ptr;
+ data_ptr = data_ptr.offset(1);
+ _old
+ } != TAG_ECC_POINT
+ {
+ if (*state).verbose != 0 {
+ eprintln!("Failed to parse public key structure.\n",);
+ }
+ res = ErrorKind::ParseError;
+ } else if *{
+ let _old = data_ptr;
+ data_ptr = data_ptr.offset(1);
+ _old
+ } as (usize)
+ != len
+ {
+ if (*state).verbose != 0 {
+ eprintln!("Unexpected length.\n");
+ }
+ res = ErrorKind::AlgorithmError;
+ } else {
+ cb_point = len;
+ ptr_point = calloc(cb_point, 1) as (*mut u8);
+ if ptr_point.is_null() {
+ if (*state).verbose != 0 {
+ eprintln!("Failed to allocate memory for public point.");
}
- eprintln!("could not write admin metadata");
- _currentBlock = 20;
+ res = ErrorKind::MemoryError;
+ } else {
+ memcpy(
+ ptr_point as (*mut c_void),
+ data_ptr as (*const c_void),
+ cb_point,
+ );
+ *point = ptr_point;
+ ptr_point = ptr::null_mut();
+ *point_len = cb_point;
}
}
} else {
- _ykpiv_end_transaction(state);
- return res;
+ if (*state).verbose != 0 {
+ eprintln!("Wrong algorithm.");
+ }
+ res = ErrorKind::AlgorithmError;
}
}
}
-}
-#[derive(Copy)]
-#[repr(C)]
-pub struct _ykpiv_container {
- pub name: [i32; 40],
- pub slot: u8,
- pub key_spec: u8,
- pub key_size_bits: u16,
- pub flags: u8,
- pub pin_id: u8,
- pub associated_echd_container: u8,
- pub cert_fingerprint: [u8; 20],
-}
-
-impl Clone for _ykpiv_container {
- fn clone(&self) -> Self {
- *self
+ if !ptr_modulus.is_null() {
+ free(modulus as (*mut c_void));
}
+
+ if !ptr_exp.is_null() {
+ free(ptr_exp as (*mut c_void));
+ }
+
+ if !ptr_point.is_null() {
+ free(ptr_exp as (*mut c_void));
+ }
+
+ _ykpiv_end_transaction(state);
+ res
}
-pub fn ykpiv_util_read_mscmap(
- mut state: *mut ykpiv_state,
- mut containers: *mut *mut _ykpiv_container,
- mut n_containers: *mut usize,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf: [u8; 3072];
- let mut cbBuf: usize = mem::size_of::<[u8; 3072]>();
- let mut len: usize = 0usize;
- let mut ptr: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- if 0i32 as (*mut c_void) as (*mut *mut _ykpiv_container) == containers
- || 0i32 as (*mut c_void) as (*mut usize) == n_containers
- {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- return ErrorKind::YKPIV_PCSC_ERROR;
- } else if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- *containers = 0i32 as (*mut _ykpiv_container);
- *n_containers = 0usize;
- if ErrorKind::YKPIV_OK as (i32) == {
- res = _ykpiv_fetch_object(
- state,
- 0x5fff10i32,
- buf.as_mut_ptr(),
- &mut cbBuf as (*mut usize),
- );
- res
- } as (i32)
- {
- ptr = buf.as_mut_ptr();
- if cbBuf < 2usize {
- res = ErrorKind::YKPIV_OK;
- } else if *{
- let _old = ptr;
- ptr = ptr.offset(1isize);
- _old
- } as (i32)
- == 0x81i32
+/// Config mgm type
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+#[repr(i32)]
+#[allow(non_camel_case_types)]
+pub enum YkPivConfigMgmType {
+ /// Manual
+ YKPIV_CONFIG_MGM_MANUAL = 0i32,
+
+ /// Derived
+ YKPIV_CONFIG_MGM_DERIVED = 1i32,
+
+ /// Protected
+ YKPIV_CONFIG_MGM_PROTECTED = 2i32,
+}
+
+/// Config
+#[derive(Copy, Clone)]
+pub struct YkPivConfig {
+ /// Protected data available
+ protected_data_available: u8,
+
+ /// PUK blocked
+ puk_blocked: u8,
+
+ /// No block on upgrade
+ puk_noblock_on_upgrade: u8,
+
+ /// PIN last changed
+ pin_last_changed: u32,
+
+ /// MGM type
+ mgm_type: YkPivConfigMgmType,
+}
+
+/// Get config
+pub unsafe fn ykpiv_util_get_config(state: *mut YubiKey, config: *mut YkPivConfig) -> ErrorKind {
+ let mut data = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_data: usize = mem::size_of::<[u8; YKPIV_OBJ_MAX_SIZE]>();
+ let mut p_item: *mut u8 = ptr::null_mut();
+ let mut cb_item: usize = 0;
+ let res = ErrorKind::Ok;
+
+ if state.is_null() || config.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ (*config).protected_data_available = 0u8;
+ (*config).puk_blocked = 0u8;
+ (*config).puk_noblock_on_upgrade = 0u8;
+ (*config).pin_last_changed = 0u32;
+ (*config).mgm_type = YkPivConfigMgmType::YKPIV_CONFIG_MGM_MANUAL;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ if _read_metadata(state, 0x80u8, data.as_mut_ptr(), &mut cb_data) == ErrorKind::Ok {
+ if _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x81u8,
+ &mut p_item,
+ &mut cb_item,
+ ) == ErrorKind::Ok
{
- ptr = ptr.offset(
- _ykpiv_get_length(ptr as (*const u8), &mut len as (*mut usize)) as (usize)
- as (isize),
- );
- if len
- > cbBuf.wrapping_sub(
- ((ptr as (isize)).wrapping_sub(buf.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize)) as (usize),
- )
- {
- res = ErrorKind::YKPIV_OK;
- } else if 0i32 as (*mut c_void) as (*mut _ykpiv_container) == {
- *containers = _ykpiv_alloc(state, len) as (*mut _ykpiv_container);
- *containers
- } {
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- memcpy(*containers as (*mut c_void), ptr as (*const c_void), len);
- *n_containers = len.wrapping_div(mem::size_of::<_ykpiv_container>());
+ if *p_item & 0x1 != 0 {
+ (*config).puk_blocked = 1u8;
}
+
+ if *p_item & 0x2 != 0 {
+ (*config).mgm_type = YkPivConfigMgmType::YKPIV_CONFIG_MGM_PROTECTED;
+ }
+ }
+ if _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x82u8,
+ &mut p_item,
+ &mut cb_item,
+ ) == ErrorKind::Ok
+ {
+ if (*config).mgm_type as (i32)
+ != YkPivConfigMgmType::YKPIV_CONFIG_MGM_MANUAL as (i32)
+ {
+ if (*state).verbose != 0 {
+ eprintln!("conflicting types of mgm key administration configured");
+ }
+ } else {
+ (*config).mgm_type = YkPivConfigMgmType::YKPIV_CONFIG_MGM_DERIVED;
+ }
+ }
+
+ if _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x83u8,
+ &mut p_item,
+ &mut cb_item,
+ ) == ErrorKind::Ok
+ {
+ if cb_item != 4 {
+ if (*state).verbose != 0 {
+ eprintln!("pin timestamp in admin metadata is an invalid size");
+ }
+ } else {
+ // TODO(tarcieri): get rid of memcpy and pointers, replace with slices!
+ #[allow(trivial_casts)]
+ memcpy(
+ &mut (*config).pin_last_changed as (*mut u32) as (*mut c_void),
+ p_item as (*const c_void),
+ cb_item,
+ );
+ }
+ }
+ }
+ cb_data = mem::size_of::<[u8; YKPIV_OBJ_MAX_SIZE]>();
+ if _read_metadata(state, 0x88u8, data.as_mut_ptr(), &mut cb_data) == ErrorKind::Ok {
+ (*config).protected_data_available = 1u8;
+
+ let res = _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x81u8,
+ &mut p_item,
+ &mut cb_item,
+ );
+
+ if res == ErrorKind::Ok && *p_item as (i32) & 0x1i32 != 0 {
+ (*config).puk_noblock_on_upgrade = 1u8;
+ }
+
+ let res = _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x89u8,
+ &mut p_item,
+ &mut cb_item,
+ );
+
+ if res == ErrorKind::Ok {
+ if (*config).mgm_type != YkPivConfigMgmType::YKPIV_CONFIG_MGM_PROTECTED
+ && (*state).verbose != 0
+ {
+ eprintln!(
+ "conflicting types of mgm key administration configured - protected mgm exists"
+ );
+ }
+ (*config).mgm_type = YkPivConfigMgmType::YKPIV_CONFIG_MGM_PROTECTED;
+ }
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Set PIN last changed
+pub unsafe fn ykpiv_util_set_pin_last_changed(state: *mut YubiKey) -> ErrorKind {
+ let mut data = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_data = data.len();
+ let mut res = ErrorKind::Ok;
+ let ykrc: ErrorKind;
+
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ ykrc = _read_metadata(state, 0x80, data.as_mut_ptr(), &mut cb_data);
+
+ if ykrc != ErrorKind::Ok {
+ cb_data = 0;
+ }
+
+ let mut tnow = time(ptr::null_mut());
+
+ res = {
+ // TODO(tarcieri): get rid of memcpy and pointers, replace with slices!
+ #[allow(trivial_casts)]
+ _set_metadata_item(
+ data.as_mut_ptr(),
+ &mut cb_data,
+ CB_OBJ_MAX,
+ 0x83,
+ &mut tnow as *mut i64 as *mut u8,
+ 4,
+ )
+ };
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!("could not set pin timestamp, err = {}\n", res as (i32),);
+ }
+ } else {
+ res = _write_metadata(state, 0x80u8, data.as_mut_ptr(), cb_data);
+ if res != ErrorKind::Ok && (*state).verbose != 0 {
+ eprintln!("could not write admin data, err = {}", res);
}
}
}
@@ -1055,1263 +1596,269 @@ pub fn ykpiv_util_read_mscmap(
res
}
-unsafe fn _obj_size_max(mut state: *mut ykpiv_state) -> usize {
- (if !state.is_null() && (*state).isNEO {
- 2048i32 - 9i32
- } else {
- 3063i32
- }) as (usize)
-}
+/// Management key (MGM)
+#[derive(Clone)]
+pub struct YkPivMgm([u8; 24]);
-pub fn ykpiv_util_write_mscmap(
- mut state: *mut ykpiv_state,
- mut containers: *mut _ykpiv_container,
- mut n_containers: usize,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf: [u8; 3063];
- let mut offset: usize = 0usize;
- let mut req_len: usize = 0usize;
- let mut data_len: usize = n_containers.wrapping_mul(mem::size_of::<_ykpiv_container>());
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if 0i32 as (*mut c_void) as (*mut _ykpiv_container) == containers
- || 0usize == n_containers
- {
- if 0i32 as (*mut c_void) as (*mut _ykpiv_container) != containers
- || 0usize != n_containers
- {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- res = _ykpiv_save_object(
- state,
- 0x5fff10i32,
- 0i32 as (*mut c_void) as (*mut u8),
- 0usize,
- );
- }
- } else {
- req_len = 1usize
- .wrapping_add(_ykpiv_set_length(buf.as_mut_ptr(), data_len) as (usize))
- .wrapping_add(data_len);
- if req_len > _obj_size_max(state) {
- res = ErrorKind::YKPIV_SIZE_ERROR;
- } else {
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = 0x81u8;
- offset = offset.wrapping_add(_ykpiv_set_length(
- buf.as_mut_ptr().offset(offset as (isize)),
- data_len,
- ) as (usize));
- memcpy(
- buf.as_mut_ptr().offset(offset as (isize)) as (*mut c_void),
- containers as (*mut u8) as (*const c_void),
- data_len,
- );
- offset = offset.wrapping_add(data_len);
- res = _ykpiv_save_object(state, 0x5fff10i32, buf.as_mut_ptr(), offset);
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
+impl Zeroize for YkPivMgm {
+ fn zeroize(&mut self) {
+ self.0.zeroize();
}
}
-pub fn ykpiv_util_read_msroots(
- mut state: *mut ykpiv_state,
- mut data: *mut *mut u8,
- mut data_len: *mut usize,
-) -> ErrorKind {
- let mut _currentBlock;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf: [u8; 3072];
- let mut cbBuf: usize = mem::size_of::<[u8; 3072]>();
- let mut len: usize = 0usize;
- let mut ptr: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut object_id: i32 = 0i32;
- let mut tag: u8 = 0u8;
- let mut pData: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut pTemp: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cbData: usize = 0usize;
- let mut cbRealloc: usize = 0usize;
- let mut offset: usize = 0usize;
- if data.is_null() || data_len.is_null() {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- *data = 0i32 as (*mut u8);
- *data_len = 0usize;
- cbData = _obj_size_max(state);
- if 0i32 as (*mut c_void) as (*mut u8) == {
- pData = _ykpiv_alloc(state, cbData) as (*mut u8);
- pData
- } {
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- object_id = 0x5fff11i32;
- 'loop5: loop {
- if !(object_id <= 0x5fff15i32) {
- _currentBlock = 15;
- break;
- }
- cbBuf = mem::size_of::<[u8; 3072]>();
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_fetch_object(
- state,
- object_id,
- buf.as_mut_ptr(),
- &mut cbBuf as (*mut usize),
- );
- res
- } as (i32)
- {
- _currentBlock = 21;
- break;
- }
- ptr = buf.as_mut_ptr();
- if cbBuf < 2usize {
- _currentBlock = 19;
- break;
- }
- tag = *{
- let _old = ptr;
- ptr = ptr.offset(1isize);
- _old
- };
- if 0x83i32 != tag as (i32) && (0x82i32 != tag as (i32))
- || 0x5fff15i32 == object_id && (0x82i32 != tag as (i32))
- {
- _currentBlock = 18;
- break;
- }
- ptr = ptr.offset(
- _ykpiv_get_length(ptr as (*const u8), &mut len as (*mut usize)) as (isize),
- );
- if len
- > cbBuf.wrapping_sub(
- ((ptr as (isize)).wrapping_sub(buf.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize))
- as (usize),
- )
- {
- _currentBlock = 17;
- break;
- }
- cbRealloc = if len > cbData.wrapping_sub(offset) {
- len.wrapping_sub(cbData.wrapping_sub(offset))
- } else {
- 0usize
- };
- if 0usize != cbRealloc {
- if {
- pTemp = _ykpiv_realloc(
- state,
- pData as (*mut c_void),
- cbData.wrapping_add(cbRealloc),
- ) as (*mut u8);
- pTemp
- }
- .is_null()
- {
- _currentBlock = 16;
- break;
- }
- pData = pTemp;
- pTemp = 0i32 as (*mut c_void) as (*mut u8);
- }
- cbData = cbData.wrapping_add(cbRealloc);
- memcpy(
- pData.offset(offset as (isize)) as (*mut c_void),
- ptr as (*const c_void),
- len,
- );
- offset = offset.wrapping_add(len);
- if 0x82i32 == tag as (i32) {
- _currentBlock = 15;
- break;
- }
- object_id = object_id + 1;
- }
- if _currentBlock == 21 {
- } else if _currentBlock == 15 {
- *data = pData;
- pData = 0i32 as (*mut c_void) as (*mut u8);
- *data_len = offset;
- res = ErrorKind::YKPIV_OK;
- } else if _currentBlock == 16 {
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else if _currentBlock == 17 {
- res = ErrorKind::YKPIV_OK;
- } else if _currentBlock == 18 {
- res = ErrorKind::YKPIV_OK;
- } else {
- res = ErrorKind::YKPIV_OK;
- }
- }
- }
- if !pData.is_null() {
- _ykpiv_free(state, pData as (*mut c_void));
- }
- _ykpiv_end_transaction(state);
- res
+impl Drop for YkPivMgm {
+ fn drop(&mut self) {
+ self.zeroize();
}
}
-pub fn ykpiv_util_write_msroots(
- mut state: *mut ykpiv_state,
- mut data: *mut u8,
- mut data_len: usize,
+/// Get derived management key (MGM)
+pub unsafe fn ykpiv_util_get_derived_mgm(
+ state: *mut YubiKey,
+ pin: *const u8,
+ pin_len: usize,
+ mgm: *mut YkPivMgm,
) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf: [u8; 3063];
- let mut offset: usize = 0usize;
- let mut data_offset: usize = 0usize;
- let mut data_chunk: usize = 0usize;
- let mut n_objs: usize = 0usize;
- let mut i: u32 = 0u32;
- let mut cb_obj_max: usize = _obj_size_max(state);
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if 0i32 as (*mut c_void) as (*mut u8) == data || 0usize == data_len {
- if 0i32 as (*mut c_void) as (*mut u8) != data || 0usize != data_len {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- res = _ykpiv_save_object(
- state,
- 0x5fff11i32,
- 0i32 as (*mut c_void) as (*mut u8),
- 0usize,
- );
- }
- } else {
- n_objs = data_len
- .wrapping_div(cb_obj_max.wrapping_sub((2i32 + 2i32) as (usize)))
- .wrapping_add(1usize);
- if n_objs > 5usize {
- res = ErrorKind::YKPIV_SIZE_ERROR;
- } else {
- i = 0u32;
- 'loop5: loop {
- if !(i as (usize) < n_objs) {
- break;
- }
- offset = 0usize;
- data_chunk = if cb_obj_max.wrapping_sub((2i32 + 2i32) as (usize))
- < data_len.wrapping_sub(data_offset)
- {
- cb_obj_max.wrapping_sub((2i32 + 2i32) as (usize))
- } else {
- data_len.wrapping_sub(data_offset)
- };
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = if i as (usize) == n_objs.wrapping_sub(1usize) {
- 0x82i32
- } else {
- 0x83i32
- } as (u8);
- offset = offset.wrapping_add(_ykpiv_set_length(
- buf.as_mut_ptr().offset(offset as (isize)),
- data_chunk,
- ) as (usize));
- memcpy(
- buf.as_mut_ptr().offset(offset as (isize)) as (*mut c_void),
- data.offset(data_offset as (isize)) as (*const c_void),
- data_chunk,
- );
- offset = offset.wrapping_add(data_chunk);
- res = _ykpiv_save_object(
- state,
- 0x5fff11u32.wrapping_add(i) as (i32),
- buf.as_mut_ptr(),
- offset,
- );
- if ErrorKind::YKPIV_OK as (i32) != res as (i32) {
- break;
- }
- data_offset = data_offset.wrapping_add(data_chunk);
- i = i.wrapping_add(1u32);
- }
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-pub unsafe fn ykpiv_util_generate_key(
- mut state: *mut ykpiv_state,
- mut slot: u8,
- mut algorithm: u8,
- mut pin_policy: u8,
- mut touch_policy: u8,
- mut modulus: *mut *mut u8,
- mut modulus_len: *mut usize,
- mut exp: *mut *mut u8,
- mut exp_len: *mut usize,
- mut point: *mut *mut u8,
- mut point_len: *mut usize,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut in_data: [u8; 11];
- let mut in_ptr: *mut u8 = in_data.as_mut_ptr();
- let mut data: [u8; 1024];
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut recv_len: usize = mem::size_of::<[u8; 1024]>();
- let mut sw: i32;
- let mut ptr_modulus: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_modulus: usize = 0usize;
- let mut ptr_exp: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_exp: usize = 0usize;
- let mut ptr_point: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_point: usize = 0usize;
- let mut setting_roca = SettingBool {
- value: false,
- source: SettingSource::SETTING_SOURCE_DEFAULT,
- };
- let sz_setting_roca: &str = "Enable_Unsafe_Keygen_ROCA";
- let sz_roca_allow_user: &str =
- "was permitted by an end-user configuration setting, but is not recommended.";
- let sz_roca_allow_admin: &str =
- "was permitted by an administrator configuration setting, but is not recommended.";
- let sz_roca_block_user: &str = "was blocked due to an end-user configuration setting.";
- let sz_roca_block_admin: &str = "was blocked due to an administrator configuration setting.";
- let sz_roca_default: &str = "was permitted by default, but is not recommended. The default behavior will change in a future Yubico release.";
+ let mut data = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_data: usize = data.len();
+ let mut p_item: *mut u8 = ptr::null_mut();
+ let mut cb_item: usize = 0;
+ let mut res: ErrorKind = ErrorKind::Ok;
if state.is_null() {
- ErrorKind::YKPIV_ARGUMENT_ERROR
- } else {
- if ykpiv_util_devicemodel(state) == (0x594b0000i32 | 0x34i32) as (u32)
- && (algorithm as (i32) == 0x6i32 || algorithm as (i32) == 0x7i32)
- {
- if (*state).ver.major as (i32) == 4i32
- && ((*state).ver.minor as (i32) < 3i32
- || (*state).ver.minor as (i32) == 3i32 && ((*state).ver.patch as (i32) < 5i32))
- {
- let setting_name = CString::new(sz_setting_roca).unwrap();
- setting_roca = setting_get_bool(setting_name.as_ptr(), true);
- let switch9 = setting_roca.source;
+ return ErrorKind::GenericError;
+ }
- let psz_msg = if switch9 as (i32) == SettingSource::SETTING_SOURCE_USER as (i32) {
- if setting_roca.value {
- sz_roca_allow_user
- } else {
- sz_roca_block_user
- }
- } else if switch9 as (i32) == SettingSource::SETTING_SOURCE_ADMIN as (i32) {
- if setting_roca.value {
- sz_roca_allow_admin
- } else {
- sz_roca_block_admin
- }
- } else {
- sz_roca_default
- };
+ if pin.is_null() || pin_len == 0 || mgm.is_null() {
+ return ErrorKind::GenericError;
+ }
- eprintln!(
- "YubiKey serial number {} is affected by vulnerability CVE-2017-15361 \
- (ROCA) and should be replaced. On-chip key generation {} See \
- YSA-2017-01 \
- for additional information on device replacement and mitigation assistance",
- (*state).serial,
- psz_msg
- );
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
- if !setting_roca.value {
- return ErrorKind::YKPIV_NOT_SUPPORTED;
- }
- }
- }
- if algorithm as (i32) == 0x14i32 || algorithm as (i32) == 0x11i32 {
- if point.is_null() || point_len.is_null() {
- if (*state).verbose != 0 {
- eprintln!("Invalid output parameter for ECC algorithm",);
- }
- return ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- *point = 0i32 as (*mut c_void) as (*mut u8);
- *point_len = 0usize;
- }
- } else if algorithm as (i32) == 0x7i32 || algorithm as (i32) == 0x6i32 {
- if modulus.is_null() || modulus_len.is_null() || exp.is_null() || exp_len.is_null() {
- if (*state).verbose != 0 {
- eprintln!("Invalid output parameter for RSA algorithm",);
- }
- return ErrorKind::YKPIV_GENERIC_ERROR;
- } else {
- *modulus = 0i32 as (*mut c_void) as (*mut u8);
- *modulus_len = 0usize;
- *exp = 0i32 as (*mut c_void) as (*mut u8);
- *exp_len = 0usize;
- }
- } else {
- if (*state).verbose != 0 {
- eprintln!("Invalid algorithm specified");
- }
- return ErrorKind::YKPIV_GENERIC_ERROR;
- }
- (if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- *templ.offset(3isize) = slot;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0xacu8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 3u8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0x80u8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 1u8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = algorithm;
- if in_data[4usize] as (i32) == 0i32 {
- res = ErrorKind::YKPIV_ALGORITHM_ERROR;
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _read_metadata(state, 0x80u8, data.as_mut_ptr(), &mut cb_data);
+
+ if res == ErrorKind::Ok {
+ res = _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x82u8,
+ &mut p_item,
+ &mut cb_item,
+ );
+
+ if res == ErrorKind::Ok {
+ if cb_item != 16usize {
if (*state).verbose != 0 {
- eprintln!("Unexpected algorithm.\n");
- }
- } else {
- if pin_policy as (i32) != 0i32 {
- let _rhs = 3i32;
- let _lhs = &mut in_data[1usize];
- *_lhs = (*_lhs as (i32) + _rhs) as (u8);
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0xaau8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 1u8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = pin_policy;
- }
- if touch_policy as (i32) != 0i32 {
- let _rhs = 3i32;
- let _lhs = &mut in_data[1usize];
- *_lhs = (*_lhs as (i32) + _rhs) as (u8);
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 0xabu8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = 1u8;
- *{
- let _old = in_ptr;
- in_ptr = in_ptr.offset(1isize);
- _old
- } = touch_policy;
- }
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_transfer_data(
- state,
- templ as (*const u8),
- in_data.as_mut_ptr() as (*const u8),
- (in_ptr as (isize)).wrapping_sub(in_data.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize),
- data.as_mut_ptr(),
- &mut recv_len as (*mut usize),
- &mut sw as (*mut i32),
- );
- res
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("Failed to communicate.\n");
- }
- } else if sw != 0x9000i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed to generate new key (");
- }
- if sw == 0x6b00i32 {
- res = ErrorKind::YKPIV_KEY_ERROR;
- if (*state).verbose != 0 {
- eprintln!("incorrect slot)\n");
- }
- } else if sw == 0x6a80i32 {
- res = ErrorKind::YKPIV_ALGORITHM_ERROR;
- if (*state).verbose != 0 {
- if pin_policy as (i32) != 0i32 {
- eprintln!("pin policy not supported?)\n",);
- } else if touch_policy as (i32) != 0i32 {
- eprintln!("touch policy not supported?)\n",);
- } else {
- eprintln!("algorithm not supported?)\n",);
- }
- }
- } else if sw == 0x6982i32 {
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
- if (*state).verbose != 0 {
- eprintln!("not authenticated)");
- }
- } else {
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- if (*state).verbose != 0 {
- eprintln!("error {:x})", sw);
- }
- }
- } else if 0x6i32 == algorithm as (i32) || 0x7i32 == algorithm as (i32) {
- let mut data_ptr: *mut u8 = data.as_mut_ptr().offset(5isize);
- let mut len: usize = 0usize;
- if *data_ptr as (i32) != 0x81i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed to parse public key structure (modulus).");
- }
- res = ErrorKind::YKPIV_PARSE_ERROR;
- } else {
- data_ptr = data_ptr.offset(1isize);
- data_ptr = data_ptr.offset(_ykpiv_get_length(
- data_ptr as (*const u8),
- &mut len as (*mut usize),
- ) as (isize));
- cb_modulus = len;
- if 0i32 as (*mut c_void) as (*mut u8) == {
- ptr_modulus = _ykpiv_alloc(state, cb_modulus) as (*mut u8);
- ptr_modulus
- } {
- if (*state).verbose != 0 {
- eprintln!("Failed to allocate memory for modulus.");
- }
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- memcpy(
- ptr_modulus as (*mut c_void),
- data_ptr as (*const c_void),
- cb_modulus,
- );
- data_ptr = data_ptr.offset(len as (isize));
- if *data_ptr as (i32) != 0x82i32 {
- if (*state).verbose != 0 {
- eprintln!("Failed to parse public key structure (public exponent).");
- }
- res = ErrorKind::YKPIV_PARSE_ERROR;
- } else {
- data_ptr = data_ptr.offset(1isize);
- data_ptr = data_ptr.offset(_ykpiv_get_length(
- data_ptr as (*const u8),
- &mut len as (*mut usize),
- )
- as (isize));
- cb_exp = len;
- if 0i32 as (*mut c_void) as (*mut u8) == {
- ptr_exp = _ykpiv_alloc(state, cb_exp) as (*mut u8);
- ptr_exp
- } {
- if (*state).verbose != 0 {
- eprintln!(
- "Failed to allocate memory for public exponent."
- );
- }
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- memcpy(
- ptr_exp as (*mut c_void),
- data_ptr as (*const c_void),
- cb_exp,
- );
- *modulus = ptr_modulus;
- ptr_modulus = 0i32 as (*mut c_void) as (*mut u8);
- *modulus_len = cb_modulus;
- *exp = ptr_exp;
- ptr_exp = 0i32 as (*mut c_void) as (*mut u8);
- *exp_len = cb_exp;
- }
- }
- }
- }
- } else if 0x11i32 == algorithm as (i32) || 0x14i32 == algorithm as (i32) {
- let mut data_ptr: *mut u8 = data.as_mut_ptr().offset(3isize);
- let mut len: usize;
- if 0x11i32 == algorithm as (i32) {
- len = 65usize;
- } else {
- len = 97usize;
- }
- if *{
- let _old = data_ptr;
- data_ptr = data_ptr.offset(1isize);
- _old
- } as (i32)
- != 0x86i32
- {
- if (*state).verbose != 0 {
- eprintln!("Failed to parse public key structure.\n",);
- }
- res = ErrorKind::YKPIV_PARSE_ERROR;
- } else if *{
- let _old = data_ptr;
- data_ptr = data_ptr.offset(1isize);
- _old
- } as (usize)
- != len
- {
- if (*state).verbose != 0 {
- eprintln!("Unexpected length.\n");
- }
- res = ErrorKind::YKPIV_ALGORITHM_ERROR;
- } else {
- cb_point = len;
- if 0i32 as (*mut c_void) as (*mut u8) == {
- ptr_point = _ykpiv_alloc(state, cb_point) as (*mut u8);
- ptr_point
- } {
- if (*state).verbose != 0 {
- eprintln!("Failed to allocate memory for public point.");
- }
- res = ErrorKind::YKPIV_MEMORY_ERROR;
- } else {
- memcpy(
- ptr_point as (*mut c_void),
- data_ptr as (*const c_void),
- cb_point,
- );
- *point = ptr_point;
- ptr_point = 0i32 as (*mut c_void) as (*mut u8);
- *point_len = cb_point;
- }
- }
- } else {
- if (*state).verbose != 0 {
- eprintln!("Wrong algorithm.");
- }
- res = ErrorKind::YKPIV_ALGORITHM_ERROR;
- }
- }
- }
- if !ptr_modulus.is_null() {
- _ykpiv_free(state, modulus as (*mut c_void));
- }
- if !ptr_exp.is_null() {
- _ykpiv_free(state, ptr_exp as (*mut c_void));
- }
- if !ptr_point.is_null() {
- _ykpiv_free(state, ptr_exp as (*mut c_void));
- }
- _ykpiv_end_transaction(state);
- res
- })
- }
-}
-
-#[derive(Clone, Copy)]
-#[repr(i32)]
-#[allow(non_camel_case_types)]
-pub enum Enum10 {
- YKPIV_CONFIG_MGM_MANUAL = 0i32,
- YKPIV_CONFIG_MGM_DERIVED = 1i32,
- YKPIV_CONFIG_MGM_PROTECTED = 2i32,
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct _ykpiv_config {
- pub protected_data_available: u8,
- pub puk_blocked: u8,
- pub puk_noblock_on_upgrade: u8,
- pub pin_last_changed: u32,
- pub mgm_type: Enum10,
-}
-
-impl Clone for _ykpiv_config {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-pub fn ykpiv_util_get_config(
- mut state: *mut ykpiv_state,
- mut config: *mut _ykpiv_config,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut data = [0u8; 3072];
- let mut cb_data: usize = mem::size_of::<[u8; 3072]>();
- let mut p_item: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_item: usize = 0usize;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if 0i32 as (*mut c_void) as (*mut _ykpiv_config) == config {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- (*config).protected_data_available = 0u8;
- (*config).puk_blocked = 0u8;
- (*config).puk_noblock_on_upgrade = 0u8;
- (*config).pin_last_changed = 0u32;
- (*config).mgm_type = Enum10::YKPIV_CONFIG_MGM_MANUAL;
- (if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if ErrorKind::YKPIV_OK as (i32)
- == _read_metadata(
- state,
- 0x80u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- ) as (i32)
- {
- if ErrorKind::YKPIV_OK as (i32)
- == _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x81u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- ) as (i32)
- {
- if *p_item as (i32) & 0x1i32 != 0 {
- (*config).puk_blocked = 1u8;
- }
- if *p_item as (i32) & 0x2i32 != 0 {
- (*config).mgm_type = Enum10::YKPIV_CONFIG_MGM_PROTECTED;
- }
- }
- if ErrorKind::YKPIV_OK as (i32)
- == _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x82u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- ) as (i32)
- {
- if (*config).mgm_type as (i32) != Enum10::YKPIV_CONFIG_MGM_MANUAL as (i32) {
- if (*state).verbose != 0 {
- eprintln!("conflicting types of mgm key administration configured");
- }
- } else {
- (*config).mgm_type = Enum10::YKPIV_CONFIG_MGM_DERIVED;
- }
- }
- if ErrorKind::YKPIV_OK as (i32)
- == _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x83u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- ) as (i32)
- {
- if 4usize != cb_item {
- if (*state).verbose != 0 {
- eprintln!("pin timestamp in admin metadata is an invalid size");
- }
- } else {
- memcpy(
- &mut (*config).pin_last_changed as (*mut u32) as (*mut c_void),
- p_item as (*const c_void),
- cb_item,
- );
- }
- }
- }
- cb_data = mem::size_of::<[u8; 3072]>();
- if ErrorKind::YKPIV_OK as (i32)
- == _read_metadata(
- state,
- 0x88u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- ) as (i32)
- {
- (*config).protected_data_available = 1u8;
- if ErrorKind::YKPIV_OK as (i32)
- == _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x81u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- ) as (i32)
- {
- if *p_item as (i32) & 0x1i32 != 0 {
- (*config).puk_noblock_on_upgrade = 1u8;
- }
- }
- if ErrorKind::YKPIV_OK as (i32)
- == _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x89u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- ) as (i32)
- {
- if (*config).mgm_type as (i32)
- != Enum10::YKPIV_CONFIG_MGM_PROTECTED as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "conflicting types of mgm key administration configured - protected mgm exists"
- );
- }
- }
- (*config).mgm_type = Enum10::YKPIV_CONFIG_MGM_PROTECTED;
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
- })
- }
-}
-
-pub fn ykpiv_util_set_pin_last_changed(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut ykrc: ErrorKind = ErrorKind::YKPIV_OK;
- let mut data = [0u8; 3072];
- let mut cb_data: usize = mem::size_of::<[u8; 3072]>();
- let mut tnow: time_t = 0;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _read_metadata(
- state,
- 0x80u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- );
- ykrc
- } as (i32)
- {
- cb_data = 0usize;
- }
- tnow = time(0 as *mut time_t);
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _set_metadata_item(
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- 3063usize,
- 0x83u8,
- mem::transmute(&mut tnow),
- 4usize,
- );
- res
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("could not set pin timestamp, err = {}\n", res as (i32),);
- }
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _write_metadata(state, 0x80u8, data.as_mut_ptr(), cb_data);
- res
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("could not write admin data, err = {}", res as (i32),);
- }
- }
- }
- _ykpiv_end_transaction(state);
- res
- }
-}
-
-#[derive(Copy)]
-#[repr(C)]
-pub struct _ykpiv_mgm {
- pub data: [u8; 24],
-}
-
-impl Clone for _ykpiv_mgm {
- fn clone(&self) -> Self {
- *self
- }
-}
-
-#[derive(Clone, Copy)]
-#[repr(i32)]
-pub enum Enum11 {
- PKCS5_OK = 0i32,
- PKCS5_GENERAL_ERROR = -1i32,
-}
-
-pub fn ykpiv_util_get_derived_mgm(
- mut state: *mut ykpiv_state,
- mut pin: *const u8,
- pin_len: usize,
- mut mgm: *mut _ykpiv_mgm,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut p5rc: Enum11 = Enum11::PKCS5_OK;
- let mut data = [0u8; 3072];
- let mut cb_data: usize = mem::size_of::<[u8; 3072]>();
- let mut p_item: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_item: usize = 0usize;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if 0i32 as (*mut c_void) as (*const u8) == pin
- || 0usize == pin_len
- || 0i32 as (*mut c_void) as (*mut _ykpiv_mgm) == mgm
- {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if ErrorKind::YKPIV_OK as (i32) == {
- res = _read_metadata(
- state,
- 0x80u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- );
- res
- } as (i32)
- {
- if ErrorKind::YKPIV_OK as (i32) == {
- res = _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x82u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- );
- res
- } as (i32)
- {
- if cb_item != 16usize {
- if (*state).verbose != 0 {
- eprintln!(
- "derived mgm salt exists, but is incorrect size = {}",
- cb_item,
- );
- }
- res = ErrorKind::YKPIV_GENERIC_ERROR;
- } else if Enum11::PKCS5_OK as (i32) != {
- p5rc = pkcs5_pbkdf2_sha1(
- pin,
- pin_len,
- p_item as (*const u8),
+ eprintln!(
+ "derived mgm salt exists, but is incorrect size = {}",
cb_item,
- 10000usize,
- (*mgm).data.as_mut_ptr() as (*const u8),
- mem::size_of::<[u8; 24]>(),
);
- p5rc
- } as (i32)
- {
+ }
+ res = ErrorKind::GenericError;
+ } else {
+ let p5rc = pkcs5_pbkdf2_sha1(
+ pin,
+ pin_len,
+ p_item,
+ cb_item,
+ 10000,
+ (*mgm).0.as_mut_ptr(),
+ (*mgm).0.len(),
+ );
+
+ if p5rc != Pkcs5ErrorKind::Ok {
if (*state).verbose != 0 {
- eprintln!("pbkdf2 failure, err = {}", p5rc as (i32));
+ eprintln!("pbkdf2 failure, err = {:?}", p5rc);
}
- res = ErrorKind::YKPIV_GENERIC_ERROR;
+
+ res = ErrorKind::GenericError;
}
}
}
}
- _ykpiv_end_transaction(state);
- res
}
+
+ _ykpiv_end_transaction(state);
+ res
}
-pub fn ykpiv_util_get_protected_mgm(
- mut state: *mut ykpiv_state,
- mut mgm: *mut _ykpiv_mgm,
-) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut data = [0u8; 3072];
- let mut cb_data: usize = mem::size_of::<[u8; 3072]>();
- let mut p_item: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_item: usize = 0usize;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if 0i32 as (*mut c_void) as (*mut _ykpiv_mgm) == mgm {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- ErrorKind::YKPIV_PCSC_ERROR
- } else {
- if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _read_metadata(
- state,
- 0x88u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- );
- res
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("could not read protected data, err = {}", res as (i32),);
- }
- } else if ErrorKind::YKPIV_OK as (i32) != {
- res = _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x89u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- );
- res
- } as (i32)
- {
+/// Get protected management key (MGM)
+pub unsafe fn ykpiv_util_get_protected_mgm(state: *mut YubiKey, mgm: *mut YkPivMgm) -> ErrorKind {
+ let mut data = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_data: usize = data.len();
+ let mut p_item: *mut u8 = ptr::null_mut();
+ let mut cb_item: usize = 0;
+ let mut res = ErrorKind::Ok;
+
+ if state.is_null() || mgm.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _read_metadata(state, 0x88u8, data.as_mut_ptr(), &mut cb_data);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!("could not read protected data, err = {:?}", res);
+ }
+ } else {
+ res = _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x89u8,
+ &mut p_item,
+ &mut cb_item,
+ );
+
+ if res != ErrorKind::Ok {
if (*state).verbose != 0 {
eprintln!(
"could not read protected mgm from metadata, err = {}",
res as (i32),
);
}
- } else if cb_item != mem::size_of::<[u8; 24]>() {
+ } else if cb_item != (*mgm).0.len() {
if (*state).verbose != 0 {
eprintln!(
"protected data contains mgm, but is the wrong size = {}",
cb_item,
);
}
- res = ErrorKind::YKPIV_AUTHENTICATION_ERROR;
+ res = ErrorKind::AuthenticationError;
} else {
memcpy(
- (*mgm).data.as_mut_ptr() as (*mut c_void),
+ (*mgm).0.as_mut_ptr() as (*mut c_void),
p_item as (*const c_void),
cb_item,
);
}
}
- memset_s(
- data.as_mut_ptr() as (*mut c_void),
- mem::size_of::<[u8; 3072]>(),
- 0i32,
- mem::size_of::<[u8; 3072]>(),
- );
- _ykpiv_end_transaction(state);
- res
}
+
+ data.zeroize();
+ _ykpiv_end_transaction(state);
+ res
}
-pub fn ykpiv_util_set_protected_mgm(
- mut state: *mut ykpiv_state,
- mut mgm: *mut _ykpiv_mgm,
-) -> ErrorKind {
+/// Set protected management key (MGM)
+#[allow(clippy::cognitive_complexity)]
+pub unsafe fn ykpiv_util_set_protected_mgm(state: *mut YubiKey, mgm: *mut YkPivMgm) -> ErrorKind {
let mut _currentBlock;
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut ykrc: ErrorKind = ErrorKind::YKPIV_OK;
- let mut prngrc: Enum7 = Enum7::PRNG_OK;
- let mut fGenerate: bool = false;
- let mut mgm_key: [u8; 24];
- let mut i: usize = 0usize;
- let mut data = [0u8; 3072];
- let mut cb_data: usize = mem::size_of::<[u8; 3072]>();
- let mut p_item: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_item: usize = 0usize;
- let mut flags_1: u8 = 0u8;
- if 0i32 as (*mut c_void) as (*mut ykpiv_state) == state {
- ErrorKind::YKPIV_GENERIC_ERROR
+ let mut res: ErrorKind = ErrorKind::Ok;
+ let mut ykrc: ErrorKind = ErrorKind::Ok;
+ let mut prngrc: PRngErrorKind = PRngErrorKind::Ok;
+ let mut f_generate: bool;
+ let mut mgm_key = [0u8; 24];
+ let mut i: usize;
+ let mut data = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut cb_data = data.len();
+ let mut p_item: *mut u8 = ptr::null_mut();
+ let mut cb_item: usize = 0;
+ let mut flags_1: u8 = 0;
+
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if mgm.is_null() {
+ f_generate = true;
} else {
- if mgm.is_null() {
- fGenerate = true;
- } else {
- fGenerate = true;
- memcpy(
- mgm_key.as_mut_ptr() as (*mut c_void),
- (*mgm).data.as_mut_ptr() as (*const c_void),
- mem::size_of::<[u8; 24]>(),
- );
- i = 0usize;
- 'loop3: loop {
- if !(i < mem::size_of::<[u8; 24]>()) {
- _currentBlock = 8;
- break;
- }
- if mgm_key[i] as (i32) != 0i32 {
- _currentBlock = 6;
- break;
- }
- i = i.wrapping_add(1usize);
+ f_generate = true;
+ memcpy(
+ mgm_key.as_mut_ptr() as (*mut c_void),
+ (*mgm).0.as_mut_ptr() as (*const c_void),
+ (*mgm).0.len(),
+ );
+ i = 0;
+ loop {
+ if i >= 24 {
+ _currentBlock = 8;
+ break;
}
- if _currentBlock == 8 {
+ if mgm_key[i] as (i32) != 0i32 {
+ _currentBlock = 6;
+ break;
+ }
+ i = i.wrapping_add(1);
+ }
+ if _currentBlock == 8 {
+ } else {
+ f_generate = false;
+ }
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ loop {
+ if f_generate {
+ prngrc = _ykpiv_prng_generate(mgm_key.as_mut_ptr(), mem::size_of::<[u8; 24]>());
+ if prngrc != PRngErrorKind::Ok {
+ _currentBlock = 47;
+ break;
+ }
+ }
+
+ ykrc = ykpiv_set_mgmkey(state, mgm_key.as_mut_ptr());
+ if ykrc != ErrorKind::Ok {
+ if ErrorKind::KeyError as (i32) != ykrc as (i32) {
+ _currentBlock = 44;
+ break;
+ }
} else {
- fGenerate = false;
+ f_generate = false;
+ }
+ if !f_generate {
+ _currentBlock = 16;
+ break;
}
}
- if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_begin_transaction(state);
- res
- } as (i32)
- {
- res = ErrorKind::YKPIV_PCSC_ERROR;
- } else if !(ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_ensure_application_selected(state);
- res
- } as (i32))
- {
- 'loop10: loop {
- if fGenerate {
- if Enum7::PRNG_OK as (i32) != {
- prngrc =
- _ykpiv_prng_generate(mgm_key.as_mut_ptr(), mem::size_of::<[u8; 24]>());
- prngrc
- } as (i32)
- {
- _currentBlock = 47;
- break;
- }
- }
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = ykpiv_set_mgmkey(state, mgm_key.as_mut_ptr() as (*const u8));
- ykrc
- } as (i32)
- {
- if ErrorKind::YKPIV_KEY_ERROR as (i32) != ykrc as (i32) {
- _currentBlock = 44;
- break;
- }
- } else {
- fGenerate = false;
- }
- if !fGenerate {
- _currentBlock = 16;
- break;
- }
+
+ if _currentBlock == 16 {
+ if !mgm.is_null() {
+ memcpy(
+ (*mgm).0.as_mut_ptr() as (*mut c_void),
+ mgm_key.as_mut_ptr() as (*const c_void),
+ (*mgm).0.len(),
+ );
}
- if _currentBlock == 16 {
- if !mgm.is_null() {
- memcpy(
- (*mgm).data.as_mut_ptr() as (*mut c_void),
- mgm_key.as_mut_ptr() as (*const c_void),
- mem::size_of::<[u8; 24]>(),
- );
+
+ ykrc = _read_metadata(state, 0x88u8, data.as_mut_ptr(), &mut cb_data);
+
+ if ykrc != ErrorKind::Ok {
+ cb_data = 0;
+ }
+
+ ykrc = _set_metadata_item(
+ data.as_mut_ptr(),
+ &mut cb_data,
+ CB_OBJ_MAX,
+ 0x89,
+ mgm_key.as_mut_ptr(),
+ mgm_key.len(),
+ );
+
+ if ykrc != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!("could not set protected mgm item, err = {:?}", ykrc);
+ _currentBlock = 26;
+ } else {
+ _currentBlock = 26;
}
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _read_metadata(
- state,
- 0x88u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- );
- ykrc
- } as (i32)
- {
- cb_data = 0usize;
- }
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _set_metadata_item(
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- 3063usize,
- 0x89u8,
- mgm_key.as_mut_ptr(),
- mem::size_of::<[u8; 24]>(),
- );
- ykrc
- } as (i32)
- {
+ } else {
+ ykrc = _write_metadata(state, 0x88u8, data.as_mut_ptr(), cb_data);
+ if ykrc != ErrorKind::Ok {
if (*state).verbose != 0 {
- eprintln!("could not set protected mgm item, err = {}", ykrc as (i32),);
- _currentBlock = 26;
- } else {
- _currentBlock = 26;
- }
- } else if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _write_metadata(state, 0x88u8, data.as_mut_ptr(), cb_data);
- ykrc
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("could not write protected data, err = {}", ykrc as (i32),);
+ eprintln!("could not write protected data, err = {:?}", ykrc);
_currentBlock = 51;
} else {
_currentBlock = 51;
@@ -2319,549 +1866,489 @@ pub fn ykpiv_util_set_protected_mgm(
} else {
_currentBlock = 26;
}
- if _currentBlock == 51 {
- } else {
- cb_data = mem::size_of::<[u8; 3072]>();
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _read_metadata(
- state,
- 0x80u8,
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- );
- ykrc
- } as (i32)
- {
- cb_data = 0usize;
- } else {
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _get_metadata_item(
- data.as_mut_ptr(),
- cb_data,
- 0x81u8,
- &mut p_item as (*mut *mut u8),
- &mut cb_item as (*mut usize),
- );
- ykrc
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("admin data exists, but flags are not present",);
- }
- }
- if cb_item == mem::size_of::() {
- memcpy(
- &mut flags_1 as (*mut u8) as (*mut c_void),
- p_item as (*const c_void),
- cb_item,
- );
- } else if (*state).verbose != 0 {
- eprintln!("admin data flags are an incorrect size = {}", cb_item,);
- }
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _set_metadata_item(
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- 3063usize,
- 0x82u8,
- 0i32 as (*mut c_void) as (*mut u8),
- 0usize,
- );
- ykrc
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!(
- "could not unset derived mgm salt, err = {}",
- ykrc as (i32),
- );
- }
- }
- }
- flags_1 = (flags_1 as (i32) | 0x2i32) as (u8);
- if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _set_metadata_item(
- data.as_mut_ptr(),
- &mut cb_data as (*mut usize),
- 3063usize,
- 0x81u8,
- &mut flags_1 as (*mut u8),
- mem::size_of::(),
- );
- ykrc
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("could not set admin flags item, err = {}", ykrc as (i32),);
- }
- } else if ErrorKind::YKPIV_OK as (i32) != {
- ykrc = _write_metadata(state, 0x80u8, data.as_mut_ptr(), cb_data);
- ykrc
- } as (i32)
- {
- if (*state).verbose != 0 {
- eprintln!("could not write admin data, err = {}", ykrc as (i32),);
- }
- }
- }
- } else if _currentBlock == 44 {
- if (*state).verbose != 0 {
- eprintln!("could not set new derived mgm key, err = {}", ykrc as (i32),);
- }
- res = ykrc;
- } else {
- if (*state).verbose != 0 {
- eprintln!("could not generate new mgm, err = {}", prngrc as (i32),);
- }
- res = ErrorKind::YKPIV_RANDOMNESS_ERROR;
}
+
+ if _currentBlock != 51 {
+ cb_data = YKPIV_OBJ_MAX_SIZE;
+ ykrc = _read_metadata(state, 0x80u8, data.as_mut_ptr(), &mut cb_data);
+
+ if ykrc != ErrorKind::Ok {
+ cb_data = 0;
+ } else {
+ ykrc = _get_metadata_item(
+ data.as_mut_ptr(),
+ cb_data,
+ 0x81u8,
+ &mut p_item,
+ &mut cb_item,
+ );
+
+ if ykrc != ErrorKind::Ok && (*state).verbose != 0 {
+ eprintln!("admin data exists, but flags are not present",);
+ }
+
+ if cb_item == 1 {
+ // TODO(tarcieri): get rid of memcpy and pointers, replace with slices!
+ #[allow(trivial_casts)]
+ memcpy(
+ &mut flags_1 as (*mut u8) as (*mut c_void),
+ p_item as (*const c_void),
+ cb_item,
+ );
+ } else if (*state).verbose != 0 {
+ eprintln!("admin data flags are an incorrect size = {}", cb_item,);
+ }
+
+ ykrc = _set_metadata_item(
+ data.as_mut_ptr(),
+ &mut cb_data,
+ CB_OBJ_MAX,
+ 0x82,
+ ptr::null_mut(),
+ 0,
+ );
+
+ if ykrc != ErrorKind::Ok && (*state).verbose != 0 {
+ eprintln!("could not unset derived mgm salt, err = {}", ykrc);
+ }
+ }
+ flags_1 |= 0x2;
+
+ ykrc = _set_metadata_item(
+ data.as_mut_ptr(),
+ &mut cb_data,
+ CB_OBJ_MAX,
+ 0x81,
+ &mut flags_1,
+ 1,
+ );
+
+ if ykrc != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!("could not set admin flags item, err = {}", ykrc);
+ }
+ } else {
+ ykrc = _write_metadata(state, 0x80u8, data.as_mut_ptr(), cb_data);
+ if ykrc != ErrorKind::Ok && (*state).verbose != 0 {
+ eprintln!("could not write admin data, err = {}", ykrc);
+ }
+ }
+ }
+ } else if _currentBlock == 44 {
+ if (*state).verbose != 0 {
+ eprintln!("could not set new derived mgm key, err = {}", ykrc);
+ }
+
+ res = ykrc;
+ } else {
+ if (*state).verbose != 0 {
+ eprintln!("could not generate new mgm, err = {:?}", prngrc);
+ }
+
+ res = ErrorKind::RandomnessError;
}
- memset_s(
- data.as_mut_ptr() as (*mut c_void),
- mem::size_of::<[u8; 3072]>(),
- 0i32,
- mem::size_of::<[u8; 3072]>(),
- );
- memset_s(
- mgm_key.as_mut_ptr() as (*mut c_void),
- mem::size_of::<[u8; 24]>(),
- 0i32,
- mem::size_of::<[u8; 24]>(),
- );
- _ykpiv_end_transaction(state);
- res
}
+
+ data.zeroize();
+ mgm_key.zeroize();
+ _ykpiv_end_transaction(state);
+
+ res
}
-pub fn ykpiv_util_reset(mut state: *mut ykpiv_state) -> ErrorKind {
- let mut templ: *mut u8 = 0i32 as (*mut u8);
- let mut data: [u8; 255];
- let mut recv_len: usize = mem::size_of::<[u8; 255]>();
- let mut res: ErrorKind;
- let mut sw: i32;
- res = ykpiv_transfer_data(
+/// Reset
+pub unsafe fn ykpiv_util_reset(state: *mut YubiKey) -> ErrorKind {
+ let templ = [0, YKPIV_INS_RESET, 0, 0];
+ let mut data = [0u8; 255];
+ let mut recv_len = data.len();
+ let mut sw: i32 = 0;
+
+ let res = ykpiv_transfer_data(
state,
- templ as (*const u8),
- 0i32 as (*mut c_void) as (*const u8),
- 0isize,
+ templ.as_ptr(),
+ ptr::null(),
+ 0,
data.as_mut_ptr(),
- &mut recv_len as (*mut usize),
- &mut sw as (*mut i32),
+ &mut recv_len,
+ &mut sw,
);
- if ErrorKind::YKPIV_OK as (i32) == res as (i32) && (0x9000i32 == sw) {
- ErrorKind::YKPIV_OK
+
+ if res == ErrorKind::Ok && sw == SW_SUCCESS {
+ ErrorKind::Ok
} else {
- ErrorKind::YKPIV_GENERIC_ERROR
+ ErrorKind::GenericError
}
}
-pub fn ykpiv_util_slot_object(mut slot: u8) -> u32 {
- let mut object_id: i32 = -1i32;
- if slot as (i32) == 0xf9i32 {
- object_id = 0x5fff01i32;
- } else if slot as (i32) == 0x9ei32 {
- object_id = 0x5fc101i32;
- } else if slot as (i32) == 0x9di32 {
- object_id = 0x5fc10bi32;
- } else if slot as (i32) == 0x9ci32 {
- object_id = 0x5fc10ai32;
- } else if slot as (i32) == 0x9ai32 {
- object_id = 0x5fc105i32;
- } else if slot as (i32) >= 0x82i32 && (slot as (i32) <= 0x95i32) {
- object_id = 0x5fc10di32 + (slot as (i32) - 0x82i32);
+/// Get object for slot
+pub fn ykpiv_util_slot_object(slot: u8) -> u32 {
+ match slot {
+ YKPIV_KEY_AUTHENTICATION => YKPIV_OBJ_AUTHENTICATION,
+ YKPIV_KEY_SIGNATURE => YKPIV_OBJ_SIGNATURE,
+ YKPIV_KEY_KEYMGM => YKPIV_OBJ_KEY_MANAGEMENT,
+ YKPIV_KEY_CARDAUTH => YKPIV_OBJ_CARD_AUTH,
+ YKPIV_KEY_ATTESTATION => YKPIV_OBJ_ATTESTATION,
+ _ => {
+ if slot >= YKPIV_KEY_RETIRED1 && (slot <= YKPIV_KEY_RETIRED20) {
+ YKPIV_OBJ_RETIRED1 + (slot - YKPIV_KEY_RETIRED1) as u32
+ } else {
+ 0
+ }
+ }
}
- object_id as (u32)
}
+/// Read certificate
unsafe fn _read_certificate(
- mut state: *mut ykpiv_state,
- mut slot: u8,
- mut buf: *mut u8,
- mut buf_len: *mut usize,
+ state: *mut YubiKey,
+ slot: u8,
+ buf: *mut u8,
+ buf_len: *mut usize,
) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut ptr: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut object_id: i32 = ykpiv_util_slot_object(slot) as (i32);
- let mut len: usize = 0usize;
- if -1i32 == object_id {
- ErrorKind::YKPIV_INVALID_OBJECT
- } else {
- if ErrorKind::YKPIV_OK as (i32) == {
- res = _ykpiv_fetch_object(state, object_id, buf, buf_len);
- res
- } as (i32)
- {
- ptr = buf;
- if *buf_len < 2usize {
- *buf_len = 0usize;
- return ErrorKind::YKPIV_OK;
- } else if *{
- let _old = ptr;
- ptr = ptr.offset(1isize);
- _old
- } as (i32)
- == 0x70i32
- {
- ptr = ptr.offset(
- _ykpiv_get_length(ptr as (*const u8), &mut len as (*mut usize)) as (isize),
- );
- if len
- > (*buf_len).wrapping_sub(
- ((ptr as (isize)).wrapping_sub(buf as (isize))
- / mem::size_of::() as (isize)) as (usize),
- )
- {
- *buf_len = 0usize;
- return ErrorKind::YKPIV_OK;
- } else {
- memmove(buf as (*mut c_void), ptr as (*const c_void), len);
- *buf_len = len;
- }
- }
- } else {
- *buf_len = 0usize;
- }
- res
+ let mut ptr: *mut u8;
+ let object_id = ykpiv_util_slot_object(slot) as i32;
+ let mut len: usize = 0;
+
+ if object_id == -1 {
+ return ErrorKind::InvalidObject;
}
+
+ if _ykpiv_fetch_object(state, object_id, buf, buf_len) == ErrorKind::Ok {
+ ptr = buf;
+
+ if *buf_len < CB_OBJ_TAG_MIN {
+ *buf_len = 0;
+ return ErrorKind::Ok;
+ } else if *{
+ let _old = ptr;
+ ptr = ptr.offset(1);
+ _old
+ } == TAG_CERT
+ {
+ ptr = ptr.add(_ykpiv_get_length(ptr, &mut len));
+
+ if len > *buf_len - (ptr as isize - buf as isize) as usize {
+ *buf_len = 0;
+ return ErrorKind::Ok;
+ } else {
+ memmove(buf as (*mut c_void), ptr as (*const c_void), len);
+ *buf_len = len;
+ }
+ }
+ } else {
+ *buf_len = 0;
+ }
+
+ ErrorKind::Ok
}
+/// Write certificate
unsafe fn _write_certificate(
- mut state: *mut ykpiv_state,
- mut slot: u8,
- mut data: *mut u8,
- mut data_len: usize,
- mut certinfo: u8,
+ state: *mut YubiKey,
+ slot: u8,
+ data: *mut u8,
+ data_len: usize,
+ certinfo: u8,
) -> ErrorKind {
- let mut buf: [u8; 3063];
- let mut object_id: i32 = ykpiv_util_slot_object(slot) as (i32);
- let mut offset: usize = 0usize;
- let mut req_len: usize = 0usize;
- if -1i32 == object_id {
- ErrorKind::YKPIV_INVALID_OBJECT
- } else if 0i32 as (*mut c_void) as (*mut u8) == data || 0usize == data_len {
- (if 0i32 as (*mut c_void) as (*mut u8) != data || 0usize != data_len {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- _ykpiv_save_object(state, object_id, 0i32 as (*mut c_void) as (*mut u8), 0usize)
- })
- } else {
- req_len = (1i32 + 3i32 + 2i32) as (usize);
- req_len = req_len.wrapping_add(_ykpiv_set_length(buf.as_mut_ptr(), data_len) as (usize));
- req_len = req_len.wrapping_add(data_len);
- (if req_len < data_len {
- ErrorKind::YKPIV_SIZE_ERROR
- } else if req_len > _obj_size_max(state) {
- ErrorKind::YKPIV_SIZE_ERROR
- } else {
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = 0x70u8;
- offset = offset.wrapping_add(_ykpiv_set_length(
- buf.as_mut_ptr().offset(offset as (isize)),
- data_len,
- ) as (usize));
- memcpy(
- buf.as_mut_ptr().offset(offset as (isize)) as (*mut c_void),
- data as (*const c_void),
- data_len,
- );
- offset = offset.wrapping_add(data_len);
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = 0x71u8;
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = 0x1u8;
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = if certinfo as (i32) == 1i32 {
- 0x1i32
- } else {
- 0x0i32
- } as (u8);
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = 0xfeu8;
- buf[{
- let _old = offset;
- offset = offset.wrapping_add(1usize);
- _old
- }] = 0o0u8;
- _ykpiv_save_object(state, object_id, buf.as_mut_ptr(), offset)
- })
+ let mut buf = [0u8; CB_OBJ_MAX];
+ let object_id = ykpiv_util_slot_object(slot) as i32;
+ let mut offset: usize = 0;
+ let mut req_len: usize;
+
+ if object_id == -1 {
+ return ErrorKind::InvalidObject;
}
+
+ if data.is_null() || data_len == 0 {
+ if !data.is_null() || data_len != 0 {
+ return ErrorKind::GenericError;
+ }
+
+ return _ykpiv_save_object(state, object_id, ptr::null_mut(), 0);
+ }
+
+ req_len = 1 /* cert tag */ + 3 /* compression tag + data*/ + 2 /* lrc */;
+ req_len += _ykpiv_set_length(buf.as_mut_ptr(), data_len);
+ req_len += data_len;
+
+ if req_len < data_len || req_len > _obj_size_max(state) {
+ return ErrorKind::SizeError;
+ }
+
+ buf[offset] = TAG_CERT;
+ offset += 1;
+ offset += _ykpiv_set_length(buf.as_mut_ptr().add(offset), data_len);
+
+ memcpy(
+ buf.as_mut_ptr().add(offset) as (*mut c_void),
+ data as (*const c_void),
+ data_len,
+ );
+
+ offset += data_len;
+
+ // write compression info and LRC trailer
+ buf[offset] = TAG_CERT_COMPRESS;
+ buf[offset + 1] = 0x01;
+ buf[offset + 2] = if certinfo == YKPIV_CERTINFO_GZIP {
+ 0x01
+ } else {
+ 0x00
+ };
+ buf[offset + 3] = TAG_CERT_LRC;
+ buf[offset + 4] = 00;
+
+ offset += 5;
+
+ _ykpiv_save_object(state, object_id, buf.as_mut_ptr(), offset)
}
+/// Get metadata item
unsafe fn _get_metadata_item(
- mut data: *mut u8,
- mut cb_data: usize,
- mut tag: u8,
- mut pp_item: *mut *mut u8,
- mut pcb_item: *mut usize,
+ data: *mut u8,
+ cb_data: usize,
+ tag: u8,
+ pp_item: *mut *mut u8,
+ pcb_item: *mut usize,
) -> ErrorKind {
- let mut _currentBlock;
let mut p_temp: *mut u8 = data;
- let mut cb_temp: usize = 0usize;
- let mut tag_temp: u8 = 0u8;
+ let mut cb_temp: usize = 0;
+ let mut tag_temp: u8;
+
if data.is_null() || pp_item.is_null() || pcb_item.is_null() {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- *pp_item = 0i32 as (*mut c_void) as (*mut u8);
- *pcb_item = 0usize;
- 'loop2: loop {
- if !(p_temp < data.offset(cb_data as (isize))) {
- _currentBlock = 6;
- break;
- }
- tag_temp = *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- };
- if !_ykpiv_has_valid_length(
- p_temp as (*const u8),
- ((data.offset(cb_data as (isize)) as (isize)).wrapping_sub(p_temp as (isize))
- / mem::size_of::() as (isize)) as (usize),
- ) {
- _currentBlock = 9;
- break;
- }
- p_temp = p_temp.offset(_ykpiv_get_length(
- p_temp as (*const u8),
- &mut cb_temp as (*mut usize),
- ) as (isize));
- if tag_temp as (i32) == tag as (i32) {
- _currentBlock = 6;
- break;
- }
- p_temp = p_temp.offset(cb_temp as (isize));
+ return ErrorKind::GenericError;
+ }
+
+ *pp_item = ptr::null_mut();
+ *pcb_item = 0;
+
+ while p_temp < data.add(cb_data) {
+ tag_temp = *p_temp;
+ p_temp = p_temp.add(1);
+
+ if !_ykpiv_has_valid_length(p_temp, data.add(cb_data) as usize - p_temp as usize) {
+ return ErrorKind::SizeError;
}
- (if _currentBlock == 6 {
- (if p_temp < data.offset(cb_data as (isize)) {
- *pp_item = p_temp;
- *pcb_item = cb_temp;
- ErrorKind::YKPIV_OK
- } else {
- ErrorKind::YKPIV_GENERIC_ERROR
- })
- } else {
- ErrorKind::YKPIV_SIZE_ERROR
- })
- }
-}
-unsafe fn _get_length_size(mut length: usize) -> i32 {
- if length < 0x80usize {
- 1i32
- } else if length < 0xffusize {
- 2i32
+ p_temp = p_temp.add(_ykpiv_get_length(p_temp, &mut cb_temp));
+
+ if tag_temp == tag {
+ break;
+ }
+
+ p_temp = p_temp.add(cb_temp);
+ }
+
+ if p_temp < data.add(cb_data) {
+ *pp_item = p_temp;
+ *pcb_item = cb_temp;
+
+ ErrorKind::Ok
} else {
- 3i32
+ ErrorKind::GenericError
}
}
+/// Get length size
+fn _get_length_size(length: usize) -> i32 {
+ if length < 0x80 {
+ 1
+ } else if length < 0xff {
+ 2
+ } else {
+ 3
+ }
+}
+
+/// Set metadata item
unsafe fn _set_metadata_item(
- mut data: *mut u8,
- mut pcb_data: *mut usize,
- mut cb_data_max: usize,
- mut tag: u8,
- mut p_item: *mut u8,
- mut cb_item: usize,
+ data: *mut u8,
+ pcb_data: *mut usize,
+ cb_data_max: usize,
+ tag: u8,
+ p_item: *mut u8,
+ cb_item: usize,
) -> ErrorKind {
- let mut _currentBlock;
let mut p_temp: *mut u8 = data;
- let mut cb_temp: usize = 0usize;
- let mut tag_temp: u8 = 0u8;
- let mut cb_len: usize = 0usize;
- let mut p_next: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_moved: isize = 0isize;
+ let mut cb_temp: usize = 0;
+ let mut tag_temp: u8 = 0;
+ let mut cb_len: usize = 0;
+ let p_next: *mut u8;
+ let cb_moved: isize;
+
if data.is_null() || pcb_data.is_null() {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- 'loop1: loop {
- if !(p_temp < data.offset(*pcb_data as (isize))) {
- _currentBlock = 2;
- break;
- }
- tag_temp = *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- };
- cb_len =
- _ykpiv_get_length(p_temp as (*const u8), &mut cb_temp as (*mut usize)) as (usize);
- p_temp = p_temp.offset(cb_len as (isize));
- if tag_temp as (i32) == tag as (i32) {
- _currentBlock = 9;
- break;
- }
- p_temp = p_temp.offset(cb_temp as (isize));
- }
- (if _currentBlock == 2 {
- (if cb_item == 0usize {
- ErrorKind::YKPIV_OK
- } else {
- p_temp = data.offset(*pcb_data as (isize));
- cb_len = _get_length_size(cb_item) as (usize);
- (if (*pcb_data).wrapping_add(cb_len).wrapping_add(cb_item) > cb_data_max {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- } = tag;
- p_temp = p_temp.offset(_ykpiv_set_length(p_temp, cb_item) as (isize));
- memcpy(p_temp as (*mut c_void), p_item as (*const c_void), cb_item);
- *pcb_data =
- (*pcb_data).wrapping_add(1usize.wrapping_add(cb_len).wrapping_add(cb_item));
- ErrorKind::YKPIV_OK
- })
- })
- } else if cb_temp == cb_item {
- memcpy(p_temp as (*mut c_void), p_item as (*const c_void), cb_item);
- ErrorKind::YKPIV_OK
- } else {
- p_next = p_temp.offset(cb_temp as (isize));
- cb_moved = cb_item as (isize) - cb_temp as (isize)
- + (if cb_item != 0usize {
- _get_length_size(cb_item)
- } else {
- -1i32
- } as (isize)
- - cb_len as (isize));
- (if (*pcb_data).wrapping_add(cb_moved as (usize)) > cb_data_max {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- memmove(
- p_next.offset(cb_moved) as (*mut c_void),
- p_next as (*const c_void),
- (*pcb_data).wrapping_sub(
- ((p_next as (isize)).wrapping_sub(data as (isize))
- / mem::size_of::() as (isize)) as (usize),
- ),
- );
- *pcb_data = (*pcb_data).wrapping_add(cb_moved as (usize));
- if cb_item != 0usize {
- p_temp = p_temp.offset(-(cb_len as (isize)));
- p_temp = p_temp.offset(_ykpiv_set_length(p_temp, cb_item) as (isize));
- memcpy(p_temp as (*mut c_void), p_item as (*const c_void), cb_item);
- }
- ErrorKind::YKPIV_OK
- })
- })
+ return ErrorKind::GenericError;
}
+
+ while p_temp < data.add(*pcb_data) {
+ tag_temp = *p_temp;
+ p_temp = p_temp.add(1);
+
+ cb_len = _ykpiv_get_length(p_temp, &mut cb_temp);
+ p_temp = p_temp.add(cb_len);
+
+ if tag_temp == tag {
+ break;
+ }
+
+ p_temp = p_temp.add(cb_temp);
+ }
+
+ if tag_temp != tag {
+ if cb_item == 0 {
+ return ErrorKind::Ok;
+ }
+
+ p_temp = data.add(*pcb_data);
+ cb_len = _get_length_size(cb_item) as (usize);
+
+ if (*pcb_data).wrapping_add(cb_len).wrapping_add(cb_item) > cb_data_max {
+ return ErrorKind::GenericError;
+ }
+
+ *p_temp = tag;
+ p_temp = p_temp.add(1);
+ p_temp = p_temp.add(_ykpiv_set_length(p_temp, cb_item));
+
+ memcpy(p_temp as (*mut c_void), p_item as (*const c_void), cb_item);
+ *pcb_data += 1 + cb_len + cb_item;
+
+ return ErrorKind::Ok;
+ }
+
+ if cb_temp == cb_item {
+ memcpy(p_temp as (*mut c_void), p_item as (*const c_void), cb_item);
+ return ErrorKind::Ok;
+ }
+
+ p_next = p_temp.add(cb_temp);
+ cb_moved = cb_item as (isize) - cb_temp as (isize)
+ + (if cb_item != 0 {
+ _get_length_size(cb_item)
+ } else {
+ -1
+ } as (isize)
+ - cb_len as (isize));
+
+ if (*pcb_data + cb_moved as usize) > cb_data_max {
+ return ErrorKind::GenericError;
+ }
+
+ memmove(
+ p_next.offset(cb_moved) as (*mut c_void),
+ p_next as (*const c_void),
+ (*pcb_data).wrapping_sub(
+ ((p_next as (isize)).wrapping_sub(data as (isize)) / mem::size_of::() as (isize))
+ as (usize),
+ ),
+ );
+
+ *pcb_data = (*pcb_data).wrapping_add(cb_moved as (usize));
+
+ if cb_item != 0 {
+ p_temp = p_temp.offset(-(cb_len as (isize)));
+ p_temp = p_temp.add(_ykpiv_set_length(p_temp, cb_item));
+ memcpy(p_temp as (*mut c_void), p_item as (*const c_void), cb_item);
+ }
+
+ ErrorKind::Ok
}
+/// Read metadata
unsafe fn _read_metadata(
- mut state: *mut ykpiv_state,
- mut tag: u8,
- mut data: *mut u8,
- mut pcb_data: *mut usize,
+ state: *mut YubiKey,
+ tag: u8,
+ data: *mut u8,
+ pcb_data: *mut usize,
) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut p_temp: *mut u8 = 0i32 as (*mut c_void) as (*mut u8);
- let mut cb_temp: usize = 0usize;
- let mut obj_id: i32 = 0i32;
- if data.is_null() || pcb_data.is_null() || 3072usize > *pcb_data {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- if tag as (i32) == 0x88i32 {
- obj_id = 0x5fc109i32;
- } else if tag as (i32) == 0x80i32 {
- obj_id = 0x5fff00i32;
- } else {
- return ErrorKind::YKPIV_INVALID_OBJECT;
- }
- cb_temp = *pcb_data;
- *pcb_data = 0usize;
- (if ErrorKind::YKPIV_OK as (i32) != {
- res = _ykpiv_fetch_object(state, obj_id, data, &mut cb_temp as (*mut usize));
- res
- } as (i32)
- {
- res
- } else if cb_temp < 2usize {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- p_temp = data;
- (if tag as (i32)
- != *{
- let _old = p_temp;
- p_temp = p_temp.offset(1isize);
- _old
- } as (i32)
- {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- p_temp =
- p_temp.offset(_ykpiv_get_length(p_temp as (*const u8), pcb_data) as (isize));
- (if *pcb_data
- > cb_temp.wrapping_sub(
- ((p_temp as (isize)).wrapping_sub(data as (isize))
- / mem::size_of::() as (isize)) as (usize),
- )
- {
- *pcb_data = 0usize;
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- memmove(data as (*mut c_void), p_temp as (*const c_void), *pcb_data);
- ErrorKind::YKPIV_OK
- })
- })
- })
+ let mut p_temp: *mut u8;
+ let mut cb_temp: usize;
+ let res: ErrorKind;
+
+ if data.is_null() || pcb_data.is_null() || YKPIV_OBJ_MAX_SIZE > *pcb_data {
+ return ErrorKind::GenericError;
}
+
+ let obj_id = match tag {
+ TAG_ADMIN => YKPIV_OBJ_ADMIN_DATA,
+ TAG_PROTECTED => YKPIV_OBJ_PRINTED,
+ _ => return ErrorKind::InvalidObject,
+ } as i32;
+
+ cb_temp = *pcb_data;
+ *pcb_data = 0;
+
+ res = _ykpiv_fetch_object(state, obj_id, data, &mut cb_temp);
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ if cb_temp < CB_OBJ_TAG_MIN {
+ return ErrorKind::GenericError;
+ }
+ p_temp = data;
+
+ if tag as (i32)
+ != *{
+ let _old = p_temp;
+ p_temp = p_temp.offset(1);
+ _old
+ } as (i32)
+ {
+ return ErrorKind::GenericError;
+ }
+
+ p_temp = p_temp.add(_ykpiv_get_length(p_temp, pcb_data));
+
+ if *pcb_data > cb_temp - (p_temp as isize - data as isize) as usize {
+ *pcb_data = 0;
+ return ErrorKind::GenericError;
+ }
+
+ memmove(data as (*mut c_void), p_temp as (*const c_void), *pcb_data);
+ ErrorKind::Ok
}
+/// Write metadata
unsafe fn _write_metadata(
- mut state: *mut ykpiv_state,
- mut tag: u8,
- mut data: *mut u8,
- mut cb_data: usize,
+ state: *mut YubiKey,
+ tag: u8,
+ data: *mut u8,
+ cb_data: usize,
) -> ErrorKind {
- let mut res: ErrorKind = ErrorKind::YKPIV_OK;
- let mut buf = [0u8; 3063];
- let mut pTemp: *mut u8 = buf.as_mut_ptr();
- let mut obj_id: i32 = 0i32;
- if cb_data > _obj_size_max(state).wrapping_sub((2i32 + 2i32) as (usize)) {
- ErrorKind::YKPIV_GENERIC_ERROR
- } else {
- if tag as (i32) == 0x88i32 {
- obj_id = 0x5fc109i32;
- } else if tag as (i32) == 0x80i32 {
- obj_id = 0x5fff00i32;
- } else {
- return ErrorKind::YKPIV_INVALID_OBJECT;
- }
- if data.is_null() || 0usize == cb_data {
- res = _ykpiv_save_object(state, obj_id, 0i32 as (*mut c_void) as (*mut u8), 0usize);
- } else {
- *{
- let _old = pTemp;
- pTemp = pTemp.offset(1isize);
- _old
- } = tag;
- pTemp = pTemp.offset(_ykpiv_set_length(pTemp, cb_data) as (isize));
- memcpy(pTemp as (*mut c_void), data as (*const c_void), cb_data);
- pTemp = pTemp.offset(cb_data as (isize));
- res = _ykpiv_save_object(
- state,
- obj_id,
- buf.as_mut_ptr(),
- ((pTemp as (isize)).wrapping_sub(buf.as_mut_ptr() as (isize))
- / mem::size_of::() as (isize)) as (usize),
- );
- }
- res
+ let mut buf = [0u8; CB_OBJ_MAX]; // XXX REMEMBER TO ZERO
+ let mut p_temp: *mut u8 = buf.as_mut_ptr();
+
+ if cb_data > _obj_size_max(state) - CB_OBJ_TAG_MAX {
+ return ErrorKind::GenericError;
}
+
+ let obj_id = match tag {
+ TAG_ADMIN => YKPIV_OBJ_ADMIN_DATA,
+ TAG_PROTECTED => YKPIV_OBJ_PRINTED,
+ _ => return ErrorKind::InvalidObject,
+ } as i32;
+
+ if data.is_null() || cb_data == 0 {
+ return _ykpiv_save_object(state, obj_id, ptr::null_mut(), 0);
+ }
+
+ *{
+ let _old = p_temp;
+ p_temp = p_temp.offset(1);
+ _old
+ } = tag;
+
+ p_temp = p_temp.add(_ykpiv_set_length(p_temp, cb_data));
+ memcpy(p_temp as (*mut c_void), data as (*const c_void), cb_data);
+ p_temp = p_temp.add(cb_data);
+
+ _ykpiv_save_object(
+ state,
+ obj_id,
+ buf.as_mut_ptr(),
+ ((p_temp as (isize)).wrapping_sub(buf.as_mut_ptr() as (isize))
+ / mem::size_of::() as (isize)) as (usize),
+ )
}
diff --git a/src/ykpiv.c b/src/ykpiv.c
index 4ac6667..a22aa42 100644
--- a/src/ykpiv.c
+++ b/src/ykpiv.c
@@ -373,7 +373,7 @@ static ykpiv_rc _ykpiv_connect(ykpiv_state *state, uintptr_t context, uintptr_t
return YKPIV_PCSC_ERROR;
}
- state->isNEO = (((sizeof(YKPIV_ATR_NEO_R3) - 1) == atr_len) && (0 == memcmp(YKPIV_ATR_NEO_R3, atr, atr_len)));
+ state->is_neo = (((sizeof(YKPIV_ATR_NEO_R3) - 1) == atr_len) && (0 == memcmp(YKPIV_ATR_NEO_R3, atr, atr_len)));
}
state->context = context;
diff --git a/src/yubikey.rs b/src/yubikey.rs
new file mode 100644
index 0000000..75b76ba
--- /dev/null
+++ b/src/yubikey.rs
@@ -0,0 +1,2549 @@
+//! YubiKey-related types and communication support
+
+// Adapted from yubico-piv-tool:
+//
+//
+// Copyright (c) 2014-2016 Yubico AB
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#![allow(non_snake_case, non_upper_case_globals)]
+#![allow(clippy::too_many_arguments, clippy::missing_safety_doc)]
+
+use crate::{
+ apdu::APDU,
+ consts::*,
+ error::{ykpiv_strerror, ErrorKind},
+ internal::{
+ des_decrypt, des_destroy_key, des_encrypt, des_import_key, yk_des_is_weak_key,
+ DesErrorKind, DesKey, PRngErrorKind, _ykpiv_prng_generate,
+ },
+};
+use libc::{c_char, free, malloc, memcmp, memcpy, memmove, memset, strlen, strncasecmp};
+use std::{convert::TryInto, ffi::CStr, mem, os::raw::c_void, ptr, slice};
+use zeroize::Zeroize;
+
+extern "C" {
+ fn SCardBeginTransaction(hCard: i32) -> i32;
+ fn SCardConnect(
+ hContext: i32,
+ szReader: *const c_char,
+ dwShareMode: u32,
+ dwPreferredProtocols: u32,
+ phCard: *mut i32,
+ pdwActiveProtocol: *mut u32,
+ ) -> i32;
+ fn SCardDisconnect(hCard: i32, dwDisposition: u32) -> i32;
+ fn SCardEndTransaction(hCard: i32, dwDisposition: u32) -> i32;
+ fn SCardEstablishContext(
+ dwScope: u32,
+ pvReserved1: *const c_void,
+ pvReserved2: *const c_void,
+ phContext: *mut i32,
+ ) -> i32;
+ fn SCardIsValidContext(hContext: i32) -> i32;
+ fn SCardListReaders(
+ hContext: i32,
+ mszGroups: *const c_char,
+ mszReaders: *mut c_char,
+ pcchReaders: *mut u32,
+ ) -> i32;
+ fn SCardReconnect(
+ hCard: i32,
+ dwShareMode: u32,
+ dwPreferredProtocols: u32,
+ dwInitialization: u32,
+ pdwActiveProtocol: *mut u32,
+ ) -> i32;
+ fn SCardReleaseContext(hContext: i32) -> i32;
+ fn SCardStatus(
+ hCard: i32,
+ mszReaderNames: *mut u8,
+ pcchReaderLen: *mut u32,
+ pdwState: *mut u32,
+ pdwProtocol: *mut u32,
+ pbAtr: *mut u8,
+ pcbAtrLen: *mut u32,
+ ) -> i32;
+ fn SCardTransmit(
+ hCard: i32,
+ pioSendPci: *const c_void,
+ pbSendBuffer: *mut c_char,
+ cbSendLength: u32,
+ pioRecvPci: *const c_void,
+ pbRecvBuffer: *mut u8,
+ pcbRecvLength: *mut u32,
+ ) -> i32;
+}
+
+/// TEMPORARY PLACEHOLDER for SCARD PCI_T1
+// TODO(tarcieri): PLACEHOLDER!
+pub const SCARD_PCI_T1: *const c_void = ptr::null();
+
+/// TEMPORARY PLACEHOLDER for SCARD success value
+// TODO(tarcieri): PLACEHOLDER!
+pub const SCARD_S_SUCCESS: i32 = 0;
+
+/// Application ID(?)
+pub const AID: [u8; 5] = [0xa0, 0x00, 0x00, 0x03, 0x08];
+
+/// YubiKey PIV version
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub struct Version {
+ /// Major version component
+ pub major: u8,
+
+ /// Minor version component
+ pub minor: u8,
+
+ /// Patch version component
+ pub patch: u8,
+}
+
+/// YubiKey PIV state
+// TODO(tarcieri): reduce coupling to internal fields via `pub(crate)`
+#[derive(Copy, Clone, Debug)]
+pub struct YubiKey {
+ pub(crate) context: i32,
+ pub(crate) card: i32,
+ pub(crate) verbose: i32,
+ pub(crate) pin: *mut u8,
+ pub(crate) is_neo: bool,
+ pub(crate) ver: Version,
+ pub(crate) serial: u32,
+}
+
+/// Set length
+pub(crate) unsafe fn _ykpiv_set_length(buffer: *mut u8, length: usize) -> usize {
+ if length < 0x80 {
+ *buffer = length as u8;
+ 1
+ } else if length < 0x100 {
+ *buffer = 0x81;
+ *buffer.add(1) = length as u8;
+ 2
+ } else {
+ *buffer = 0x82;
+ *buffer.add(1) = ((length >> 8) & 0xff) as u8;
+ *buffer.add(2) = (length & 0xff) as u8;
+ 3
+ }
+}
+
+/// Get length
+pub(crate) unsafe fn _ykpiv_get_length(buffer: *const u8, len: *mut usize) -> usize {
+ if *buffer < 0x81 {
+ *len = *buffer as usize;
+ 1
+ } else if (*buffer & 0x7f) == 1 {
+ *len = *buffer.add(1) as usize;
+ 2
+ } else if (*buffer & 0x7f) == 2 {
+ let tmp = *buffer.add(1) as usize;
+ *len = (tmp << 8) + *buffer.add(2) as usize;
+ 3
+ } else {
+ 0
+ }
+}
+
+/// Is length valid?
+pub(crate) unsafe fn _ykpiv_has_valid_length(buffer: *const u8, len: usize) -> bool {
+ ((*buffer as i32) < 0x81 && (len > 0))
+ || ((*buffer as i32 & 0x7f == 1) && (len > 1))
+ || ((*buffer as i32 & 0x7f == 2) && (len > 2))
+}
+
+/// Initialize YubiKey client instance
+pub unsafe fn ykpiv_init(state: *mut *mut YubiKey, verbose: i32) -> ErrorKind {
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ let s = malloc(mem::size_of::()) as (*mut YubiKey);
+
+ if s.is_null() {
+ return ErrorKind::MemoryError;
+ }
+
+ memset(s as (*mut c_void), 0i32, mem::size_of::());
+ (*s).pin = ptr::null_mut();
+ (*s).verbose = verbose;
+ (*s).context = -1i32;
+ *state = s;
+ ErrorKind::Ok
+}
+
+/// Cleanup YubiKey session
+pub(crate) unsafe fn _ykpiv_done(state: *mut YubiKey, disconnect: bool) -> ErrorKind {
+ if disconnect {
+ ykpiv_disconnect(state);
+ }
+
+ _cache_pin(state, ptr::null(), 0);
+ free(state as *mut c_void);
+ ErrorKind::Ok
+}
+
+/// Cleanup YubiKey session with external card upon completion
+// TODO(tarcieri): make this a `Drop` handler
+pub unsafe fn ykpiv_done_with_external_card(state: *mut YubiKey) -> ErrorKind {
+ _ykpiv_done(state, false)
+}
+
+/// Cleanup YubiKey session upon completion
+pub unsafe fn ykpiv_done(state: *mut YubiKey) -> ErrorKind {
+ _ykpiv_done(state, true)
+}
+
+/// Disconnect a YubiKey session
+pub unsafe fn ykpiv_disconnect(state: *mut YubiKey) -> ErrorKind {
+ if (*state).card != 0 {
+ SCardDisconnect((*state).card, 0x1);
+ (*state).card = 0i32;
+ }
+
+ if SCardIsValidContext((*state).context) == 0x0 {
+ SCardReleaseContext((*state).context);
+ (*state).context = -1i32;
+ }
+
+ ErrorKind::Ok
+}
+
+/// Select application
+pub(crate) unsafe fn _ykpiv_select_application(state: *mut YubiKey) -> ErrorKind {
+ let mut data = [0u8; 255];
+ let mut recv_len = data.len() as u32;
+ let mut sw = 0i32;
+ let mut res: ErrorKind;
+
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_SELECT_APPLICATION;
+ apdu.p1 = 0x04;
+ apdu.lc = AID.len() as u8;
+
+ memcpy(
+ apdu.data.as_mut_ptr() as *mut c_void,
+ AID.as_ptr() as *const c_void,
+ AID.len(),
+ );
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed communicating with card: \'{}\'",
+ ykpiv_strerror(res)
+ );
+ }
+ } else if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed selecting application: {:04x}", sw);
+ }
+ return ErrorKind::GenericError;
+ }
+
+ // now that the PIV application is selected, retrieve the version
+ // and serial number. Previously the NEO/YK4 required switching
+ // to the yk applet to retrieve the serial, YK5 implements this
+ // as a PIV applet command. Unfortunately, this change requires
+ // that we retrieve the version number first, so that get_serial
+ // can determine how to get the serial number, which for the NEO/Yk4
+ // will result in another selection of the PIV applet.
+
+ res = _ykpiv_get_version(state, ptr::null_mut());
+ if res != ErrorKind::Ok && (*state).verbose != 0 {
+ eprintln!("Failed to retrieve version: \'{}\'", ykpiv_strerror(res));
+ }
+
+ res = _ykpiv_get_serial(state, ptr::null_mut(), false);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed to retrieve serial number: \'{}\'",
+ ykpiv_strerror(res)
+ );
+ }
+
+ res = ErrorKind::Ok;
+ }
+
+ res
+}
+
+/// Ensure an application is selected (presently noop)
+pub(crate) unsafe fn _ykpiv_ensure_application_selected(_state: *mut YubiKey) -> ErrorKind {
+ // TODO(tarcieri): ENABLE_APPLICATION_RESELECTION support?
+ //
+ // Original C code below:
+ //
+ // #if ENABLE_APPLICATION_RESELECTION
+ // if (NULL == state) {
+ // return YKPIV_GENERIC_ERROR;
+ // }
+ //
+ // res = ykpiv_verify(state, NULL, 0);
+ //
+ // if ((YKPIV_OK != res) && (YKPIV_WRONG_PIN != res)) {
+ // res = _ykpiv_select_application(state);
+ // }
+ // else {
+ // res = YKPIV_OK;
+ // }
+ //
+ // return res;
+ // #else
+ // (void)state;
+ // return res;
+ // #endif
+
+ ErrorKind::Ok
+}
+
+/// Connect to the YubiKey
+pub(crate) unsafe fn _ykpiv_connect(state: *mut YubiKey, context: usize, card: usize) -> ErrorKind {
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ // if the context has changed, and the new context is not valid, return an error
+ if context != (*state).context as (usize) && (0x0i32 != SCardIsValidContext(context as (i32))) {
+ return ErrorKind::PcscError;
+ }
+
+ // if card handle has changed, determine if handle is valid (less efficient, but complete)
+ if card != (*state).card as usize {
+ let mut reader = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut reader_len = reader.len() as u32;
+ let mut atr = [0u8; 33];
+ let mut atr_len = atr.len() as u32;
+
+ // Cannot set the reader len to NULL. Confirmed in OSX 10.10,
+ // so we have to retrieve it even though we don't need it.
+ if SCardStatus(
+ card as i32,
+ reader.as_mut_ptr(),
+ &mut reader_len,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ atr.as_mut_ptr(),
+ &mut atr_len,
+ ) != 0
+ {
+ return ErrorKind::PcscError;
+ }
+
+ (*state).is_neo = (atr_len as usize == YKPIV_ATR_NEO_R3.len() - 1)
+ && (memcmp(
+ YKPIV_ATR_NEO_R3.as_ptr() as *const c_void,
+ atr.as_mut_ptr() as *const c_void,
+ atr_len as usize,
+ ) == 0);
+ }
+
+ (*state).context = context as i32;
+ (*state).card = card as i32;
+
+ // Do not select the applet here, as we need to accommodate commands that are
+ // sensitive to re-select (custom apdu/auth). All commands that can handle explicit
+ // selection already check the applet state and select accordingly anyway.
+ // ykpiv_verify_select is supplied for those who want to select explicitly.
+ //
+ // The applet _is_ selected by ykpiv_connect(), but is not selected when bypassing
+ // it with ykpiv_connect_with_external_card().
+
+ ErrorKind::Ok
+}
+
+/// Connect to an external card
+pub unsafe fn ykpiv_connect_with_external_card(
+ state: *mut YubiKey,
+ context: usize,
+ card: usize,
+) -> ErrorKind {
+ _ykpiv_connect(state, context, card)
+}
+
+/// Connect to a YubiKey
+pub unsafe fn ykpiv_connect(state: *mut YubiKey, wanted: *const c_char) -> ErrorKind {
+ let mut _currentBlock;
+ let mut active_protocol: u32 = 0;
+ let mut reader_buf: [c_char; 2048] = [0; 2048];
+ let mut num_readers = reader_buf.len();
+ let mut rc: isize;
+ let mut reader_ptr: *mut c_char;
+ let mut card: i32 = -1i32;
+
+ let mut ret: ErrorKind = ykpiv_list_readers(state, reader_buf.as_mut_ptr(), &mut num_readers);
+
+ if ret != ErrorKind::Ok {
+ return ret;
+ }
+ reader_ptr = reader_buf.as_mut_ptr();
+ loop {
+ if *reader_ptr == b'\0' as c_char {
+ _currentBlock = 3;
+ break;
+ }
+ if !wanted.is_null() {
+ let mut ptr = reader_ptr;
+ let mut found: bool = false;
+ loop {
+ if strlen(ptr) < strlen(wanted) {
+ _currentBlock = 14;
+ break;
+ }
+ if strncasecmp(ptr, wanted, strlen(wanted)) == 0i32 {
+ _currentBlock = 13;
+ break;
+ }
+ if *{
+ let _old = ptr;
+ ptr = ptr.offset(1);
+ _old
+ } == 0
+ {
+ _currentBlock = 14;
+ break;
+ }
+ }
+ if _currentBlock == 13 {
+ found = true;
+ }
+ if found as (i32) == 0i32 {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "skipping reader \'{}\' since it doesn\'t match \'{}\'.",
+ CStr::from_ptr(reader_ptr).to_string_lossy(),
+ CStr::from_ptr(wanted).to_string_lossy()
+ );
+ _currentBlock = 26;
+ } else {
+ _currentBlock = 26;
+ }
+ } else {
+ _currentBlock = 15;
+ }
+ } else {
+ _currentBlock = 15;
+ }
+ if _currentBlock == 15 {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "trying to connect to reader \'{}\'.",
+ CStr::from_ptr(reader_ptr).to_string_lossy()
+ );
+ }
+ rc = SCardConnect(
+ (*state).context,
+ reader_ptr,
+ 0x2u32,
+ 0x2u32,
+ &mut card,
+ &mut active_protocol,
+ ) as (isize);
+ if rc != 0x0 {
+ if (*state).verbose != 0 {
+ eprintln!("SCardConnect failed, rc={}", rc);
+ }
+ } else {
+ // at this point, card should not equal state->card,
+ // to allow _ykpiv_connect() to determine device type
+ let res = _ykpiv_connect(state, (*state).context as (usize), card as (usize));
+ if res != ErrorKind::Ok {
+ _currentBlock = 19;
+ break;
+ }
+ }
+ }
+
+ reader_ptr = reader_ptr.add(strlen(reader_ptr) + 1);
+ }
+
+ if _currentBlock == 3 {
+ if *reader_ptr == b'\0' as c_char {
+ if (*state).verbose != 0 {
+ eprintln!("error: no usable reader found.");
+ }
+
+ SCardReleaseContext((*state).context);
+ (*state).context = -1;
+ return ErrorKind::PcscError;
+ } else {
+ return ErrorKind::GenericError;
+ }
+ }
+
+ // Select applet. This is done here instead of in _ykpiv_connect() because
+ // you may not want to select the applet when connecting to a card handle that
+ // was supplied by an external library.
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ ret = _ykpiv_select_application(state);
+ _ykpiv_end_transaction(state);
+ ret
+}
+
+/// List readers
+pub unsafe fn ykpiv_list_readers(
+ state: *mut YubiKey,
+ readers: *mut c_char,
+ len: *mut usize,
+) -> ErrorKind {
+ let mut num_readers: u32 = 0u32;
+ let mut rc: i32;
+
+ if SCardIsValidContext((*state).context) != 0 {
+ rc = SCardEstablishContext(0x2, ptr::null(), ptr::null(), &mut (*state).context);
+
+ if rc != 0 {
+ if (*state).verbose != 0 {
+ eprintln!("error: SCardEstablishContext failed, rc={}", rc);
+ }
+ return ErrorKind::PcscError;
+ }
+ }
+
+ rc = SCardListReaders(
+ (*state).context,
+ ptr::null(),
+ ptr::null_mut(),
+ &mut num_readers,
+ );
+
+ if rc != 0 {
+ if (*state).verbose != 0 {
+ eprintln!("error: SCardListReaders failed, rc={}", rc);
+ }
+ SCardReleaseContext((*state).context);
+ (*state).context = -1i32;
+ return ErrorKind::PcscError;
+ }
+
+ if num_readers as (usize) > *len {
+ num_readers = *len as (u32);
+ } else if num_readers as (usize) < *len {
+ *len = num_readers as (usize);
+ }
+
+ rc = SCardListReaders((*state).context, ptr::null(), readers, &mut num_readers);
+
+ if rc != 0 {
+ if (*state).verbose != 0 {
+ eprintln!("error: SCardListReaders failed, rc={}", rc);
+ }
+
+ SCardReleaseContext((*state).context);
+ (*state).context = -1i32;
+ return ErrorKind::PcscError;
+ }
+
+ *len = num_readers as usize;
+ ErrorKind::Ok
+}
+
+/// Reconnect to a YubiKey
+pub(crate) unsafe fn reconnect(state: *mut YubiKey) -> ErrorKind {
+ let mut active_protocol: u32 = 0;
+ let mut tries: i32 = 0;
+
+ if (*state).verbose != 0 {
+ eprintln!("trying to reconnect to current reader.");
+ }
+
+ let rc = SCardReconnect((*state).card, 0x2u32, 0x2u32, 0x1u32, &mut active_protocol);
+
+ if rc != 0x0 {
+ if (*state).verbose != 0 {
+ eprintln!("SCardReconnect failed, rc={}", rc);
+ }
+ return ErrorKind::PcscError;
+ }
+
+ let res = _ykpiv_select_application(state);
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ if !(*state).pin.is_null() {
+ ykpiv_verify(state, (*state).pin as *const c_char, &mut tries)
+ } else {
+ ErrorKind::Ok
+ }
+}
+
+/// Begin a transaction
+pub(crate) unsafe fn _ykpiv_begin_transaction(state: *mut YubiKey) -> ErrorKind {
+ let mut rc = SCardBeginTransaction((*state).card);
+
+ if rc as usize & 0xffff_ffff == 0x8010_0068 {
+ let res = reconnect(state);
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ rc = SCardBeginTransaction((*state).card);
+ }
+
+ if rc != 0 {
+ if (*state).verbose != 0 {
+ eprintln!("error: Failed to begin pcsc transaction, rc={}", rc);
+ }
+
+ return ErrorKind::PcscError;
+ }
+
+ ErrorKind::Ok
+}
+
+/// End a transaction
+pub(crate) unsafe fn _ykpiv_end_transaction(state: *mut YubiKey) -> ErrorKind {
+ let rc = SCardEndTransaction((*state).card, 0x0);
+
+ if rc != 0x0 && (*state).verbose != 0 {
+ eprintln!("error: Failed to end pcsc transaction, rc={}", rc);
+ return ErrorKind::PcscError;
+ }
+
+ ErrorKind::Ok
+}
+
+/// Transfer data
+pub(crate) unsafe fn _ykpiv_transfer_data(
+ state: *mut YubiKey,
+ templ: *const u8,
+ in_data: *const u8,
+ in_len: isize,
+ mut out_data: *mut u8,
+ out_len: *mut usize,
+ sw: *mut i32,
+) -> ErrorKind {
+ let mut _currentBlock;
+ let mut in_ptr: *const u8 = in_data;
+ let max_out = *out_len;
+ let mut res: ErrorKind;
+ let mut recv_len: u32;
+
+ *out_len = 0;
+
+ loop {
+ let mut this_size: usize = 0xff;
+ let mut data = [0u8; 261];
+ recv_len = data.len() as u32;
+
+ let mut apdu = APDU::default();
+ apdu.cla = *templ;
+ apdu.ins = *templ.offset(1);
+ apdu.p1 = *templ.offset(2);
+ apdu.p2 = *templ.offset(3);
+
+ if in_ptr.offset(0xff) < in_data.offset(in_len) {
+ apdu.cla = 0x10;
+ } else {
+ this_size = in_data.offset(in_len) as usize - in_ptr as usize;
+ }
+
+ if (*state).verbose > 2 {
+ eprintln!("Going to send {} bytes in this go.", this_size);
+ }
+
+ apdu.lc = this_size.try_into().unwrap();
+ memcpy(
+ apdu.data.as_mut_ptr() as *mut c_void,
+ in_ptr as *const c_void,
+ this_size,
+ );
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, sw);
+
+ if res != ErrorKind::Ok {
+ _currentBlock = 24;
+ break;
+ }
+ if *sw != SW_SUCCESS && (*sw >> 8 != 0x61) {
+ _currentBlock = 24;
+ break;
+ }
+ if (*out_len)
+ .wrapping_add(recv_len as (usize))
+ .wrapping_sub(2usize)
+ > max_out
+ {
+ _currentBlock = 21;
+ break;
+ }
+
+ if !out_data.is_null() {
+ memcpy(
+ out_data as (*mut c_void),
+ data.as_mut_ptr() as (*const c_void),
+ recv_len.wrapping_sub(2u32) as (usize),
+ );
+ out_data = out_data.offset(recv_len.wrapping_sub(2u32) as (isize));
+ *out_len = (*out_len).wrapping_add(recv_len.wrapping_sub(2u32) as (usize));
+ }
+
+ in_ptr = in_ptr.add(this_size);
+
+ if in_ptr >= in_data.offset(in_len) {
+ _currentBlock = 10;
+ break;
+ }
+ }
+
+ if _currentBlock == 10 {
+ loop {
+ if *sw >> 8 != 0x61 {
+ _currentBlock = 24;
+ break;
+ }
+
+ let mut data = [0u8; 261];
+ recv_len = data.len() as u32;
+
+ if (*state).verbose > 2 {
+ eprintln!(
+ "The card indicates there is {} bytes more data for us.",
+ *sw & 0xff
+ );
+ }
+
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_GET_RESPONSE_APDU;
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, sw);
+
+ if res != ErrorKind::Ok {
+ _currentBlock = 24;
+ break;
+ }
+ if *sw != SW_SUCCESS && (*sw >> 8 != 0x61) {
+ _currentBlock = 24;
+ break;
+ }
+ if (*out_len).wrapping_add(recv_len as (usize)).wrapping_sub(2) > max_out {
+ _currentBlock = 18;
+ break;
+ }
+
+ if out_data.is_null() {
+ continue;
+ }
+
+ memcpy(
+ out_data as (*mut c_void),
+ data.as_mut_ptr() as (*const c_void),
+ recv_len.wrapping_sub(2) as (usize),
+ );
+
+ out_data = out_data.offset(recv_len.wrapping_sub(2) as (isize));
+ *out_len = (*out_len).wrapping_add(recv_len.wrapping_sub(2) as (usize));
+ }
+
+ if _currentBlock != 24 {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Output buffer to small, wanted to write {}, max was {}.",
+ (*out_len).wrapping_add(recv_len as usize).wrapping_sub(2),
+ max_out
+ );
+ }
+ res = ErrorKind::SizeError;
+ }
+ } else if _currentBlock == 21 {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Output buffer to small, wanted to write {}, max was {}.",
+ (*out_len).wrapping_add(recv_len as usize).wrapping_sub(2),
+ max_out
+ );
+ }
+ res = ErrorKind::SizeError;
+ }
+ res
+}
+
+/// Transfer data
+pub unsafe fn ykpiv_transfer_data(
+ state: *mut YubiKey,
+ templ: *const u8,
+ in_data: *const u8,
+ in_len: isize,
+ out_data: *mut u8,
+ out_len: *mut usize,
+ sw: *mut i32,
+) -> ErrorKind {
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ *out_len = 0;
+ return ErrorKind::PcscError;
+ }
+
+ let res = _ykpiv_transfer_data(state, templ, in_data, in_len, out_data, out_len, sw);
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Dump hex
+pub(crate) unsafe fn dump_hex(buf: *const u8, len: u32) {
+ let mut i: u32 = 0;
+
+ while i < len {
+ eprintln!("{:02x} ", *buf.offset(i as isize));
+ i += 1;
+ }
+}
+
+/// Send data
+pub(crate) unsafe fn _send_data(
+ state: *mut YubiKey,
+ apdu: *mut APDU,
+ data: *mut u8,
+ recv_len: *mut u32,
+ sw: *mut i32,
+) -> ErrorKind {
+ let send_len = (*apdu).lc as u32 + 5;
+ let mut tmp_len = *recv_len;
+
+ if (*state).verbose > 1 {
+ eprint!("> ");
+ dump_hex((*apdu).as_ptr() as *const u8, send_len);
+ eprintln!();
+ }
+
+ let rc = SCardTransmit(
+ (*state).card,
+ SCARD_PCI_T1,
+ (*apdu).as_mut_ptr() as *mut i8,
+ send_len,
+ ptr::null(),
+ data,
+ &mut tmp_len,
+ );
+
+ if rc != SCARD_S_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("error: SCardTransmit failed, rc={:08x}", rc);
+ }
+
+ return ErrorKind::PcscError;
+ }
+
+ *recv_len = tmp_len;
+
+ if (*state).verbose > 1 {
+ eprint!("< ");
+ dump_hex(data, *recv_len);
+ eprintln!();
+ }
+
+ if *recv_len >= 2 {
+ *sw = *data.offset((*recv_len).wrapping_sub(2) as (isize)) as (i32) << 8
+ | *data.offset((*recv_len).wrapping_sub(1) as (isize)) as (i32);
+ } else {
+ *sw = 0;
+ }
+
+ ErrorKind::Ok
+}
+
+/// Default authentication key
+pub const DEFAULT_AUTH_KEY: &[u8] = b"\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\x01\x02\x03\x04\x05\x06\x07\x08\0";
+
+/// Authenticate to the card
+pub unsafe fn ykpiv_authenticate(state: *mut YubiKey, mut key: *const u8) -> ErrorKind {
+ let mut data = [0u8; 261];
+ let mut challenge = [0u8; 8];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let mut drc: DesErrorKind;
+ let mut mgm_key: *mut DesKey = ptr::null_mut();
+ let mut out_len: usize;
+ let mut res = ErrorKind::Ok;
+
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ if key.is_null() {
+ key = DEFAULT_AUTH_KEY.as_ptr();
+ }
+
+ // set up our key
+ drc = des_import_key(1i32, key, (8i32 * 3i32) as (usize), &mut mgm_key);
+
+ if drc != DesErrorKind::Ok {
+ assert!(
+ mgm_key.is_null(),
+ "didn't expect mgm key to be set by failing op!"
+ );
+ _ykpiv_end_transaction(state);
+ return ErrorKind::AlgorithmError;
+ }
+
+ // get a challenge from the card
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_AUTHENTICATE;
+ apdu.p1 = YKPIV_ALGO_3DES; // triple des
+ apdu.p2 = YKPIV_KEY_CARDMGM; // management key
+ apdu.lc = 0x04;
+ apdu.data[0] = 0x7c;
+ apdu.data[1] = 0x02;
+ apdu.data[2] = 0x80;
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ _ykpiv_end_transaction(state);
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::AuthenticationError;
+ }
+
+ memcpy(
+ challenge.as_mut_ptr() as *mut c_void,
+ data.as_ptr().offset(4) as *const c_void,
+ 8,
+ );
+
+ // send a response to the cards challenge and a challenge of our own.
+ let mut response = [0u8; 8];
+ out_len = response.len();
+
+ drc = des_decrypt(
+ mgm_key,
+ challenge.as_ptr(),
+ challenge.len(),
+ response.as_mut_ptr(),
+ &mut out_len,
+ );
+
+ if drc != DesErrorKind::Ok {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::AuthenticationError;
+ }
+
+ recv_len = data.len() as u32;
+ apdu = APDU::default();
+ apdu.ins = YKPIV_INS_AUTHENTICATE;
+ apdu.p1 = YKPIV_ALGO_3DES; // triple des
+ apdu.p2 = YKPIV_KEY_CARDMGM; // management key
+ apdu.data[0] = 0x7c;
+ apdu.data[1] = 20; // 2 + 8 + 2 +8
+ apdu.data[2] = 0x80;
+ apdu.data[3] = 8;
+ memcpy(
+ apdu.data[4..12].as_mut_ptr() as *mut c_void,
+ response.as_ptr() as *const c_void,
+ 8,
+ );
+ apdu.data[12] = 0x81;
+ apdu.data[13] = 8;
+
+ if _ykpiv_prng_generate(data[14..20].as_mut_ptr(), 8) == PRngErrorKind::GeneralError {
+ if (*state).verbose != 0 {
+ eprintln!("Failed getting randomness for authentication.");
+ }
+
+ _ykpiv_end_transaction(state);
+ return ErrorKind::RandomnessError;
+ }
+
+ memcpy(
+ challenge.as_mut_ptr() as *mut c_void,
+ data[14..20].as_ptr() as *const c_void,
+ 8,
+ );
+ apdu.lc = 20;
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ _ykpiv_end_transaction(state);
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::AuthenticationError;
+ }
+
+ // compare the response from the card with our challenge
+ let mut response = [0u8; 8];
+ out_len = response.len();
+ drc = des_encrypt(
+ mgm_key,
+ challenge.as_ptr(),
+ mem::size_of::<[u8; 8]>(),
+ response.as_mut_ptr(),
+ &mut out_len,
+ );
+
+ if drc == DesErrorKind::Ok
+ // TODO(tarcieri): constant time comparison!
+ && memcmp(
+ response.as_mut_ptr() as *const c_void,
+ data.as_mut_ptr().offset(4) as *const c_void,
+ 8,
+ ) == 0
+ {
+ res = ErrorKind::Ok;
+ } else {
+ res = ErrorKind::AuthenticationError;
+ }
+ }
+
+ if !mgm_key.is_null() {
+ des_destroy_key(mgm_key);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Set the management key (MGM)
+pub unsafe fn ykpiv_set_mgmkey(state: *mut YubiKey, new_key: *const u8) -> ErrorKind {
+ ykpiv_set_mgmkey2(state, new_key, 0)
+}
+
+/// Set the management key (MGM)
+pub(crate) unsafe fn ykpiv_set_mgmkey2(
+ state: *mut YubiKey,
+ new_key: *const u8,
+ touch: u8,
+) -> ErrorKind {
+ let mut data = [0u8; 261];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let mut res = ErrorKind::Ok;
+ let mut apdu = APDU::default();
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ if yk_des_is_weak_key(new_key, (8i32 * 3i32) as (usize)) {
+ if (*state).verbose != 0 {
+ // TODO(tarcieri): format string
+ eprint!("Won\'t set new key \'");
+ dump_hex(new_key, DES_LEN_3DES as u32);
+ eprintln!("\' since it\'s weak (with odd parity).");
+ }
+ res = ErrorKind::KeyError;
+ apdu.ins = YKPIV_INS_SET_MGMKEY;
+ apdu.p1 = 0xff;
+
+ apdu.p2 = match touch {
+ 0 => 0xff,
+ 1 => 0xfe,
+ _ => {
+ _ykpiv_end_transaction(state);
+ return ErrorKind::GenericError;
+ }
+ };
+
+ apdu.lc = DES_LEN_3DES as u8 + 3;
+ apdu.data[0] = YKPIV_ALGO_3DES;
+ apdu.data[1] = YKPIV_KEY_CARDMGM;
+ apdu.data[2] = DES_LEN_3DES as u8;
+ memcpy(
+ apdu.data.as_mut_ptr().offset(3) as *mut c_void,
+ new_key as *const c_void,
+ DES_LEN_3DES,
+ );
+ } else {
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok && sw != SW_SUCCESS {
+ res = ErrorKind::GenericError;
+ }
+ }
+ }
+
+ apdu.zeroize();
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Authenticate to the YubiKey
+pub(crate) unsafe fn _general_authenticate(
+ state: *mut YubiKey,
+ sign_in: *const u8,
+ in_len: usize,
+ out: *mut u8,
+ out_len: *mut usize,
+ algorithm: u8,
+ key: u8,
+ decipher: bool,
+) -> ErrorKind {
+ let mut _currentBlock;
+ let mut indata = [0u8; 1024];
+ let mut dataptr: *mut u8 = indata.as_mut_ptr();
+ let mut data = [0u8; 1024];
+ let templ = [0, YKPIV_INS_AUTHENTICATE, algorithm, key];
+ let mut recv_len = data.len();
+ let mut sw: i32 = 0;
+ let bytes: usize;
+ let mut len: usize = 0;
+ let res: ErrorKind;
+
+ match algorithm {
+ YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => {
+ let key_len = if algorithm == YKPIV_ALGO_RSA1024 {
+ 128
+ } else {
+ 256
+ };
+
+ if in_len != key_len {
+ return ErrorKind::SizeError;
+ } else {
+ _currentBlock = 16;
+ }
+ }
+ YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => {
+ let key_len = if algorithm == YKPIV_ALGO_ECCP256 {
+ 32
+ } else {
+ 48
+ };
+
+ if (!decipher && (in_len > key_len)) || (decipher && (in_len != (key_len * 2) + 1)) {
+ return ErrorKind::SizeError;
+ }
+ }
+ _ => return ErrorKind::AlgorithmError,
+ }
+
+ if in_len < 0x80 {
+ bytes = 1;
+ } else if in_len < 0xff {
+ bytes = 2;
+ } else {
+ bytes = 3;
+ }
+
+ *dataptr = 0x7c;
+ dataptr = dataptr.add(_ykpiv_set_length(dataptr, in_len + bytes + 3));
+ *dataptr = 0x82;
+ *dataptr.add(1) = 0x00;
+ *dataptr.add(2) =
+ if (algorithm == YKPIV_ALGO_ECCP256 || algorithm == YKPIV_ALGO_ECCP384) && decipher {
+ 0x85
+ } else {
+ 0x81
+ };
+ dataptr = dataptr.add(3 + _ykpiv_set_length(dataptr, in_len));
+ memcpy(dataptr as *mut c_void, sign_in as *const c_void, in_len);
+ dataptr = dataptr.add(in_len);
+
+ res = ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ indata.as_mut_ptr(),
+ dataptr as isize - indata.as_mut_ptr() as isize,
+ data.as_mut_ptr(),
+ &mut recv_len,
+ &mut sw,
+ );
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!("Sign command failed to communicate.");
+ }
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed sign command with code {:x}.\n\0", sw);
+ }
+
+ if sw == SW_ERR_SECURITY_STATUS {
+ return ErrorKind::AuthenticationError;
+ } else {
+ return ErrorKind::GenericError;
+ }
+ }
+
+ // skip the first 7c tag
+ if data[0] != 0x7c {
+ if (*state).verbose != 0 {
+ eprintln!("Failed parsing signature reply.");
+ }
+ return ErrorKind::ParseError;
+ }
+
+ dataptr = data.as_mut_ptr().add(1);
+ dataptr = dataptr.add(_ykpiv_get_length(dataptr, &mut len));
+
+ // skip the 82 tag
+ if *dataptr != 0x82 {
+ if (*state).verbose != 0 {
+ eprintln!("Failed parsing signature reply.");
+ }
+
+ return ErrorKind::ParseError;
+ }
+
+ dataptr = dataptr.add(1);
+ dataptr = dataptr.add(_ykpiv_get_length(dataptr, &mut len));
+
+ if len > *out_len {
+ if (*state).verbose != 0 {
+ eprintln!("Wrong size on output buffer.");
+ }
+ return ErrorKind::SizeError;
+ }
+
+ *out_len = len;
+ memcpy(out as (*mut c_void), dataptr as (*const c_void), len);
+ ErrorKind::Ok
+}
+
+/// Sign data using a PIV key
+pub unsafe fn ykpiv_sign_data(
+ state: *mut YubiKey,
+ raw_in: *const u8,
+ in_len: usize,
+ sign_out: *mut u8,
+ out_len: *mut usize,
+ algorithm: u8,
+ key: u8,
+) -> ErrorKind {
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ // don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS
+
+ let res = _general_authenticate(
+ state, raw_in, in_len, sign_out, out_len, algorithm, key, false,
+ );
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Decrypt data using a PIV key
+pub unsafe fn ykpiv_decrypt_data(
+ state: *mut YubiKey,
+ input: *const u8,
+ input_len: usize,
+ out: *mut u8,
+ out_len: *mut usize,
+ algorithm: u8,
+ key: u8,
+) -> ErrorKind {
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ // don't attempt to reselect in crypt operations to avoid problems with PIN_ALWAYS
+
+ let res = _general_authenticate(state, input, input_len, out, out_len, algorithm, key, true);
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Get the version of the PIV application installed on the YubiKey
+pub(crate) unsafe fn _ykpiv_get_version(state: *mut YubiKey, p_version: *mut Version) -> ErrorKind {
+ let mut data = [0u8; 261];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let res: ErrorKind;
+
+ if state.is_null() {
+ return ErrorKind::ArgumentError;
+ }
+
+ // get version from state if already from device
+ if (*state).ver.major != 0 || (*state).ver.minor != 0 || (*state).ver.patch != 0 {
+ if !p_version.is_null() {
+ // TODO(tarcieri): use real references instead of pointers and memcpy!!!
+ #[allow(trivial_casts)]
+ memcpy(
+ p_version as *mut c_void,
+ &(*state).ver as *const Version as *const c_void,
+ mem::size_of::(),
+ );
+ }
+
+ return ErrorKind::Ok;
+ }
+
+ // get version from device
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_GET_VERSION;
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ return ErrorKind::GenericError;
+ }
+
+ if recv_len < 3 {
+ return ErrorKind::SizeError;
+ }
+
+ (*state).ver.major = data[0];
+ (*state).ver.minor = data[1];
+ (*state).ver.patch = data[2];
+
+ if !p_version.is_null() {
+ // TODO(tarcieri): use real references instead of pointers and memcpy!!!
+ #[allow(trivial_casts)]
+ memcpy(
+ p_version as *mut c_void,
+ &(*state).ver as (*const Version) as (*const c_void),
+ mem::size_of::(),
+ );
+ }
+
+ ErrorKind::Ok
+}
+
+/// Get the YubiKey's PIV application version as a string
+pub unsafe fn ykpiv_get_version(state: *mut YubiKey) -> Result {
+ let mut ver: Version = Version {
+ major: 0u8,
+ minor: 0u8,
+ patch: 0u8,
+ };
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return Err(ErrorKind::PcscError);
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ let res = _ykpiv_get_version(state, &mut ver);
+
+ if res == ErrorKind::Ok {
+ _ykpiv_end_transaction(state);
+ return Ok(format!("{}.{}.{}", ver.major, ver.minor, ver.patch));
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ Err(ErrorKind::GenericError)
+}
+
+/// Get YubiKey device serial number
+///
+/// NOTE: caller must make sure that this is wrapped in a transaction for synchronized operation
+pub(crate) unsafe fn _ykpiv_get_serial(
+ state: *mut YubiKey,
+ p_serial: *mut u32,
+ f_force: bool,
+) -> ErrorKind {
+ let mut _currentBlock;
+ let mut res;
+ let yk_applet: *const u8 = ptr::null();
+ let mut data = [0u8; 255];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let p_temp: *mut u8;
+
+ if state.is_null() {
+ return ErrorKind::ArgumentError;
+ }
+
+ if !f_force && (*state).serial != 0 {
+ if !p_serial.is_null() {
+ *p_serial = (*state).serial;
+ }
+
+ return ErrorKind::Ok;
+ }
+
+ if (*state).ver.major < 5 {
+ // get serial from neo/yk4 devices using the otp applet
+ let mut temp = [0u8; 255];
+ recv_len = temp.len() as u32;
+
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_SELECT_APPLICATION;
+ apdu.p1 = 0x04;
+ apdu.lc = mem::size_of_val(&yk_applet) as u8;
+
+ memcpy(
+ apdu.data.as_mut_ptr() as *mut c_void,
+ yk_applet as *const c_void,
+ mem::size_of_val(&yk_applet),
+ );
+
+ res = _send_data(state, &mut apdu, temp.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed communicating with card: \'{}\'",
+ ykpiv_strerror(res)
+ );
+ }
+
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed selecting yk application: {:04x}", sw);
+ }
+
+ return ErrorKind::GenericError;
+ }
+
+ recv_len = temp.len() as u32;
+ apdu = APDU::default();
+ apdu.ins = 0x01;
+ apdu.p1 = 0x10;
+ apdu.lc = 0x00;
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed communicating with card: \'{}\'",
+ ykpiv_strerror(res)
+ );
+ }
+
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed retrieving serial number: {:04x}", sw);
+ }
+
+ return ErrorKind::GenericError;
+ }
+
+ recv_len = temp.len() as u32;
+ apdu = APDU::default();
+ apdu.ins = YKPIV_INS_SELECT_APPLICATION;
+ apdu.p1 = 0x04;
+ apdu.lc = mem::size_of_val(&AID) as u8;
+
+ memcpy(
+ apdu.data.as_mut_ptr() as *mut c_void,
+ AID.as_ptr() as *const c_void,
+ mem::size_of_val(&AID),
+ );
+
+ res = _send_data(state, &mut apdu, temp.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed communicating with card: \'{}\'",
+ ykpiv_strerror(res)
+ );
+ }
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed selecting application: {:04x}", sw);
+ }
+ return ErrorKind::GenericError;
+ }
+
+ _currentBlock = 17;
+ } else {
+ // get serial from yk5 and later devices using the f8 command
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_GET_SERIAL;
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed communicating with card: \'{}\'",
+ ykpiv_strerror(res)
+ );
+ }
+ return res;
+ } else if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed retrieving serial number: {:04x}", sw);
+ }
+ return ErrorKind::GenericError;
+ }
+ _currentBlock = 17;
+ }
+
+ if _currentBlock == 17 {
+ // check that we received enough data for the serial number
+ if recv_len < 4 {
+ return ErrorKind::SizeError;
+ }
+
+ // TODO(tarcieri): replace pointers and casts with proper references!
+ #[allow(trivial_casts)]
+ {
+ p_temp = &mut (*state).serial as (*mut u32) as (*mut u8);
+ }
+
+ *p_temp = data[3];
+ *p_temp.add(1) = data[2];
+ *p_temp.add(2) = data[1];
+ *p_temp.add(3) = data[0];
+
+ if !p_serial.is_null() {
+ *p_serial = (*state).serial;
+ }
+ }
+
+ res
+}
+
+/// Get YubiKey device serial number
+pub unsafe fn ykpiv_get_serial(state: *mut YubiKey, p_serial: *mut u32) -> ErrorKind {
+ let mut res = ErrorKind::Ok;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_get_serial(state, p_serial, false);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Cache PIN in memory
+// TODO(tarcieri): better security around the cached PIN
+pub(crate) unsafe fn _cache_pin(state: *mut YubiKey, pin: *const c_char, len: usize) -> ErrorKind {
+ if state.is_null() {
+ return ErrorKind::ArgumentError;
+ }
+
+ if !pin.is_null() && ((*state).pin as *const c_char == pin) {
+ return ErrorKind::Ok;
+ }
+
+ if !(*state).pin.is_null() {
+ // Zeroize the old cached PIN
+ let old_len = strlen((*state).pin as *const c_char);
+ let pin_slice = slice::from_raw_parts_mut((*state).pin, old_len);
+ pin_slice.zeroize();
+
+ free((*state).pin as (*mut c_void));
+ (*state).pin = ptr::null_mut();
+ }
+
+ if !pin.is_null() && len > 0 {
+ (*state).pin = malloc(len + 1) as (*mut u8);
+
+ if (*state).pin.is_null() {
+ return ErrorKind::MemoryError;
+ }
+
+ memcpy((*state).pin as (*mut c_void), pin as (*const c_void), len);
+ *(*state).pin.add(len) = 0u8;
+ }
+
+ ErrorKind::Ok
+}
+
+/// Verify device PIN
+pub unsafe fn ykpiv_verify(state: *mut YubiKey, pin: *const c_char, tries: *mut i32) -> ErrorKind {
+ ykpiv_verify_select(
+ state,
+ pin,
+ if !pin.is_null() { strlen(pin) } else { 0 },
+ tries,
+ false,
+ )
+}
+
+/// Verify device PIN
+pub(crate) unsafe fn _verify(
+ state: *mut YubiKey,
+ pin: *const c_char,
+ pin_len: usize,
+ tries: *mut i32,
+) -> ErrorKind {
+ let mut data = [0u8; 261];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let res: ErrorKind;
+
+ if pin_len > CB_PIN_MAX {
+ return ErrorKind::SizeError;
+ }
+
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_VERIFY;
+ apdu.p1 = 0x00;
+ apdu.p2 = 0x80;
+ apdu.lc = if pin.is_null() { 0 } else { 0x08 };
+
+ if !pin.is_null() {
+ memcpy(
+ apdu.data.as_mut_ptr() as *mut c_void,
+ pin as *const c_void,
+ pin_len,
+ );
+
+ if pin_len < CB_PIN_MAX {
+ memset(
+ apdu.data.as_mut_ptr().add(pin_len) as *mut c_void,
+ 0xff,
+ CB_PIN_MAX - pin_len,
+ );
+ }
+ }
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ apdu.zeroize();
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ if sw == SW_SUCCESS {
+ if !pin.is_null() && (pin_len != 0) {
+ // Intentionally ignore errors. If the PIN fails to save, it will only
+ // be a problem if a reconnect is attempted. Failure deferred until then.
+ _cache_pin(state, pin, pin_len);
+ }
+
+ if !tries.is_null() {
+ *tries = sw & 0xf;
+ }
+ ErrorKind::Ok
+ } else if sw >> 8 == 0x63 {
+ if !tries.is_null() {
+ *tries = sw & 0xf;
+ }
+ ErrorKind::WrongPin
+ } else if sw == SW_ERR_AUTH_BLOCKED {
+ if !tries.is_null() {
+ *tries = 0;
+ }
+ ErrorKind::WrongPin
+ } else {
+ ErrorKind::GenericError
+ }
+}
+
+/// Verify and select application
+pub unsafe fn ykpiv_verify_select(
+ state: *mut YubiKey,
+ pin: *const c_char,
+ pin_len: usize,
+ tries: *mut i32,
+ force_select: bool,
+) -> ErrorKind {
+ let mut res = ErrorKind::Ok;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if force_select {
+ res = _ykpiv_ensure_application_selected(state);
+ }
+
+ if res == ErrorKind::Ok {
+ res = _verify(state, pin, pin_len, tries);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Get the number of PIN retries
+pub unsafe fn ykpiv_get_pin_retries(state: *mut YubiKey, tries: *mut i32) -> ErrorKind {
+ if state.is_null() || tries.is_null() {
+ return ErrorKind::ArgumentError;
+ }
+
+ // Force a re-select to unverify, because once verified the spec dictates that
+ // subsequent verify calls will return a "verification not needed" instead of
+ // the number of tries left...
+ let res = _ykpiv_select_application(state);
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ let ykrc = ykpiv_verify(state, ptr::null(), tries);
+
+ // WRONG_PIN is expected on successful query.
+ if ykrc == ErrorKind::WrongPin {
+ ErrorKind::Ok
+ } else {
+ ykrc
+ }
+}
+
+/// Set the number of PIN retries
+pub unsafe fn ykpiv_set_pin_retries(
+ state: *mut YubiKey,
+ pin_tries: i32,
+ puk_tries: i32,
+) -> ErrorKind {
+ let mut res = ErrorKind::Ok;
+ let mut templ = [0, YKPIV_INS_SET_PIN_RETRIES, 0, 0];
+ let mut data = [0u8; 255];
+ let mut recv_len: usize = data.len();
+ let mut sw: i32 = 0i32;
+
+ // Special case: if either retry count is 0, it's a successful no-op
+ if pin_tries == 0 || puk_tries == 0 {
+ return ErrorKind::Ok;
+ }
+
+ if pin_tries > 0xff || puk_tries > 0xff || pin_tries < 1 || puk_tries < 1 {
+ return ErrorKind::RangeError;
+ }
+
+ templ[2] = pin_tries as (u8);
+ templ[3] = puk_tries as (u8);
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ ptr::null(),
+ 0,
+ data.as_mut_ptr(),
+ &mut recv_len,
+ &mut sw,
+ );
+
+ if res == ErrorKind::Ok {
+ res = match sw {
+ SW_SUCCESS => ErrorKind::Ok,
+ SW_ERR_AUTH_BLOCKED => ErrorKind::AuthenticationError,
+ SW_ERR_SECURITY_STATUS => ErrorKind::AuthenticationError,
+ _ => ErrorKind::GenericError,
+ };
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Change the PIN
+pub(crate) unsafe fn _ykpiv_change_pin(
+ state: *mut YubiKey,
+ action: i32,
+ current_pin: *const c_char,
+ current_pin_len: usize,
+ new_pin: *const c_char,
+ new_pin_len: usize,
+ tries: *mut i32,
+) -> ErrorKind {
+ let mut sw: i32 = 0;
+ let mut templ = [0, YKPIV_INS_CHANGE_REFERENCE, 0, 0x80];
+ let mut indata = [0u8; 16];
+ let mut data = [0u8; 255];
+ let mut recv_len: usize = data.len();
+ let res: ErrorKind;
+
+ if current_pin_len > 8 || new_pin_len > 8 {
+ return ErrorKind::SizeError;
+ }
+
+ if action == CHREF_ACT_UNBLOCK_PIN {
+ templ[1] = YKPIV_INS_RESET_RETRY;
+ } else if action == CHREF_ACT_CHANGE_PUK {
+ templ[3] = 0x81;
+ }
+
+ memcpy(
+ indata.as_mut_ptr() as (*mut c_void),
+ current_pin as (*const c_void),
+ current_pin_len,
+ );
+
+ if current_pin_len < 8 {
+ memset(
+ indata.as_mut_ptr().add(current_pin_len) as *mut c_void,
+ 0xff,
+ 8 - current_pin_len,
+ );
+ }
+
+ memcpy(
+ indata.as_mut_ptr().offset(8) as *mut c_void,
+ new_pin as *const c_void,
+ new_pin_len,
+ );
+
+ if new_pin_len < 8 {
+ memset(
+ indata.as_mut_ptr().offset(8).add(new_pin_len) as *mut c_void,
+ 0xff,
+ 8 - new_pin_len,
+ );
+ }
+
+ res = ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ indata.as_mut_ptr(),
+ indata.len() as isize,
+ data.as_mut_ptr(),
+ &mut recv_len,
+ &mut sw,
+ );
+
+ indata.zeroize();
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ if sw >> 8 == 0x63 {
+ if !tries.is_null() {
+ *tries = sw & 0xf;
+ }
+
+ return ErrorKind::WrongPin;
+ } else if sw == SW_ERR_AUTH_BLOCKED {
+ return ErrorKind::PinLocked;
+ } else {
+ if (*state).verbose != 0 {
+ eprintln!("Failed changing pin, token response code: {:x}.", sw);
+ }
+
+ return ErrorKind::GenericError;
+ }
+ }
+
+ ErrorKind::Ok
+}
+
+/// Change the Personal Identification Number (PIN).
+///
+/// The default PIN code is 123456
+pub unsafe fn ykpiv_change_pin(
+ state: *mut YubiKey,
+ current_pin: *const c_char,
+ current_pin_len: usize,
+ new_pin: *const c_char,
+ new_pin_len: usize,
+ tries: *mut i32,
+) -> ErrorKind {
+ let mut res: ErrorKind = ErrorKind::GenericError;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_change_pin(
+ state,
+ 0,
+ current_pin,
+ current_pin_len,
+ new_pin,
+ new_pin_len,
+ tries,
+ );
+
+ if res == ErrorKind::Ok && !new_pin.is_null() {
+ // Intentionally ignore errors. If the PIN fails to save, it will only
+ // be a problem if a reconnect is attempted. Failure deferred until then.
+ _cache_pin(state, new_pin, new_pin_len);
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Change the PIN Unblocking Key (PUK). PUKs are codes for resetting
+/// lost/forgotten PINs, or devices that have become blocked because of too
+/// many failed attempts.
+///
+/// The PUK is part of the PIV standard that the YubiKey follows.
+///
+/// The default PUK code is 12345678.
+pub unsafe fn ykpiv_change_puk(
+ state: *mut YubiKey,
+ current_puk: *const c_char,
+ current_puk_len: usize,
+ new_puk: *const c_char,
+ new_puk_len: usize,
+ tries: *mut i32,
+) -> ErrorKind {
+ let mut res = ErrorKind::GenericError;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_change_pin(
+ state,
+ 2,
+ current_puk,
+ current_puk_len,
+ new_puk,
+ new_puk_len,
+ tries,
+ );
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Unblock a Personal Identification Number (PIN) using a previously
+/// configured PIN Unblocking Key (PUK).
+pub unsafe fn ykpiv_unblock_pin(
+ state: *mut YubiKey,
+ puk: *const c_char,
+ puk_len: usize,
+ new_pin: *const c_char,
+ new_pin_len: usize,
+ tries: *mut i32,
+) -> ErrorKind {
+ let mut res = ErrorKind::GenericError;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_change_pin(state, 1, puk, puk_len, new_pin, new_pin_len, tries);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Fetch an object from the YubiKey
+pub unsafe fn ykpiv_fetch_object(
+ state: *mut YubiKey,
+ object_id: i32,
+ data: *mut u8,
+ len: *mut usize,
+) -> ErrorKind {
+ let mut res = ErrorKind::Ok;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_fetch_object(state, object_id, data, len);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Fetch an object
+pub(crate) unsafe fn _ykpiv_fetch_object(
+ state: *mut YubiKey,
+ object_id: i32,
+ data: *mut u8,
+ len: *mut usize,
+) -> ErrorKind {
+ let mut sw: i32 = 0;
+ let mut indata = [0u8; 5];
+ let mut inptr: *mut u8 = indata.as_mut_ptr();
+ let templ = [0, YKPIV_INS_GET_DATA, 0x3f, 0xff];
+ let res: ErrorKind;
+
+ inptr = set_object(object_id, inptr);
+
+ if inptr.is_null() {
+ return ErrorKind::InvalidObject;
+ }
+
+ res = ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ indata.as_mut_ptr(),
+ inptr as isize - indata.as_mut_ptr() as isize,
+ data,
+ len,
+ &mut sw,
+ );
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ if sw != SW_SUCCESS {
+ return ErrorKind::GenericError;
+ }
+
+ let mut outlen: usize = 0;
+
+ if *len < 2 || !_ykpiv_has_valid_length(data.offset(1), (*len).wrapping_sub(1)) {
+ return ErrorKind::SizeError;
+ }
+
+ let offs = _ykpiv_get_length(data.offset(1), &mut outlen);
+
+ if offs == 0 {
+ return ErrorKind::SizeError;
+ }
+
+ if outlen.wrapping_add(offs).wrapping_add(1) != *len {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Invalid length indicated in object, total objlen is {}, indicated length is {}.",
+ *len, outlen
+ );
+ }
+
+ return ErrorKind::SizeError;
+ }
+
+ memmove(
+ data as *mut c_void,
+ data.add(1).add(offs) as *const c_void,
+ outlen,
+ );
+ *len = outlen;
+
+ ErrorKind::Ok
+}
+
+/// Save an object
+pub unsafe fn ykpiv_save_object(
+ state: *mut YubiKey,
+ object_id: i32,
+ indata: *mut u8,
+ len: usize,
+) -> ErrorKind {
+ let mut res = ErrorKind::Ok;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = _ykpiv_save_object(state, object_id, indata, len);
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Save an object
+pub unsafe fn _ykpiv_save_object(
+ state: *mut YubiKey,
+ object_id: i32,
+ indata: *mut u8,
+ len: usize,
+) -> ErrorKind {
+ let mut data = [0u8; YKPIV_OBJ_MAX_SIZE];
+ let mut dataptr: *mut u8 = data.as_mut_ptr();
+ let templ = [0, YKPIV_INS_PUT_DATA, 0x3f, 0xff];
+ let mut sw: i32 = 0;
+ let res: ErrorKind;
+ let mut outlen: usize = 0usize;
+
+ if len > CB_OBJ_MAX {
+ return ErrorKind::SizeError;
+ }
+
+ dataptr = set_object(object_id, dataptr);
+
+ if dataptr.is_null() {
+ return ErrorKind::InvalidObject;
+ }
+ *{
+ let _old = dataptr;
+ dataptr = dataptr.offset(1);
+ _old
+ } = 0x53;
+
+ dataptr = dataptr.add(_ykpiv_set_length(dataptr, len));
+ memcpy(dataptr as (*mut c_void), indata as (*const c_void), len);
+ dataptr = dataptr.add(len);
+
+ res = _ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ data.as_mut_ptr(),
+ dataptr as isize - data.as_mut_ptr() as isize,
+ ptr::null_mut(),
+ &mut outlen,
+ &mut sw,
+ );
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ match sw {
+ SW_SUCCESS => ErrorKind::Ok,
+ SW_ERR_SECURITY_STATUS => ErrorKind::AuthenticationError,
+ _ => ErrorKind::GenericError,
+ }
+}
+
+/// Set an object
+pub(crate) unsafe fn set_object(object_id: i32, mut buffer: *mut u8) -> *mut u8 {
+ *buffer = 0x5c;
+
+ if object_id == YKPIV_OBJ_DISCOVERY as i32 {
+ *buffer.add(1) = 1;
+ *buffer.add(2) = YKPIV_OBJ_DISCOVERY as u8;
+ buffer = buffer.add(3);
+ } else if object_id > 0xffff && object_id <= 0x00ff_ffff {
+ *buffer.add(1) = 3;
+ *buffer.add(2) = ((object_id >> 16) & 0xff) as u8;
+ *buffer.add(3) = ((object_id >> 8) & 0xff) as u8;
+ *buffer.add(4) = (object_id & 0xff) as u8;
+ buffer = buffer.add(5);
+ }
+
+ buffer
+}
+
+/// Import a private encryption or signing key into the YubiKey
+pub unsafe fn ykpiv_import_private_key(
+ state: *mut YubiKey,
+ key: u8,
+ algorithm: u8,
+ p: *const u8,
+ p_len: usize,
+ q: *const u8,
+ q_len: usize,
+ dp: *const u8,
+ dp_len: usize,
+ dq: *const u8,
+ dq_len: usize,
+ qinv: *const u8,
+ qinv_len: usize,
+ ec_data: *const u8,
+ ec_data_len: u8,
+ pin_policy: u8,
+ touch_policy: u8,
+) -> ErrorKind {
+ let mut key_data = [0u8; 1024];
+ let mut in_ptr: *mut u8 = key_data.as_mut_ptr();
+ let templ = [0, YKPIV_INS_IMPORT_KEY, algorithm, key];
+ let mut data = [0u8; 256];
+ let mut recv_len = data.len();
+ let mut elem_len: u32 = 0;
+ let mut sw: i32 = 0;
+ let mut params: [*const u8; 5] = [ptr::null(); 5];
+ let mut lens = [0usize; 5];
+ let n_params: u8;
+ let param_tag: i32;
+ let mut res = ErrorKind::Ok;
+
+ if state.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if key == YKPIV_KEY_CARDMGM
+ || key < YKPIV_KEY_RETIRED1
+ || key > YKPIV_KEY_RETIRED20 && (key < YKPIV_KEY_AUTHENTICATION)
+ || key > YKPIV_KEY_CARDAUTH && (key != YKPIV_KEY_ATTESTATION)
+ {
+ return ErrorKind::KeyError;
+ }
+
+ if pin_policy != YKPIV_PINPOLICY_DEFAULT
+ && (pin_policy != YKPIV_PINPOLICY_NEVER)
+ && (pin_policy != YKPIV_PINPOLICY_ONCE)
+ && (pin_policy != YKPIV_PINPOLICY_ALWAYS)
+ {
+ return ErrorKind::GenericError;
+ }
+
+ if touch_policy != YKPIV_TOUCHPOLICY_DEFAULT
+ && (touch_policy != YKPIV_TOUCHPOLICY_NEVER)
+ && (touch_policy != YKPIV_TOUCHPOLICY_ALWAYS)
+ && (touch_policy != YKPIV_TOUCHPOLICY_CACHED)
+ {
+ return ErrorKind::GenericError;
+ }
+
+ match algorithm {
+ YKPIV_ALGO_RSA1024 | YKPIV_ALGO_RSA2048 => {
+ if p_len + q_len + dp_len + dq_len + qinv_len >= 1024 {
+ return ErrorKind::SizeError;
+ } else {
+ if algorithm == YKPIV_ALGO_RSA1024 {
+ elem_len = 64;
+ }
+
+ if algorithm == YKPIV_ALGO_RSA2048 {
+ elem_len = 128;
+ }
+
+ if p.is_null() || q.is_null() || dp.is_null() || dq.is_null() || qinv.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ params[0] = p;
+ lens[0] = p_len;
+ params[1] = q;
+ lens[1] = q_len;
+ params[2] = dp;
+ lens[2] = dp_len;
+ params[3] = dq;
+ lens[3] = dq_len;
+ params[4] = qinv;
+ lens[4] = qinv_len;
+ param_tag = 0x1;
+ n_params = 5u8;
+ }
+ }
+ YKPIV_ALGO_ECCP256 | YKPIV_ALGO_ECCP384 => {
+ if ec_data_len as (usize) >= key_data.len() {
+ return ErrorKind::SizeError;
+ }
+
+ if algorithm == YKPIV_ALGO_ECCP256 {
+ elem_len = 32;
+ } else if algorithm == YKPIV_ALGO_ECCP384 {
+ elem_len = 48;
+ }
+
+ if ec_data.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ params[0] = ec_data;
+ lens[0] = ec_data_len as usize;
+ param_tag = 0x6;
+ n_params = 1;
+ }
+ _ => return ErrorKind::AlgorithmError,
+ }
+
+ for i in 0..n_params {
+ *in_ptr = (param_tag + i as i32) as u8;
+ in_ptr = in_ptr.offset(1);
+
+ in_ptr = in_ptr.add(_ykpiv_set_length(in_ptr, elem_len as usize));
+ let padding = (elem_len as (usize)).wrapping_sub(lens[i as usize]);
+ let remaining = (key_data.as_mut_ptr() as usize) + 1024 - in_ptr as usize;
+
+ if padding > remaining {
+ return ErrorKind::AlgorithmError;
+ }
+
+ memset(in_ptr as *mut c_void, 0, padding);
+ in_ptr = in_ptr.add(padding);
+ memcpy(
+ in_ptr as *mut c_void,
+ params[i as usize] as *const c_void,
+ lens[i as usize],
+ );
+ in_ptr = in_ptr.add(lens[i as usize]);
+ }
+
+ if pin_policy != YKPIV_PINPOLICY_DEFAULT {
+ *in_ptr = YKPIV_PINPOLICY_TAG;
+ *in_ptr.add(1) = 0x01;
+ *in_ptr.add(2) = pin_policy;
+ in_ptr = in_ptr.add(3);
+ }
+
+ if touch_policy != YKPIV_TOUCHPOLICY_DEFAULT {
+ *in_ptr = YKPIV_TOUCHPOLICY_TAG;
+ *in_ptr.add(1) = 0x01;
+ *in_ptr.add(2) = touch_policy;
+ in_ptr = in_ptr.add(3);
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ } else if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ key_data.as_mut_ptr(),
+ in_ptr as isize - key_data.as_mut_ptr() as isize,
+ data.as_mut_ptr(),
+ &mut recv_len,
+ &mut sw,
+ );
+
+ if res == ErrorKind::Ok && sw != SW_SUCCESS {
+ res = ErrorKind::GenericError;
+ if sw == SW_ERR_SECURITY_STATUS {
+ res = ErrorKind::AuthenticationError;
+ }
+ }
+ }
+
+ key_data.zeroize();
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Generate an attestation certificate for a stored key
+pub unsafe fn ykpiv_attest(
+ state: *mut YubiKey,
+ key: u8,
+ data: *mut u8,
+ data_len: *mut usize,
+) -> ErrorKind {
+ let mut res = ErrorKind::GenericError;
+ let templ = [0, YKPIV_INS_ATTEST, key, 0];
+ let mut sw: i32 = 0;
+ let mut ul_data_len: usize;
+
+ if state.is_null() || data.is_null() || data_len.is_null() {
+ return ErrorKind::ArgumentError;
+ }
+
+ ul_data_len = *data_len;
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ res = ykpiv_transfer_data(
+ state,
+ templ.as_ptr(),
+ ptr::null(),
+ 0,
+ data,
+ &mut ul_data_len,
+ &mut sw,
+ );
+
+ if res == ErrorKind::Ok {
+ if sw != SW_SUCCESS {
+ res = ErrorKind::GenericError;
+ if sw == SW_ERR_NOT_SUPPORTED {
+ res = ErrorKind::NotSupported;
+ }
+ } else if *data as i32 != 0x30 {
+ res = ErrorKind::GenericError;
+ } else {
+ *data_len = ul_data_len;
+ }
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Get an auth challenge
+pub unsafe fn ykpiv_auth_getchallenge(
+ state: *mut YubiKey,
+ challenge: *mut u8,
+ challenge_len: usize,
+) -> ErrorKind {
+ let mut data = [0u8; 261];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let mut res = ErrorKind::Ok;
+
+ if state.is_null() || challenge.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if challenge_len != 8 {
+ return ErrorKind::SizeError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ if _ykpiv_ensure_application_selected(state) == ErrorKind::Ok {
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_AUTHENTICATE;
+ apdu.p1 = YKPIV_ALGO_3DES; // triple des
+ apdu.p2 = YKPIV_KEY_CARDMGM; // management key
+ apdu.lc = 0x04;
+ apdu.data[0] = 0x7c;
+ apdu.data[1] = 0x02;
+ apdu.data[2] = 0x81; //0x80;
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ if sw != SW_SUCCESS {
+ res = ErrorKind::AuthenticationError;
+ } else {
+ memcpy(
+ challenge as (*mut c_void),
+ data.as_mut_ptr().offset(4isize) as (*const c_void),
+ 8usize,
+ );
+ }
+ }
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// Verify an auth response
+pub unsafe fn ykpiv_auth_verifyresponse(
+ state: *mut YubiKey,
+ response: *mut u8,
+ response_len: usize,
+) -> ErrorKind {
+ let mut data = [0u8; 261];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let mut res: ErrorKind;
+
+ if state.is_null() || response.is_null() {
+ return ErrorKind::GenericError;
+ }
+
+ if response_len != 8 {
+ return ErrorKind::SizeError;
+ }
+
+ if _ykpiv_begin_transaction(state) != ErrorKind::Ok {
+ return ErrorKind::PcscError;
+ }
+
+ // send the response to the card and a challenge of our own.
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_AUTHENTICATE;
+ apdu.p1 = YKPIV_ALGO_3DES; // triple des
+ apdu.p2 = YKPIV_KEY_CARDMGM; // management key
+ apdu.data[0] = 0x7c;
+ apdu.data[1] = 0x0a; // 2 + 8
+ apdu.data[2] = 0x82;
+ apdu.data[3] = 8;
+
+ memcpy(
+ apdu.data.as_mut_ptr().add(4) as *mut c_void,
+ response as *const c_void,
+ response_len,
+ );
+
+ apdu.lc = 12;
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res == ErrorKind::Ok && sw != SW_SUCCESS {
+ res = ErrorKind::AuthenticationError;
+ }
+
+ apdu.zeroize();
+ _ykpiv_end_transaction(state);
+ res
+}
+
+/// MGMT Application ID(?)
+static mut MGMT_AID: [u8; 8] = [0xa0, 0x00, 0x00, 0x05, 0x27, 0x47, 0x11, 0x17];
+
+/// Deauthenticate
+pub unsafe fn ykpiv_auth_deauthenticate(state: *mut YubiKey) -> ErrorKind {
+ let mut data = [0u8; 255];
+ let mut recv_len = data.len() as u32;
+ let mut sw: i32 = 0;
+ let mut res: ErrorKind;
+
+ if state.is_null() {
+ return ErrorKind::ArgumentError;
+ }
+
+ res = _ykpiv_begin_transaction(state);
+
+ if res != ErrorKind::Ok {
+ return res;
+ }
+
+ let mut apdu = APDU::default();
+ apdu.ins = YKPIV_INS_SELECT_APPLICATION;
+ apdu.p1 = 0x04;
+ apdu.lc = mem::size_of::<*const u8>() as u8;
+
+ memcpy(
+ apdu.data.as_mut_ptr() as *mut c_void,
+ MGMT_AID.as_ptr() as *const c_void,
+ MGMT_AID.len(),
+ );
+
+ res = _send_data(state, &mut apdu, data.as_mut_ptr(), &mut recv_len, &mut sw);
+
+ if res != ErrorKind::Ok {
+ if (*state).verbose != 0 {
+ eprintln!(
+ "Failed communicating with card: \'{}\'",
+ ykpiv_strerror(res)
+ );
+ }
+ } else if sw != SW_SUCCESS {
+ if (*state).verbose != 0 {
+ eprintln!("Failed selecting mgmt application: {:04x}", sw);
+ }
+ res = ErrorKind::GenericError;
+ }
+
+ _ykpiv_end_transaction(state);
+ res
+}