cryptoki/session/
session_info.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3//! Session info
4
5use crate::error::{Error, Result};
6use crate::slot::Slot;
7use bitflags::bitflags;
8use cryptoki_sys::*;
9use std::convert::{TryFrom, TryInto};
10use std::fmt::Debug;
11
12bitflags! {
13    /// Collection of flags defined for [`CK_SESSION_INFO`]
14    struct SessionInfoFlags: CK_FLAGS {
15        const RW_SESSION = CKF_RW_SESSION;
16        const SERIAL_SESSION = CKF_SERIAL_SESSION;
17    }
18}
19
20/// Provides information about a session
21#[derive(Copy, Clone, Debug)]
22pub struct SessionInfo {
23    slot_id: Slot,
24    state: SessionState,
25    flags: SessionInfoFlags,
26    device_error: u64,
27}
28
29impl SessionInfo {
30    /// ID of the slot that interfaces the token
31    pub fn slot_id(&self) -> Slot {
32        self.slot_id
33    }
34
35    /// The state of the session
36    pub fn session_state(&self) -> SessionState {
37        self.state
38    }
39
40    /// True if the session has R/W access to token objects, and false if access
41    /// is read-only
42    pub fn read_write(&self) -> bool {
43        self.flags.contains(SessionInfoFlags::RW_SESSION)
44    }
45
46    /// An error code defined by the cryptographic device (used for errors not
47    /// covered by PKCS#11)
48    pub fn device_error(&self) -> u64 {
49        self.device_error
50    }
51}
52
53#[doc(hidden)]
54impl TryFrom<CK_SESSION_INFO> for SessionInfo {
55    type Error = Error;
56    fn try_from(val: CK_SESSION_INFO) -> Result<Self> {
57        #[allow(clippy::useless_conversion)]
58        let device_error = val.ulDeviceError.into();
59        Ok(Self {
60            slot_id: Slot::new(val.slotID),
61            state: val.state.try_into()?,
62            flags: SessionInfoFlags::from_bits_truncate(val.flags),
63            device_error,
64        })
65    }
66}
67
68/// The current state of the session which describes access to token and session
69/// objects based on user type and login status
70#[derive(Debug, Copy, Clone, PartialEq, Eq)]
71pub enum SessionState {
72    /// The session has read-only access to public token objects and R/W access
73    /// to to public session objects
74    RoPublic,
75    /// A normal user has been authenticated to the token.
76    /// The session has read-only access to all public and private token objects
77    /// The session has R/W access to all public and private session objects
78    RoUser,
79    /// The session has read/write access to all public objects
80    RwPublic,
81    /// A normal user has been authenticated to the token.
82    /// The session has read/write access to all objects
83    RwUser,
84    /// A security officer (SO) user has been authenticated to the token.
85    /// The session has R/W access only to public token objects. The SO
86    /// can set the normal user's PIN.
87    RwSecurityOfficer,
88}
89
90#[doc(hidden)]
91impl TryFrom<CK_STATE> for SessionState {
92    type Error = Error;
93    fn try_from(value: CK_STATE) -> Result<Self> {
94        match value {
95            CKS_RO_PUBLIC_SESSION => Ok(Self::RoPublic),
96            CKS_RO_USER_FUNCTIONS => Ok(Self::RoUser),
97            CKS_RW_PUBLIC_SESSION => Ok(Self::RwPublic),
98            CKS_RW_USER_FUNCTIONS => Ok(Self::RwUser),
99            CKS_RW_SO_FUNCTIONS => Ok(Self::RwSecurityOfficer),
100            _ => Err(Error::InvalidValue),
101        }
102    }
103}
104
105#[cfg(test)]
106mod test {
107    use super::{SessionInfo, SessionInfoFlags, SessionState};
108    use crate::slot::Slot;
109
110    #[test]
111    fn debug_flags_all() {
112        let expected = "RW_SESSION | SERIAL_SESSION";
113        let all = SessionInfoFlags::all();
114        let observed = format!("{all:#?}");
115        assert_eq!(observed, expected);
116    }
117
118    #[test]
119    fn debug_info() {
120        let info = SessionInfo {
121            slot_id: Slot::new(100),
122            state: SessionState::RoPublic,
123            flags: SessionInfoFlags::empty(),
124            device_error: 0,
125        };
126        let expected = r#"SessionInfo {
127    slot_id: Slot {
128        slot_id: 100,
129    },
130    state: RoPublic,
131    flags: (empty),
132    device_error: 0,
133}"#;
134        let observed = format!("{info:#?}");
135        assert_eq!(observed, expected);
136    }
137}