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 +}