1mod plain_secret;
24mod revision;
25#[cfg(test)]
26mod tests;
27
28use log::{debug, error};
29use nuts_backend::Backend;
30use openssl::error::ErrorStack;
31use plain_secret::PlainSecret;
32use std::fmt;
33use std::ops::DerefMut;
34use thiserror::Error;
35
36use crate::buffer::{BufferError, ToBuffer};
37use crate::cipher::{Cipher, CipherContext, CipherError};
38use crate::header::revision::{Data, Revision};
39use crate::kdf::{Kdf, KdfError};
40use crate::migrate::{MigrationError, Migrator};
41use crate::options::CreateOptions;
42use crate::ossl;
43use crate::password::{PasswordError, PasswordStore};
44use crate::svec::SecureVec;
45
46pub const LATEST_REVISION: u32 = 2;
47
48#[derive(Debug, Error)]
50pub enum HeaderError {
51 #[error(transparent)]
53 Cipher(#[from] CipherError),
54
55 #[error(transparent)]
57 Kdf(#[from] KdfError),
58
59 #[error(transparent)]
61 Password(#[from] PasswordError),
62
63 #[error("the password is wrong")]
65 WrongPassword,
66
67 #[error("invalid header revision, expected {0} but got {1}")]
69 InvalidRevision(u32, u32),
70
71 #[error("unknown header revision {0}")]
73 UnknownRevision(u32),
74
75 #[error("invalid header")]
77 InvalidHeader,
78
79 #[error("invalid sid")]
81 InvalidSid,
82
83 #[error("unexpected sid, expected {} but got {}",
85 .expected.map_or_else(|| "none".to_string(), |n| n.to_string()),
86 .got.map_or_else(|| "none".to_string(), |n| n.to_string()))]
87 UnexpectedSid {
88 expected: Option<u32>,
89 got: Option<u32>,
90 },
91
92 #[error("invalid settings")]
94 InvalidSettings,
95
96 #[error("invalid top-id")]
98 InvalidTopId,
99
100 #[error(transparent)]
102 Buffer(#[from] BufferError),
103
104 #[error(transparent)]
106 OpenSSL(#[from] ErrorStack),
107
108 #[error(transparent)]
110 Migration(#[from] MigrationError),
111}
112
113pub struct Header<'a, B: Backend> {
114 revision: u32,
115 migrator: Migrator<'a>,
116 cipher: Cipher,
117 kdf: Kdf,
118 data: PlainSecret<B>,
119}
120
121impl<'a, B: Backend> Header<'a, B> {
122 pub fn create(
123 options: &CreateOptions,
124 settings: B::Settings,
125 ) -> Result<Header<'a, B>, HeaderError> {
126 let cipher = options.cipher;
127 let mut key = vec![0; cipher.key_len()];
128 let mut iv = vec![0; cipher.iv_len()];
129
130 ossl::rand_bytes(&mut key)?;
131 ossl::rand_bytes(&mut iv)?;
132
133 let kdf = options.kdf.build()?;
134 let (revision, plain_secret) = PlainSecret::create_latest(key.into(), iv.into(), settings)?;
135
136 Ok(Header {
137 revision,
138 migrator: Migrator::default(),
139 cipher,
140 kdf,
141 data: plain_secret,
142 })
143 }
144
145 pub fn read(
146 buf: &[u8],
147 migrator: Migrator<'a>,
148 store: &mut PasswordStore,
149 ) -> Result<Header<'a, B>, HeaderError> {
150 match Revision::get_from_buffer(&mut &buf[..])? {
151 Revision::Rev0(data) => Self::read_rev0(data, migrator, store),
152 Revision::Rev1(data) => Self::read_rev1(data, migrator, store),
153 Revision::Rev2(data) => Self::read_rev2(data, migrator, store),
154 }
155 }
156
157 fn read_rev0(
158 data: Data,
159 migrator: Migrator<'a>,
160 store: &mut PasswordStore,
161 ) -> Result<Header<'a, B>, HeaderError> {
162 let key = Self::create_key(data.cipher, &data.kdf, store)?;
163 let mut ctx = Self::prepare_cipher_ctx(data.cipher, &data.secret);
164
165 let pbuf = ctx.decrypt(&key, &data.iv)?;
166 let plain_secret = PlainSecret::from_buffer_rev0(&mut &pbuf[..])?;
167
168 Ok(Header {
169 revision: 0,
170 migrator,
171 cipher: data.cipher,
172 kdf: data.kdf,
173 data: plain_secret,
174 })
175 }
176
177 fn read_rev1(
178 data: Data,
179 migrator: Migrator<'a>,
180 store: &mut PasswordStore,
181 ) -> Result<Header<'a, B>, HeaderError> {
182 let key = Self::create_key(data.cipher, &data.kdf, store)?;
183 let mut ctx = Self::prepare_cipher_ctx(data.cipher, &data.secret);
184
185 let pbuf = ctx.decrypt(&key, &data.iv)?;
186 let plain_secret = PlainSecret::from_buffer_rev1(&mut &pbuf[..])?;
187
188 Ok(Header {
189 revision: 1,
190 migrator,
191 cipher: data.cipher,
192 kdf: data.kdf,
193 data: plain_secret,
194 })
195 }
196
197 fn read_rev2(
198 data: Data,
199 migrator: Migrator<'a>,
200 store: &mut PasswordStore,
201 ) -> Result<Header<'a, B>, HeaderError> {
202 let key = Self::create_key(data.cipher, &data.kdf, store)?;
203 let mut ctx = Self::prepare_cipher_ctx(data.cipher, &data.secret);
204
205 let pbuf = ctx.decrypt(&key, &data.iv)?;
206 let plain_secret = PlainSecret::from_buffer_rev2(&mut &pbuf[..])?;
207
208 Ok(Header {
209 revision: 2,
210 migrator,
211 cipher: data.cipher,
212 kdf: data.kdf,
213 data: plain_secret,
214 })
215 }
216
217 pub fn write(&self, buf: &mut [u8], store: &mut PasswordStore) -> Result<(), HeaderError> {
218 let mut iv = vec![0; self.cipher.iv_len()];
219 ossl::rand_bytes(&mut iv)?;
220
221 let mut pbuf: SecureVec = vec![].into();
222 self.data.to_buffer(pbuf.deref_mut())?;
223
224 let key = Self::create_key(self.cipher, &self.kdf, store)?;
225 let mut ctx = Self::prepare_cipher_ctx(self.cipher, &pbuf);
226
227 let cbuf = ctx.encrypt(&key, &iv)?;
228 let secret = cbuf.to_vec();
229
230 let rev = match self.data {
231 PlainSecret::Rev0(_) => Revision::new_rev0(self.cipher, iv, self.kdf.clone(), secret),
232 PlainSecret::Rev1(_) => Revision::new_rev1(self.cipher, iv, self.kdf.clone(), secret),
233 PlainSecret::Rev2(_) => Revision::new_rev2(self.cipher, iv, self.kdf.clone(), secret),
234 };
235
236 rev.put_into_buffer(&mut &mut buf[..])
237 }
238
239 pub fn migrate(&mut self) -> Result<(), HeaderError> {
240 if let PlainSecret::Rev0(rev0) = &mut self.data {
241 rev0.migrate(&self.migrator)
242 } else {
243 Ok(())
244 }
245 }
246
247 pub fn revision(&self) -> u32 {
248 self.revision
249 }
250
251 pub fn latest_revision_or_err(&self) -> Result<(), HeaderError> {
252 if self.revision == LATEST_REVISION {
253 Ok(())
254 } else {
255 Err(HeaderError::InvalidRevision(LATEST_REVISION, self.revision))
256 }
257 }
258
259 pub fn cipher(&self) -> Cipher {
260 self.cipher
261 }
262
263 pub fn kdf(&self) -> &Kdf {
264 &self.kdf
265 }
266
267 pub fn set_kdf(&mut self, kdf: Kdf) -> bool {
268 if self.cipher != Cipher::None && kdf != Kdf::None {
269 self.kdf = kdf;
270 true
271 } else {
272 false
273 }
274 }
275
276 pub fn settings(&self) -> &B::Settings {
277 match &self.data {
278 PlainSecret::Rev0(rev0) => &rev0.settings,
279 PlainSecret::Rev1(rev1) => &rev1.settings,
280 PlainSecret::Rev2(rev2) => &rev2.settings,
281 }
282 }
283
284 pub fn key(&self) -> &[u8] {
285 match &self.data {
286 PlainSecret::Rev0(rev0) => &rev0.key,
287 PlainSecret::Rev1(rev1) => &rev1.key,
288 PlainSecret::Rev2(rev2) => &rev2.key,
289 }
290 }
291
292 pub fn iv(&self) -> &[u8] {
293 match &self.data {
294 PlainSecret::Rev0(rev0) => &rev0.iv,
295 PlainSecret::Rev1(rev1) => &rev1.iv,
296 PlainSecret::Rev2(rev2) => &rev2.iv,
297 }
298 }
299
300 pub fn accept_sid_for_create(&self) -> Result<(), HeaderError> {
301 let sid_opt = match &self.data {
302 PlainSecret::Rev0(rev0) => rev0.sid,
303 PlainSecret::Rev1(_) => None,
304 PlainSecret::Rev2(rev2) => rev2.sid,
305 };
306
307 if sid_opt.is_none() {
308 Ok(())
309 } else {
310 Err(HeaderError::UnexpectedSid {
311 expected: None,
312 got: sid_opt,
313 })
314 }
315 }
316
317 pub fn accept_sid_for_open(&self, sid: u32) -> Result<(), HeaderError> {
318 let accecpt = |header_sid| match header_sid {
319 Some(hsid) if hsid == sid => {
320 debug!("sid {} match", sid);
321
322 Ok(())
323 }
324 _ => {
325 error!("sid mismatch, sid: {}, header sid: {:?}", sid, header_sid);
326
327 Err(HeaderError::UnexpectedSid {
328 expected: Some(sid),
329 got: header_sid,
330 })
331 }
332 };
333
334 match &self.data {
335 PlainSecret::Rev0(rev0) => accecpt(rev0.sid),
336 PlainSecret::Rev1(_) => {
337 debug!("rev1 has no sid, say ok");
343
344 Ok(())
345 }
346 PlainSecret::Rev2(rev2) => accecpt(rev2.sid),
347 }
348 }
349
350 pub fn set_sid(&mut self, sid: u32) -> Result<(), HeaderError> {
351 match &mut self.data {
352 PlainSecret::Rev0(_) => panic!("storing a sid into a rev0 header is not supported"),
353 PlainSecret::Rev1(_) => panic!("storing a sid into a rev1 header is not supported"),
354 PlainSecret::Rev2(rev2) => {
355 if sid > 0 {
356 rev2.sid = Some(sid);
357 Ok(())
358 } else {
359 Err(HeaderError::InvalidSid)
360 }
361 }
362 }
363 }
364
365 pub fn top_id(&self) -> Option<&B::Id> {
366 match &self.data {
367 PlainSecret::Rev0(rev0) => rev0.top_id.as_ref(),
368 PlainSecret::Rev1(rev1) => rev1.top_id.as_ref(),
369 PlainSecret::Rev2(rev2) => rev2.top_id.as_ref(),
370 }
371 }
372
373 pub fn set_top_id(&mut self, id: B::Id) {
374 match &mut self.data {
375 PlainSecret::Rev0(_) => panic!("storing a top-id into a rev0 header is not supported"),
376 PlainSecret::Rev1(_) => panic!("storing a top-id into a rev1 header is not supported"),
377 PlainSecret::Rev2(rev2) => rev2.top_id = Some(id),
378 }
379 }
380
381 pub fn set_migrator(&mut self, migrator: Migrator<'a>) {
382 self.migrator = migrator;
383 }
384
385 pub fn convert_to_latest(&mut self, sid: u32) -> bool {
386 self.data.convert_to_latest(sid)
387 }
388
389 fn prepare_cipher_ctx(cipher: Cipher, input: &[u8]) -> CipherContext {
390 let mut ctx = CipherContext::new(cipher);
391
392 ctx.copy_from_slice(input.len(), input);
393
394 ctx
395 }
396
397 fn create_key(
398 cipher: Cipher,
399 kdf: &Kdf,
400 store: &mut PasswordStore,
401 ) -> Result<SecureVec, HeaderError> {
402 if cipher.key_len() > 0 {
403 let password = store.value()?;
404 Ok(kdf.create_key(password, cipher.key_len())?)
405 } else {
406 Ok(vec![].into())
407 }
408 }
409}
410
411impl<'a, B: Backend> fmt::Debug for Header<'a, B> {
412 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
413 fmt.debug_struct("Header")
414 .field("revision", &self.revision)
415 .field("migrator", &self.migrator)
416 .field("cipher", &self.cipher)
417 .field("kdf", &self.kdf)
418 .field("data", &self.data)
419 .finish()
420 }
421}