From 7d40a9917e367f4fbbfcdb82a80a0248bc956d94 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sun, 17 Nov 2019 09:02:18 -0800 Subject: [PATCH] oxidize: Fix second pass of compile errors and commented-out code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit gets the Rust code to compile! 🎉 Additionally, it fixes all of the commented out code that was failing translation from C due to the use of unions, namely around the APDU messages. It does a fair amount of reformatting around branches, with the net result hopefully being something actually a bit closer to the C code, and a straightforward list of `if` statements. It also removes all of the remaining externs that aren't supposed to be externs, replacing them with a more straightforward usage of the module system. Finally it fixes all errors and warnings (relating to e.g. usage of uninitialized memory), in addition to most clippy lints! (some have been explicitly disabled) All that said, it still doesn't do anything: it needs to be wired up to a PCSC library first before that will be possible. But hey, it compiles! --- COPYING | 3 + src/apdu.rs | 66 + src/consts.rs | 218 +++ src/error.rs | 164 +- src/internal.rs | 718 +++---- src/lib.rs | 3190 +------------------------------ src/util.c | 4 +- src/util.rs | 4775 +++++++++++++++++++++-------------------------- src/ykpiv.c | 2 +- src/yubikey.rs | 2549 +++++++++++++++++++++++++ 10 files changed, 5366 insertions(+), 6323 deletions(-) create mode 100644 src/apdu.rs create mode 100644 src/consts.rs create mode 100644 src/yubikey.rs 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 +}