Skip to main content

tecdsa_core/
ssid.rs

1//! Session identifiers (spec §10.4): always the first item of every transcript and RO.
2use alloc::vec::Vec;
3
4use crate::error::{Error, Result};
5
6/// Longest accepted `server_id` / `client_id`.
7pub const MAX_ID_LEN: usize = 256;
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10#[repr(u8)]
11pub enum SessionKind {
12    Keygen = 0x01,
13    Sign = 0x02,
14}
15
16/// `(sid, server_id, client_id, kind, tail)`, canonically encoded by [`Ssid::encode`].
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct Ssid {
19    sid: [u8; 32],
20    server_id: Vec<u8>,
21    client_id: Vec<u8>,
22    kind: SessionKind,
23    tail: Vec<u8>,
24}
25
26impl Ssid {
27    fn new(
28        sid: [u8; 32],
29        server_id: &[u8],
30        client_id: &[u8],
31        kind: SessionKind,
32        tail: Vec<u8>,
33    ) -> Result<Self> {
34        if server_id.len() > MAX_ID_LEN || client_id.len() > MAX_ID_LEN {
35            return Err(Error::OutOfRange);
36        }
37        Ok(Self {
38            sid,
39            server_id: server_id.to_vec(),
40            client_id: client_id.to_vec(),
41            kind,
42            tail,
43        })
44    }
45
46    /// Keygen: `kg_nonce` is the 32 random bytes the server puts into KgMsg1.
47    pub fn keygen(
48        sid: [u8; 32],
49        server_id: &[u8],
50        client_id: &[u8],
51        kg_nonce: &[u8; 32],
52    ) -> Result<Self> {
53        Self::new(
54            sid,
55            server_id,
56            client_id,
57            SessionKind::Keygen,
58            kg_nonce.to_vec(),
59        )
60    }
61
62    /// Sign: `key_id = SHA-256(X ‖ E)`, `digest = m`, the fresh `R₂` as the session id and the key
63    /// the signature is made under (`X`, or the HD-derived `X + δ·G`).
64    pub fn sign(
65        sid: [u8; 32],
66        server_id: &[u8],
67        client_id: &[u8],
68        key_id: &[u8; 32],
69        digest: &[u8; 32],
70        r2: &[u8; 33],
71        signing_key: &[u8; 33],
72    ) -> Result<Self> {
73        let mut tail = Vec::with_capacity(32 + 32 + 33 + 33);
74        tail.extend_from_slice(key_id);
75        tail.extend_from_slice(digest);
76        tail.extend_from_slice(r2);
77        tail.extend_from_slice(signing_key);
78        Self::new(sid, server_id, client_id, SessionKind::Sign, tail)
79    }
80
81    pub fn kind(&self) -> SessionKind {
82        self.kind
83    }
84    pub fn server_id(&self) -> &[u8] {
85        &self.server_id
86    }
87    pub fn client_id(&self) -> &[u8] {
88        &self.client_id
89    }
90
91    /// `sid ‖ u32be(len S) ‖ S ‖ u32be(len C) ‖ C ‖ kind ‖ tail`.
92    pub fn encode(&self) -> Vec<u8> {
93        let mut out = Vec::with_capacity(
94            32 + 8 + self.server_id.len() + self.client_id.len() + 1 + self.tail.len(),
95        );
96        out.extend_from_slice(&self.sid);
97        out.extend_from_slice(&(self.server_id.len() as u32).to_be_bytes());
98        out.extend_from_slice(&self.server_id);
99        out.extend_from_slice(&(self.client_id.len() as u32).to_be_bytes());
100        out.extend_from_slice(&self.client_id);
101        out.push(self.kind as u8);
102        out.extend_from_slice(&self.tail);
103        out
104    }
105}