dig_stun/credential/
request.rs1use crate::codec::{parse_binding_request, TransactionId, BINDING_REQUEST};
6use crate::credential::signature::StunSigner;
7use crate::credential::wire::{
8 is_valid_signature_der_len, is_valid_spki_der, write_attr, write_header, CredentialError,
9 ATTR_DIG_IDENTITY, ATTR_DIG_SIGNATURE, ATTR_NONCE, CREDENTIAL_VERSION,
10};
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum RequestKind<'a> {
19 Bare,
21 Identity {
24 spki: &'a [u8],
26 },
27 Signed {
29 spki: &'a [u8],
31 nonce: &'a [u8],
34 signature: &'a [u8],
36 },
37}
38
39pub fn classify_request(
51 datagram: &[u8],
52) -> Result<(TransactionId, RequestKind<'_>), CredentialError> {
53 let txid = parse_binding_request(datagram)?;
54 let msg_len = u16::from_be_bytes([datagram[2], datagram[3]]) as usize;
56 let area = &datagram[20..20 + msg_len];
57 let kind = classify_attrs(area)?;
58 Ok((txid, kind))
59}
60
61fn classify_attrs(area: &[u8]) -> Result<RequestKind<'_>, CredentialError> {
62 let mut identity: Option<&[u8]> = None;
63 let mut nonce: Option<&[u8]> = None;
64 let mut signature: Option<&[u8]> = None;
65 let mut signature_seen = false;
66
67 let mut off = 0usize;
68 while off + 4 <= area.len() {
69 if signature_seen {
73 return Err(CredentialError::Malformed);
74 }
75
76 let attr_type = u16::from_be_bytes([area[off], area[off + 1]]);
77 let attr_len = u16::from_be_bytes([area[off + 2], area[off + 3]]) as usize;
78 let val_start = off + 4;
79 let val_end = val_start + attr_len;
80 if val_end > area.len() {
81 return Err(CredentialError::Malformed);
82 }
83 let value = &area[val_start..val_end];
84
85 match attr_type {
86 ATTR_DIG_IDENTITY => {
87 if identity.is_some() {
88 return Err(CredentialError::Malformed);
89 }
90 if value.len() != 1 + crate::credential::wire::P256_SPKI_LEN
91 || value[0] != CREDENTIAL_VERSION
92 || !is_valid_spki_der(&value[1..])
93 {
94 return Err(CredentialError::Malformed);
95 }
96 identity = Some(&value[1..]);
97 }
98 ATTR_NONCE => {
99 if nonce.is_some() {
100 return Err(CredentialError::Malformed);
101 }
102 nonce = Some(value);
103 }
104 ATTR_DIG_SIGNATURE => {
105 if value.is_empty()
106 || value[0] != CREDENTIAL_VERSION
107 || !is_valid_signature_der_len(&value[1..])
108 {
109 return Err(CredentialError::Malformed);
110 }
111 signature = Some(&value[1..]);
112 signature_seen = true;
113 }
114 _ => {} }
116
117 off = val_end + ((4 - (attr_len % 4)) % 4);
118 }
119
120 match (identity, nonce, signature) {
121 (None, None, None) => Ok(RequestKind::Bare),
122 (Some(spki), None, None) => Ok(RequestKind::Identity { spki }),
123 (Some(spki), Some(nonce), Some(signature)) => Ok(RequestKind::Signed {
124 spki,
125 nonce,
126 signature,
127 }),
128 _ => Err(CredentialError::Malformed), }
130}
131
132pub fn encode_identity_request(txid: &TransactionId, spki_der: &[u8]) -> Vec<u8> {
136 debug_assert!(
137 is_valid_spki_der(spki_der),
138 "encode_identity_request requires a valid 91-byte P-256 SPKI DER"
139 );
140
141 let mut identity_value = Vec::with_capacity(1 + spki_der.len());
142 identity_value.push(CREDENTIAL_VERSION);
143 identity_value.extend_from_slice(spki_der);
144
145 let mut attrs = Vec::new();
146 write_attr(&mut attrs, ATTR_DIG_IDENTITY, &identity_value);
147
148 let mut msg = Vec::with_capacity(20 + attrs.len());
149 write_header(&mut msg, BINDING_REQUEST, attrs.len() as u16, txid);
150 msg.extend_from_slice(&attrs);
151 msg
152}
153
154pub fn encode_signed_request(
159 txid: &TransactionId,
160 nonce_attr_value: &[u8],
161 signer: &dyn StunSigner,
162) -> Vec<u8> {
163 let spki = signer.spki_der();
164 let message = crate::credential::signature::signing_message(txid, nonce_attr_value, spki);
165 let sig_der = signer.sign(&message);
166
167 let mut identity_value = Vec::with_capacity(1 + spki.len());
168 identity_value.push(CREDENTIAL_VERSION);
169 identity_value.extend_from_slice(spki);
170
171 let mut signature_value = Vec::with_capacity(1 + sig_der.len());
172 signature_value.push(CREDENTIAL_VERSION);
173 signature_value.extend_from_slice(&sig_der);
174
175 let mut attrs = Vec::new();
176 write_attr(&mut attrs, ATTR_DIG_IDENTITY, &identity_value);
177 write_attr(&mut attrs, ATTR_NONCE, nonce_attr_value);
178 write_attr(&mut attrs, ATTR_DIG_SIGNATURE, &signature_value);
179
180 let mut msg = Vec::with_capacity(20 + attrs.len());
181 write_header(&mut msg, BINDING_REQUEST, attrs.len() as u16, txid);
182 msg.extend_from_slice(&attrs);
183 msg
184}