ykoath_protocol/
select.rs

1use crate::{Algorithm, Error, YubiKey};
2
3#[derive(Clone, Copy, Debug)]
4pub struct Response<'a> {
5    pub version: &'a [u8],
6    pub name: &'a [u8],
7    pub inner: Option<Inner<'a>>,
8}
9
10#[derive(Clone, Copy, Debug)]
11pub struct Inner<'a> {
12    pub challenge: &'a [u8],
13    pub algorithm: Algorithm,
14}
15
16impl YubiKey {
17    #[tracing::instrument(err, ret, skip(buf))]
18    pub fn select<'a>(&self, buf: &'a mut Vec<u8>) -> Result<Response<'a>, Error> {
19        // https://github.com/tokio-rs/tracing/issues/2796
20        #[allow(clippy::redundant_locals)]
21        let buf = buf;
22        buf.clear();
23        buf.extend_from_slice(&[0x00, 0xa4, 0x04, 0x00]);
24        buf.push(0x00);
25        buf.extend_from_slice(&[0xa0, 0x00, 0x00, 0x05, 0x27, 0x21, 0x01]);
26        let mut response = self.transmit(buf)?;
27        let (_, version) = Self::pop(&mut response, &[0x79])?;
28        let (_, name) = Self::pop(&mut response, &[0x71])?;
29        let inner = if response.is_empty() {
30            None
31        } else {
32            let (_, challenge) = Self::pop(&mut response, &[0x74])?;
33            let (_, algorithm) = Self::pop(&mut response, &[0x7b])?;
34            let algorithm = match algorithm {
35                [v] => Algorithm::try_from(*v)?,
36                _ => Err(Error::UnexpectedValue(algorithm.len().try_into()?))?,
37            };
38            Some(Inner {
39                challenge,
40                algorithm,
41            })
42        };
43        let response = Response {
44            version,
45            name,
46            inner,
47        };
48        Ok(response)
49    }
50}