diff --git a/src/constants.rs b/src/constants.rs index 81f6332..96bb90c 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -40,10 +40,13 @@ pub const CLOCK_FREQUENCY_KHZ: [u8; 4] = [0xfc, 0x0d, 0x00, 0x00]; // (not relevant, fixed fixed for legacy reasonse // Yubico: 307200 bps, gnuk: 9600 // pub const DATA_RATE_BPS: [u8; 4] = [0x00, 0xb0, 0x04, 0x00]; +// pub const DATA_RATE_BPS: [u8; 4] = [0x80, 0x25, 0x00, 0x00]; +// ICCD spec: "9600bps, not relevant, fixed for legacy reason" pub const DATA_RATE_BPS: [u8; 4] = [0x80, 0x25, 0x00, 0x00]; // 254 (as per ICCD spec) // Yubico: 2038, gnuk: 254 // pub const MAX_IFSD: [u8; 4] = [0xf6, 0x07, 0x00, 0x00]; +// ICCD spec: "For T = 1: 000000FEh" pub const MAX_IFSD: [u8; 4] = [0xfe, 0x00, 0x00, 0x00]; // "The value shall be between 261 + 10 and 65544 + 10 @@ -62,9 +65,11 @@ pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ // bcdCCID rev1.10 0x10, 0x01, // bMaxSlotIndex - NUM_SLOTS - 1, + // NUM_SLOTS - 1, + // "An USB-ICC is regarded as a single slot CCID." + 0x00, // bVoltageSupport (5.0V + 3.0V + 1.8V) - 0x07, + 0x01, // dwProtocols: T=1 only (0 = T=0, 3 = T0+T1) 0x02, 0x00, 0x00, 0x00, @@ -112,7 +117,10 @@ pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ // Auto baud rate change // Auto parameter negotiation made by CCID // Short and extended APDU level exchange - 0xFE, 0x00, 0x04, 0x00, + // 0xFE, 0x00, 0x04, 0x00, + // ICCD: lower word (=0840): only requests valid for USB-ICC + // upper word: 0000 = char level, 0002 = short APDU, 0004 = short+exteded APDU + 0x40, 0x08, 0x04, 0x00, // dwMaxCCIDMsgLen (3072) // gnuk: 271 @@ -128,6 +136,7 @@ pub const FUNCTIONAL_INTERFACE_DESCRIPTOR: [u8; 52] = [ // wlcdLayout (none) 0x00, 0x00, // bPinSupport + // ICCD: "No PIN pad, not relevant, fixed for legacy reasons" PIN_SUPPORT, // bMaxCCIDBusySlots MAX_BUSY_SLOTS, diff --git a/src/der.rs b/src/der.rs index 59eb6a8..1e8d698 100644 --- a/src/der.rs +++ b/src/der.rs @@ -118,6 +118,14 @@ impl> Der { self.extend_from_slice(value) } + /// Write an arbitrary tag-length-value with 2-byte tag + /// NB: everything in ISO 7816 is big-endian + pub fn raw_tlv2(&mut self, tag: u16, value: &[u8]) -> Result { + self.extend_from_slice(&tag.to_be_bytes())?; + self.write_length_field(value.len())?; + self.extend_from_slice(value) + } + ///// Write the given input as integer. ///// ///// Assumes `input` is the big-endian representation of a non-negative `Integer` diff --git a/src/pipe.rs b/src/pipe.rs index cf09ba8..cdcadf6 100644 --- a/src/pipe.rs +++ b/src/pipe.rs @@ -380,6 +380,24 @@ where let packet = DataBlock::new( self.seq, Chain::BeginsAndEnds, + + // PivApplet just uses: + // 3B 80 80 01 01 + // + // 3B 88 80 01 80 57 53 6F 6C 6F 20 42 83 + // T=0, T=1, card issuer's data "Solo B" + // https://smartcard-atr.apdu.fr/parse?ATR=3B+88+80+01+80+57+53+6F+6C+6F+20+42+83 + // + // T=0, T=1, command chaining/extended Lc+Le/no logical channels, card issuer's data "Solo B" + // 3B 8C 80 01 80 73 C0 21 C0 56 53 6F 6C 6F 20 42 D4 + // https://smartcard-atr.apdu.fr/parse?ATR=3B+8C+80+01+80+73+C0+21+C0+56+53+6F+6C+6F+20+42+D4 + b";\x8c\x80\x01\x80s\xc0!\xc0VSolo B\xd4" + // + // Not sure if we also need some TA/TB/TC data as in + // https://smartcard-atr.apdu.fr/parse?ATR=3B+F8+13+00+00+81+31+FE+15+59+75+62+69+6B+65+79+34+D4 + // At least TB(1) is deprecated, so it makes no sense + // Also, there TD(1) = 0x81 and TD(2) = 0x31 both refer to protocol T=1 which seems wrong + // don't remember where i got this from // &[0x3b, 0x8c,0x80,0x01], // "corrected"? @@ -400,37 +418,37 @@ where // ], // Yubikey FIDO+CCID // 3b:f8:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:34:d4 - &[ - // TS - 0x3b, - // TO = TA1, TB1, TB2, TB3 follow, 8 historical bytes - 0xf8, + // &[ + // // TS + // 0x3b, + // // TO = TA1, TB1, TB2, TB3 follow, 8 historical bytes + // 0xf8, - // TA1 = default clock (5MHz), default clock rate conversion (372)o - // But sets Di to 3 instead of default of 1 - 0x13, - // TB1 deprecated, should not transmit - 0x00, - // TC1 = "extra guard time", default of 0 - 0x00, + // // TA1 = default clock (5MHz), default clock rate conversion (372)o + // // But sets Di to 3 instead of default of 1 + // 0x13, + // // TB1 deprecated, should not transmit + // 0x00, + // // TC1 = "extra guard time", default of 0 + // 0x00, - // TD1 = (Y2, T) -> follows D2, T = 1 - 0x81, - // TD2 = (Y2, T) - 0x31, - // TA2 - 0xfe, - // TB2 - 0x15, - // T1 = first historical byte - 0x59, + // // TD1 = (Y2, T) -> follows D2, T = 1 + // 0x81, + // // TD2 = (Y2, T) + // 0x31, + // // TA2 + // 0xfe, + // // TB2 + // 0x15, + // // T1 = first historical byte + // 0x59, - // "SoloBee" - 0x53, 0x6F, 0x6C, 0x6F, 0x42, 0x65 ,0x65, + // // "SoloBee" + // 0x53, 0x6F, 0x6C, 0x6F, 0x42, 0x65 ,0x65, - // Checksum - 0x94, - ], + // // Checksum + // 0x94, + // ], // Yubikey NEO OTP+U2F+CCID // 3b:fc:13:00:00:81:31:fe:15:59:75:62:69:6b:65:79:4e:45:4f:72:33:e1 );