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