1use std::{
4 fmt,
5 time::{SystemTime, UNIX_EPOCH},
6};
7
8use hkdf::Hkdf;
9use hpke::{
10 Deserializable, Kem as KemTrait, OpModeR, OpModeS, PskBundle, Serializable,
11 aead::{AeadCtxR, AeadCtxS, AeadTag, ChaCha20Poly1305 as HpkeChaCha20Poly1305},
12 inout::InOutBuf,
13 kdf::HkdfSha256,
14 kem::X25519HkdfSha256,
15 setup_receiver, setup_sender_with_rng,
16};
17use rand_chacha::ChaCha20Rng;
18use rand_core::SeedableRng;
19use sha2::{Digest, Sha256};
20use zeroize::Zeroizing;
21
22use crate::{
23 CLOCK_SKEW_SECS, EntropySource, Error, HARD_MAX_ID_LEN, Limits, Method, REQUEST_LIFETIME_SECS,
24 SystemEntropy,
25 codec::{
26 ENC_LEN, REQUEST_FIXED_LEN, RESPONSE_NONCE_LEN, TAG_LEN, encode_request_header,
27 parse_stream_start, stream_start_length,
28 },
29 compression,
30 message::{self, HeaderField, Request, RequestHead, Response},
31 response::{ResponseMode, ResponseOpener, ResponseRecord, ResponseSealer},
32};
33
34type Kem = X25519HkdfSha256;
35type Kdf = HkdfSha256;
36type HpkeAead = HpkeChaCha20Poly1305;
37type RecipientContext = AeadCtxR<HpkeAead, Kdf, Kem>;
38type SenderContext = AeadCtxS<HpkeAead, Kdf, Kem>;
39
40const STREAM_REQUEST_INFO_LABEL: &[u8] = b"message/hpke-http request\0v3\0";
41const STREAM_REQUEST_AAD_LABEL: &[u8] = b"hpke-http/3 request record\0";
42const STREAM_START: u8 = 1;
43const STREAM_DATA: u8 = 2;
44const STREAM_END: u8 = 3;
45pub const STREAM_DATA_LEN: usize = 64 * 1024;
47const STREAM_MAX_DATA_RECORDS: u64 = 1_048_576;
49const RESPONSE_EXPORT_LABEL: &[u8] = b"message/hpke-http response\0v3";
50const REPLAY_LABEL: &[u8] = b"hpke-http/replay\0v3\0";
51const RESPONSE_KEY_INFO: &[u8] = b"hpke-http/3 response key";
52const RESPONSE_NONCE_INFO: &[u8] = b"hpke-http/3 response nonce";
53const RESPONSE_SECRET_LEN: usize = 32;
54const RESPONSE_KEY_LEN: usize = 32;
55const AEAD_NONCE_LEN: usize = 12;
56const MIN_PSK_LEN: usize = 32;
57pub(crate) type ResponseKey = Zeroizing<[u8; RESPONSE_KEY_LEN]>;
58pub(crate) type ResponseNonce = Zeroizing<[u8; AEAD_NONCE_LEN]>;
59
60pub struct KeyPair {
62 private_key: Zeroizing<Vec<u8>>,
63 public_key: Vec<u8>,
64}
65
66impl fmt::Debug for KeyPair {
67 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
68 formatter
69 .debug_struct("KeyPair")
70 .field("private_key", &"[REDACTED]")
71 .field("public_key_len", &self.public_key.len())
72 .finish()
73 }
74}
75
76impl KeyPair {
77 #[must_use]
79 pub fn into_parts(self) -> (Zeroizing<Vec<u8>>, Vec<u8>) {
80 (self.private_key, self.public_key)
81 }
82
83 #[must_use]
85 pub fn public_key(&self) -> &[u8] {
86 &self.public_key
87 }
88}
89
90pub fn generate_key_pair() -> Result<KeyPair, Error> {
96 generate_key_pair_with_entropy(&mut SystemEntropy)
97}
98
99pub fn generate_key_pair_with_entropy(entropy: &mut impl EntropySource) -> Result<KeyPair, Error> {
105 let mut input_key_material = Zeroizing::new([0_u8; 32]);
106 entropy.fill(input_key_material.as_mut())?;
107 let (private_key, public_key) = Kem::derive_keypair(input_key_material.as_ref());
108 Ok(KeyPair {
109 private_key: Zeroizing::new(private_key.to_bytes().to_vec()),
110 public_key: public_key.to_bytes().to_vec(),
111 })
112}
113
114#[must_use]
116pub struct ProtectedRequest {
117 envelope: Vec<u8>,
118 response_token: ResponseToken,
119}
120
121impl fmt::Debug for ProtectedRequest {
122 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
123 formatter
124 .debug_struct("ProtectedRequest")
125 .field("envelope_len", &self.envelope.len())
126 .field("response_token", &self.response_token)
127 .finish()
128 }
129}
130
131impl ProtectedRequest {
132 #[must_use]
134 pub fn envelope(&self) -> &[u8] {
135 &self.envelope
136 }
137
138 pub fn into_parts(self) -> (Vec<u8>, ResponseToken) {
140 (self.envelope, self.response_token)
141 }
142}
143
144pub struct Client {
146 recipient_public_key: <Kem as KemTrait>::PublicKey,
147 recipient_key_id: Vec<u8>,
148 psk: Zeroizing<Vec<u8>>,
149 psk_id: Vec<u8>,
150 limits: Limits,
151}
152
153impl fmt::Debug for Client {
154 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
155 formatter
156 .debug_struct("Client")
157 .field("recipient_key_id_len", &self.recipient_key_id.len())
158 .field("psk", &"[REDACTED]")
159 .field("psk_id_len", &self.psk_id.len())
160 .field("limits", &self.limits)
161 .finish_non_exhaustive()
162 }
163}
164
165impl Client {
166 pub fn new(
173 recipient_public_key: &[u8],
174 recipient_key_id: Vec<u8>,
175 psk: Vec<u8>,
176 psk_id: Vec<u8>,
177 limits: Limits,
178 ) -> Result<Self, Error> {
179 let psk = Zeroizing::new(psk);
180 validate_id(&recipient_key_id)?;
181 validate_credential(psk.as_slice(), &psk_id)?;
182 let limits = limits.validate()?;
183 let recipient_public_key = <Kem as KemTrait>::PublicKey::from_bytes(recipient_public_key)
184 .map_err(|_| Error::InvalidConfiguration)?;
185 Ok(Self {
186 recipient_public_key,
187 recipient_key_id,
188 psk,
189 psk_id,
190 limits,
191 })
192 }
193
194 pub fn protect(&self, request: &Request) -> Result<ProtectedRequest, Error> {
201 self.protect_at_with_entropy(request, unix_time_seconds()?, &mut SystemEntropy)
202 }
203
204 pub fn protect_at(
213 &self,
214 request: &Request,
215 now_unix_s: u64,
216 ) -> Result<ProtectedRequest, Error> {
217 self.protect_at_with_entropy(request, now_unix_s, &mut SystemEntropy)
218 }
219
220 pub fn protect_with_entropy(
227 &self,
228 request: &Request,
229 entropy: &mut impl EntropySource,
230 ) -> Result<ProtectedRequest, Error> {
231 self.protect_at_with_entropy(request, unix_time_seconds()?, entropy)
232 }
233
234 pub fn protect_at_with_entropy(
241 &self,
242 request: &Request,
243 now_unix_s: u64,
244 entropy: &mut impl EntropySource,
245 ) -> Result<ProtectedRequest, Error> {
246 message::validate_request(request, self.limits)?;
247 let head = RequestHead {
248 method: request.method,
249 authority: request.authority.clone(),
250 path: request.path.clone(),
251 headers: request.headers.clone(),
252 };
253 let (mut writer, mut envelope) =
254 self.begin_stream_at_with_entropy(&head, now_unix_s, entropy)?;
255 let mut remaining = request.body.as_slice();
256 while !remaining.is_empty() {
257 let (used, record) = writer.push(remaining)?;
258 remaining = &remaining[used..];
259 if let Some(record) = record {
260 envelope.extend_from_slice(&record);
261 }
262 }
263 let (end, response_token) = writer.finish()?;
264 envelope.extend_from_slice(&end);
265 Ok(ProtectedRequest {
266 envelope,
267 response_token,
268 })
269 }
270}
271
272#[derive(Clone, Debug, Eq, PartialEq)]
274pub struct CredentialRequest {
275 pub psk_id: Vec<u8>,
277}
278
279#[must_use]
281pub struct PreparsedRequest {
282 pub credential: CredentialRequest,
284 pub token: StartToken,
286}
287
288#[must_use]
290pub struct StartToken {
291 envelope: Vec<u8>,
292}
293
294impl fmt::Debug for StartToken {
295 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
296 formatter
297 .debug_struct("StartToken")
298 .field("envelope_len", &self.envelope.len())
299 .finish()
300 }
301}
302
303#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
305pub struct ReplayRequest {
306 pub id: [u8; 32],
308 pub retain_until_exclusive: u64,
310}
311
312impl ReplayRequest {
313 #[must_use]
315 pub const fn decision(self, admitted: bool) -> ReplayDecision {
316 ReplayDecision {
317 id: self.id,
318 retain_until_exclusive: self.retain_until_exclusive,
319 admitted,
320 }
321 }
322}
323
324#[derive(Clone, Copy, Debug, Eq, PartialEq)]
326pub struct ReplayDecision {
327 id: [u8; 32],
328 retain_until_exclusive: u64,
329 admitted: bool,
330}
331
332fn check_replay_decision(
333 replay_id: [u8; 32],
334 retain_until_exclusive: u64,
335 decision: ReplayDecision,
336 now_unix_s: u64,
337) -> Result<(), Error> {
338 if replay_id != decision.id || retain_until_exclusive != decision.retain_until_exclusive {
339 return Err(Error::ReplayDecisionMismatch);
340 }
341 if !decision.admitted {
342 return Err(Error::ReplayRejected);
343 }
344 if now_unix_s >= retain_until_exclusive {
345 return Err(Error::InvalidRequestTime);
346 }
347 Ok(())
348}
349
350#[must_use]
352pub struct AuthenticatedRequest {
353 pub replay: ReplayRequest,
355 pub token: ReplayToken,
357}
358
359#[must_use]
361pub struct ReplayToken {
362 replay_id: [u8; 32],
363 retain_until_exclusive: u64,
364 request: Request,
365 response: ResponseCapability,
366}
367
368impl fmt::Debug for ReplayToken {
369 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
370 formatter
371 .debug_struct("ReplayToken")
372 .field("replay_id", &self.replay_id)
373 .field("retain_until_exclusive", &self.retain_until_exclusive)
374 .field("request", &"[REDACTED]")
375 .finish_non_exhaustive()
376 }
377}
378
379impl ReplayToken {
380 pub fn admit(self, decision: ReplayDecision) -> Result<OpenedRequest, Error> {
391 self.admit_at(decision, unix_time_seconds()?)
392 }
393
394 pub fn admit_at(
404 self,
405 decision: ReplayDecision,
406 now_unix_s: u64,
407 ) -> Result<OpenedRequest, Error> {
408 check_replay_decision(
409 self.replay_id,
410 self.retain_until_exclusive,
411 decision,
412 now_unix_s,
413 )?;
414 Ok(OpenedRequest {
415 request: self.request,
416 response: self.response,
417 })
418 }
419}
420
421#[must_use]
423pub struct OpenedRequest {
424 pub request: Request,
427 pub response: ResponseCapability,
429}
430
431pub struct Server {
433 recipient_private_key: <Kem as KemTrait>::PrivateKey,
434 recipient_key_id: Vec<u8>,
435 accepted_keys: Vec<(Vec<u8>, <Kem as KemTrait>::PrivateKey)>,
436 limits: Limits,
437}
438
439impl fmt::Debug for Server {
440 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
441 formatter
442 .debug_struct("Server")
443 .field("recipient_private_key", &"[REDACTED]")
444 .field("recipient_key_id_len", &self.recipient_key_id.len())
445 .field("accepted_key_count", &self.accepted_keys.len())
446 .field("limits", &self.limits)
447 .finish()
448 }
449}
450
451impl Server {
452 pub fn new(
459 recipient_private_key: &[u8],
460 recipient_key_id: Vec<u8>,
461 limits: Limits,
462 ) -> Result<Self, Error> {
463 Self::with_accepted_keys(recipient_private_key, recipient_key_id, Vec::new(), limits)
464 }
465
466 pub fn with_accepted_keys(
475 recipient_private_key: &[u8],
476 recipient_key_id: Vec<u8>,
477 accepted: Vec<(Vec<u8>, Vec<u8>)>,
478 limits: Limits,
479 ) -> Result<Self, Error> {
480 validate_id(&recipient_key_id)?;
481 let limits = limits.validate()?;
482 let recipient_private_key =
483 <Kem as KemTrait>::PrivateKey::from_bytes(recipient_private_key)
484 .map_err(|_| Error::InvalidConfiguration)?;
485 let accepted = accepted
486 .into_iter()
487 .map(|(private_key, key_id)| (Zeroizing::new(private_key), key_id))
488 .collect::<Vec<_>>();
489 let mut accepted_keys = Vec::with_capacity(accepted.len());
490 for (private_key, key_id) in accepted {
491 validate_id(&key_id)?;
492 if key_id == recipient_key_id || accepted_keys.iter().any(|(id, _)| *id == key_id) {
493 return Err(Error::InvalidConfiguration);
494 }
495 let private_key = <Kem as KemTrait>::PrivateKey::from_bytes(&private_key)
496 .map_err(|_| Error::InvalidConfiguration)?;
497 accepted_keys.push((key_id, private_key));
498 }
499 Ok(Self {
500 recipient_private_key,
501 recipient_key_id,
502 accepted_keys,
503 limits,
504 })
505 }
506
507 fn private_key_for(&self, key_id: &[u8]) -> Result<&<Kem as KemTrait>::PrivateKey, Error> {
508 if key_id == self.recipient_key_id {
509 return Ok(&self.recipient_private_key);
510 }
511 self.accepted_keys
512 .iter()
513 .find(|(id, _)| id == key_id)
514 .map(|(_, private_key)| private_key)
515 .ok_or(Error::UnknownRecipientKey)
516 }
517
518 #[must_use]
520 pub fn public_key(&self) -> Vec<u8> {
521 Kem::sk_to_pk(&self.recipient_private_key)
522 .to_bytes()
523 .to_vec()
524 }
525
526 pub fn max_complete_envelope_len(&self) -> Result<usize, Error> {
534 max_complete_envelope_len(self.limits)
535 }
536
537 pub fn preparse(&self, envelope: &[u8]) -> Result<PreparsedRequest, Error> {
545 let credential = self.preparse_credential(envelope)?;
546 Ok(PreparsedRequest {
547 credential,
548 token: StartToken {
549 envelope: envelope.to_vec(),
550 },
551 })
552 }
553
554 pub fn preparse_owned(&self, envelope: Vec<u8>) -> Result<PreparsedRequest, Error> {
565 let credential = self.preparse_credential(&envelope)?;
566 Ok(PreparsedRequest {
567 credential,
568 token: StartToken { envelope },
569 })
570 }
571
572 fn preparse_credential(&self, envelope: &[u8]) -> Result<CredentialRequest, Error> {
573 if envelope.len() > self.max_complete_envelope_len()? {
574 return Err(Error::LimitExceeded);
575 }
576 let first_len = self
577 .stream_start_length(envelope)?
578 .ok_or(Error::MalformedEnvelope)?;
579 if first_len > envelope.len() {
580 return Err(Error::MalformedEnvelope);
581 }
582 let parsed = parse_stream_start(
583 &envelope[..first_len],
584 max_stream_start_ciphertext(self.limits),
585 )?;
586 self.private_key_for(parsed.key_id)?;
587 Ok(CredentialRequest {
588 psk_id: parsed.psk_id.to_vec(),
589 })
590 }
591
592 pub fn authenticate(
601 &self,
602 token: StartToken,
603 psk: &[u8],
604 ) -> Result<AuthenticatedRequest, Error> {
605 self.authenticate_at(token, psk, unix_time_seconds()?)
606 }
607
608 pub fn authenticate_at(
614 &self,
615 token: StartToken,
616 psk: &[u8],
617 now_unix_s: u64,
618 ) -> Result<AuthenticatedRequest, Error> {
619 let StartToken { envelope } = token;
620 let first_len = self
621 .stream_start_length(&envelope)?
622 .ok_or(Error::MalformedEnvelope)?;
623 if first_len > envelope.len() {
624 return Err(Error::MalformedEnvelope);
625 }
626 let authenticated = self.authenticate_stream_at(
627 StreamStartToken {
628 first: envelope[..first_len].to_vec(),
629 },
630 psk,
631 now_unix_s,
632 )?;
633 let replay = authenticated.replay;
634 let StreamReplayToken {
635 head, mut reader, ..
636 } = authenticated.token;
637 let mut body = Vec::new();
638 let mut remaining = &envelope[first_len..];
639 while !remaining.is_empty() {
640 let (used, record) = reader.feed(remaining)?;
641 remaining = &remaining[used..];
642 if let Some(StreamRequestRecord::Data(part)) = record {
643 if part.len() > self.limits.max_body_len.saturating_sub(body.len()) {
644 return Err(Error::LimitExceeded);
645 }
646 body.extend_from_slice(&part);
647 }
648 }
649 let response = reader.finish_eof()?;
650 let request = Request {
651 method: head.method,
652 authority: head.authority,
653 path: head.path,
654 headers: head.headers,
655 body,
656 };
657 Ok(AuthenticatedRequest {
658 replay,
659 token: ReplayToken {
660 replay_id: replay.id,
661 retain_until_exclusive: replay.retain_until_exclusive,
662 request,
663 response,
664 },
665 })
666 }
667}
668
669#[cfg(test)]
670mod stream_tests {
671 use super::STREAM_MAX_DATA_RECORDS;
672 use crate::{Client, Error, Limits, Method, Request, RequestHead, Server, generate_key_pair};
673
674 #[test]
675 fn server_accepts_old_key_during_rotation() -> Result<(), Error> {
676 let old = generate_key_pair()?;
677 let new = generate_key_pair()?;
678 let old_public = old.public_key().to_vec();
679 let new_public = new.public_key().to_vec();
680 let (old_private, _) = old.into_parts();
681 let (new_private, _) = new.into_parts();
682 let psk = b"a 32-byte minimum rotation credential";
683 let server = Server::with_accepted_keys(
684 &new_private,
685 b"new".to_vec(),
686 vec![(old_private.to_vec(), b"old".to_vec())],
687 Limits::default(),
688 )?;
689 assert_eq!(server.public_key(), new_public);
690 let request = Request {
691 method: Method::Get,
692 authority: b"api.example.test".to_vec(),
693 path: b"/status".to_vec(),
694 headers: Vec::new(),
695 body: Vec::new(),
696 };
697 for (public_key, id) in [
698 (&old_public, b"old".as_slice()),
699 (&new_public, b"new".as_slice()),
700 ] {
701 let client = Client::new(
702 public_key,
703 id.to_vec(),
704 psk.to_vec(),
705 b"token-id".to_vec(),
706 Limits::default(),
707 )?;
708 let protected = client.protect(&request)?;
709 let preparsed = server.preparse(protected.envelope())?;
710 let _authenticated = server.authenticate(preparsed.token, psk)?;
711 }
712 let unknown = Client::new(
713 &old_public,
714 b"unknown".to_vec(),
715 psk.to_vec(),
716 b"token-id".to_vec(),
717 Limits::default(),
718 )?;
719 let protected = unknown.protect(&request)?;
720 assert_eq!(
721 server.preparse(protected.envelope()).err(),
722 Some(Error::UnknownRecipientKey)
723 );
724 assert_eq!(
725 Server::with_accepted_keys(
726 &new_private,
727 b"new".to_vec(),
728 vec![(new_private.to_vec(), b"new".to_vec())],
729 Limits::default(),
730 )
731 .err(),
732 Some(Error::InvalidConfiguration),
733 );
734 Ok(())
735 }
736
737 #[test]
738 fn data_record_count_guard_closes_both_sides() -> Result<(), Error> {
739 let keys = generate_key_pair()?;
740 let psk = b"a 32-byte minimum upload credential";
741 let client = Client::new(
742 keys.public_key(),
743 b"key".to_vec(),
744 psk.to_vec(),
745 b"psk".to_vec(),
746 Limits::default(),
747 )?;
748 let server = Server::new(&keys.into_parts().0, b"key".to_vec(), Limits::default())?;
749 let head = RequestHead {
750 method: Method::Post,
751 authority: b"api.example.test".to_vec(),
752 path: b"/upload".to_vec(),
753 headers: Vec::new(),
754 };
755 let (mut writer, _) = client.begin_stream(&head)?;
756 writer.data_records = STREAM_MAX_DATA_RECORDS;
757 assert_eq!(writer.push(b"x").err(), Some(Error::LimitExceeded));
758 assert!(writer.context.is_none());
759
760 let (mut writer, first) = client.begin_stream(&head)?;
761 let (used, record) = writer.push(b"x")?;
762 assert_eq!(used, 1);
763 assert!(record.is_none());
764 let (data, _) = writer.finish()?;
765 let preparsed = server.preparse_stream(&first)?;
766 let authenticated = server.authenticate_stream(preparsed.token, psk)?;
767 let mut reader = authenticated
768 .token
769 .admit(authenticated.replay.decision(true))?
770 .reader;
771 reader.data_records = STREAM_MAX_DATA_RECORDS;
772 assert_eq!(reader.feed(&data).err(), Some(Error::LimitExceeded));
773 assert!(reader.context.is_none());
774 assert!(reader.finish_eof().is_err());
775 Ok(())
776 }
777}
778
779pub(crate) struct ResponseMaterial {
780 pub(crate) secret: Zeroizing<[u8; RESPONSE_SECRET_LEN]>,
781 pub(crate) enc: [u8; ENC_LEN],
782 pub(crate) method: Method,
783 pub(crate) limits: Limits,
784}
785
786impl fmt::Debug for ResponseMaterial {
787 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
788 formatter
789 .debug_struct("ResponseMaterial")
790 .field("secret", &"[REDACTED]")
791 .field("enc_len", &self.enc.len())
792 .field("method", &self.method)
793 .field("limits", &self.limits)
794 .finish()
795 }
796}
797
798#[must_use]
800pub struct ResponseToken(ResponseMaterial);
801
802impl fmt::Debug for ResponseToken {
803 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
804 formatter
805 .debug_tuple("ResponseToken")
806 .field(&self.0)
807 .finish()
808 }
809}
810
811impl ResponseToken {
812 #[must_use]
814 pub fn into_opener(self) -> ResponseOpener {
815 ResponseOpener::new(self.0)
816 }
817
818 pub fn open_finite(self, envelope: &[u8]) -> Result<Response, Error> {
824 let mut opener = self.into_opener();
825 let mut offset = 0;
826 while offset < envelope.len() {
827 let (used, record) = opener.feed(&envelope[offset..])?;
828 offset += used;
829 if matches!(record, Some(ResponseRecord::Start(ref head)) if head.mode == ResponseMode::Sse)
830 {
831 return Err(Error::InvalidConfiguration);
832 }
833 if used == 0 {
834 return Err(Error::MalformedEnvelope);
835 }
836 }
837 opener.finish_eof()?.ok_or(Error::MalformedEnvelope)
838 }
839}
840
841#[must_use]
843pub struct ResponseCapability(ResponseMaterial);
844
845impl fmt::Debug for ResponseCapability {
846 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
847 formatter
848 .debug_tuple("ResponseCapability")
849 .field(&self.0)
850 .finish()
851 }
852}
853
854impl ResponseCapability {
855 pub fn into_sealer(
860 self,
861 status: u16,
862 headers: Vec<HeaderField>,
863 ) -> Result<(ResponseSealer, Vec<u8>), Error> {
864 self.into_sealer_with_entropy(status, headers, &mut SystemEntropy)
865 }
866
867 pub fn into_sealer_with_entropy(
872 self,
873 status: u16,
874 headers: Vec<HeaderField>,
875 entropy: &mut impl EntropySource,
876 ) -> Result<(ResponseSealer, Vec<u8>), Error> {
877 ResponseSealer::new(&self.0, status, headers, entropy)
878 }
879
880 pub fn protect_finite(self, response: &Response) -> Result<Vec<u8>, Error> {
885 self.protect_finite_with_entropy(response, &mut SystemEntropy)
886 }
887
888 pub fn protect_finite_with_entropy(
893 self,
894 response: &Response,
895 entropy: &mut impl EntropySource,
896 ) -> Result<Vec<u8>, Error> {
897 self.protect_finite_parts_with_entropy(
898 response.status,
899 response.headers.clone(),
900 &response.body,
901 entropy,
902 )
903 }
904
905 pub fn protect_finite_parts(
910 self,
911 status: u16,
912 headers: Vec<HeaderField>,
913 body: &[u8],
914 ) -> Result<Vec<u8>, Error> {
915 self.protect_finite_parts_with_entropy(status, headers, body, &mut SystemEntropy)
916 }
917
918 fn protect_finite_parts_with_entropy(
919 self,
920 status: u16,
921 headers: Vec<HeaderField>,
922 body: &[u8],
923 entropy: &mut impl EntropySource,
924 ) -> Result<Vec<u8>, Error> {
925 let (mut sealer, mut output) = self.into_sealer_with_entropy(status, headers, entropy)?;
926 if sealer.head_mode() != ResponseMode::Finite {
927 return Err(Error::InvalidConfiguration);
928 }
929 let data = sealer.seal_finite_body(body)?;
930 let end = sealer.finish()?;
931 output.reserve(data.as_ref().map_or(0, Vec::len) + end.len());
932 if let Some(data) = data {
933 output.extend_from_slice(&data);
934 }
935 output.extend_from_slice(&end);
936 Ok(output)
937 }
938}
939
940fn validate_id(identifier: &[u8]) -> Result<(), Error> {
941 if identifier.is_empty() || identifier.len() > HARD_MAX_ID_LEN {
942 return Err(Error::InvalidConfiguration);
943 }
944 Ok(())
945}
946
947fn validate_credential(psk: &[u8], psk_id: &[u8]) -> Result<(), Error> {
948 validate_id(psk_id)?;
949 if psk.len() < MIN_PSK_LEN || psk == psk_id {
950 return Err(Error::InvalidConfiguration);
951 }
952 Ok(())
953}
954
955fn unix_time_seconds() -> Result<u64, Error> {
956 SystemTime::now()
957 .duration_since(UNIX_EPOCH)
958 .map_err(|_| Error::ClockUnavailable)
959 .map(|duration| duration.as_secs())
960}
961
962fn replay_retention_deadline(issued_at_unix_s: u64, now_unix_s: u64) -> Result<u64, Error> {
963 let latest_issued_at = now_unix_s
964 .checked_add(CLOCK_SKEW_SECS)
965 .ok_or(Error::InvalidRequestTime)?;
966 let retain_until_exclusive = issued_at_unix_s
967 .checked_add(REQUEST_LIFETIME_SECS)
968 .and_then(|value| value.checked_add(CLOCK_SKEW_SECS))
969 .ok_or(Error::InvalidRequestTime)?;
970 if issued_at_unix_s > latest_issued_at || now_unix_s >= retain_until_exclusive {
971 return Err(Error::InvalidRequestTime);
972 }
973 Ok(retain_until_exclusive)
974}
975
976fn replay_id(header: &[u8], enc: &[u8]) -> [u8; 32] {
977 let mut digest = Sha256::new();
978 digest.update(REPLAY_LABEL);
979 digest.update(header);
980 digest.update(enc);
981 digest.finalize().into()
982}
983
984fn export_response_material<C>(
985 context: &C,
986 enc: &[u8],
987 method: Method,
988 limits: Limits,
989) -> Result<ResponseMaterial, Error>
990where
991 C: Exporter,
992{
993 let enc: [u8; ENC_LEN] = enc.try_into().map_err(|_| Error::CryptoFailure)?;
994 let mut secret = Zeroizing::new([0_u8; RESPONSE_SECRET_LEN]);
995 context.export_secret(RESPONSE_EXPORT_LABEL, secret.as_mut())?;
996 Ok(ResponseMaterial {
997 secret,
998 enc,
999 method,
1000 limits,
1001 })
1002}
1003
1004pub(crate) fn derive_response_key_nonce(
1005 material: &ResponseMaterial,
1006 response_nonce: &[u8],
1007) -> Result<(ResponseKey, ResponseNonce), Error> {
1008 if response_nonce.len() != RESPONSE_NONCE_LEN {
1009 return Err(Error::MalformedEnvelope);
1010 }
1011 let mut salt = Zeroizing::new(Vec::with_capacity(ENC_LEN + RESPONSE_NONCE_LEN));
1012 salt.extend_from_slice(&material.enc);
1013 salt.extend_from_slice(response_nonce);
1014 let hkdf = Hkdf::<Sha256>::new(Some(&salt), material.secret.as_ref());
1015 let mut key = Zeroizing::new([0_u8; RESPONSE_KEY_LEN]);
1016 hkdf.expand(RESPONSE_KEY_INFO, key.as_mut())
1017 .map_err(|_| Error::CryptoFailure)?;
1018 let mut nonce = Zeroizing::new([0_u8; AEAD_NONCE_LEN]);
1019 hkdf.expand(RESPONSE_NONCE_INFO, nonce.as_mut())
1020 .map_err(|_| Error::CryptoFailure)?;
1021 Ok((key, nonce))
1022}
1023
1024trait Exporter {
1025 fn export_secret(&self, context: &[u8], output: &mut [u8]) -> Result<(), Error>;
1026}
1027
1028impl Exporter for hpke::aead::AeadCtxS<HpkeAead, Kdf, Kem> {
1029 fn export_secret(&self, context: &[u8], output: &mut [u8]) -> Result<(), Error> {
1030 self.export(context, output)
1031 .map_err(|_| Error::CryptoFailure)
1032 }
1033}
1034
1035impl Exporter for RecipientContext {
1036 fn export_secret(&self, context: &[u8], output: &mut [u8]) -> Result<(), Error> {
1037 self.export(context, output)
1038 .map_err(|_| Error::CryptoFailure)
1039 }
1040}
1041
1042fn max_stream_start_ciphertext(limits: Limits) -> usize {
1043 limits.max_header_bytes + limits.max_target_len + limits.max_header_count * 16 + 256 + TAG_LEN
1044}
1045
1046fn max_complete_envelope_len(limits: Limits) -> Result<usize, Error> {
1047 let records = limits
1048 .max_body_len
1049 .min(usize::try_from(STREAM_MAX_DATA_RECORDS).map_err(|_| Error::LimitExceeded)?);
1050 let data_overhead = records
1051 .checked_mul(4 + 2 + TAG_LEN)
1052 .ok_or(Error::LimitExceeded)?;
1053 REQUEST_FIXED_LEN
1054 .checked_add(2 * HARD_MAX_ID_LEN)
1055 .and_then(|length| length.checked_add(ENC_LEN + 4))
1056 .and_then(|length| length.checked_add(max_stream_start_ciphertext(limits)))
1057 .and_then(|length| length.checked_add(limits.max_body_len))
1058 .and_then(|length| length.checked_add(data_overhead))
1059 .and_then(|length| length.checked_add(4 + 1 + TAG_LEN))
1060 .ok_or(Error::LimitExceeded)
1061}
1062
1063fn stream_request_info(header: &[u8]) -> Vec<u8> {
1064 let mut info = Vec::with_capacity(STREAM_REQUEST_INFO_LABEL.len() + header.len());
1065 info.extend_from_slice(STREAM_REQUEST_INFO_LABEL);
1066 info.extend_from_slice(header);
1067 info
1068}
1069
1070fn stream_record_aad(header: &[u8], sequence: u64, ciphertext_len: u32) -> Vec<u8> {
1071 let mut aad = Vec::with_capacity(STREAM_REQUEST_AAD_LABEL.len() + header.len() + 12);
1072 aad.extend_from_slice(STREAM_REQUEST_AAD_LABEL);
1073 aad.extend_from_slice(header);
1074 aad.extend_from_slice(&sequence.to_be_bytes());
1075 aad.extend_from_slice(&ciphertext_len.to_be_bytes());
1076 aad
1077}
1078
1079fn seal_stream_record(
1080 context: &mut SenderContext,
1081 header: &[u8],
1082 sequence: u64,
1083 kind: u8,
1084 coding: Option<u8>,
1085 body: &[u8],
1086) -> Result<Vec<u8>, Error> {
1087 let ciphertext_len = body
1088 .len()
1089 .checked_add(1 + usize::from(coding.is_some()) + TAG_LEN)
1090 .ok_or(Error::LimitExceeded)?;
1091 let ciphertext_len = u32::try_from(ciphertext_len).map_err(|_| Error::LimitExceeded)?;
1092 let mut frame = Vec::with_capacity(4 + ciphertext_len as usize);
1093 frame.extend_from_slice(&ciphertext_len.to_be_bytes());
1094 frame.push(kind);
1095 if let Some(coding) = coding {
1096 frame.push(coding);
1097 }
1098 frame.extend_from_slice(body);
1099 let aad = stream_record_aad(header, sequence, ciphertext_len);
1100 let tag = context
1101 .seal_inout_detached(InOutBuf::from(&mut frame[4..]), &aad)
1102 .map_err(|_| Error::CryptoFailure)?;
1103 frame.extend_from_slice(tag.to_bytes().as_ref());
1104 Ok(frame)
1105}
1106
1107pub struct StreamRequestSealer {
1109 context: Option<SenderContext>,
1110 header: Vec<u8>,
1111 sequence: u64,
1112 data_records: u64,
1113 total_bytes: u64,
1114 content_length: Option<u64>,
1115 max_upload_bytes: u64,
1116 pending: Vec<u8>,
1117 response_token: Option<ResponseToken>,
1118}
1119
1120impl fmt::Debug for StreamRequestSealer {
1121 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1122 formatter
1123 .debug_struct("StreamRequestSealer")
1124 .field("sequence", &self.sequence)
1125 .field("total_bytes", &self.total_bytes)
1126 .finish_non_exhaustive()
1127 }
1128}
1129
1130impl StreamRequestSealer {
1131 pub fn push(&mut self, part: &[u8]) -> Result<(usize, Option<Vec<u8>>), Error> {
1138 let result = self.push_inner(part);
1139 if result.is_err() {
1140 self.context = None;
1141 self.response_token = None;
1142 }
1143 result
1144 }
1145
1146 fn push_inner(&mut self, part: &[u8]) -> Result<(usize, Option<Vec<u8>>), Error> {
1147 if self.context.is_none() {
1148 return Err(Error::InvalidConfiguration);
1149 }
1150 if part.is_empty() {
1151 return Ok((0, None));
1152 }
1153 if self.data_records >= STREAM_MAX_DATA_RECORDS {
1154 return Err(Error::LimitExceeded);
1155 }
1156 let consumed = part.len().min(STREAM_DATA_LEN - self.pending.len());
1157 let next_total = self
1158 .total_bytes
1159 .checked_add(consumed as u64)
1160 .ok_or(Error::LimitExceeded)?;
1161 if next_total > self.max_upload_bytes
1162 || self
1163 .content_length
1164 .is_some_and(|length| next_total > length)
1165 {
1166 return Err(Error::LimitExceeded);
1167 }
1168 self.pending.extend_from_slice(&part[..consumed]);
1169 self.total_bytes = next_total;
1170 if self.pending.len() == STREAM_DATA_LEN {
1171 let frame = self.seal_pending()?;
1172 Ok((consumed, Some(frame)))
1173 } else {
1174 Ok((consumed, None))
1175 }
1176 }
1177
1178 fn seal_pending(&mut self) -> Result<Vec<u8>, Error> {
1179 if self.pending.is_empty() || self.data_records >= STREAM_MAX_DATA_RECORDS {
1180 return Err(Error::LimitExceeded);
1181 }
1182 let (coding, coded) = compression::encode(&self.pending);
1183 let context = self.context.as_mut().ok_or(Error::InvalidConfiguration)?;
1184 let frame = seal_stream_record(
1185 context,
1186 &self.header,
1187 self.sequence,
1188 STREAM_DATA,
1189 Some(coding),
1190 &coded,
1191 )?;
1192 self.pending.clear();
1193 self.sequence += 1;
1194 self.data_records += 1;
1195 Ok(frame)
1196 }
1197
1198 pub fn finish(mut self) -> Result<(Vec<u8>, ResponseToken), Error> {
1204 if self
1205 .content_length
1206 .is_some_and(|length| self.total_bytes != length)
1207 {
1208 return Err(Error::InvalidConfiguration);
1209 }
1210 let mut frame = if self.pending.is_empty() {
1211 Vec::new()
1212 } else {
1213 self.seal_pending()?
1214 };
1215 let context = self.context.as_mut().ok_or(Error::InvalidConfiguration)?;
1216 frame.extend_from_slice(&seal_stream_record(
1217 context,
1218 &self.header,
1219 self.sequence,
1220 STREAM_END,
1221 None,
1222 &[],
1223 )?);
1224 let token = self
1225 .response_token
1226 .take()
1227 .ok_or(Error::InvalidConfiguration)?;
1228 Ok((frame, token))
1229 }
1230}
1231
1232impl Client {
1233 pub fn begin_stream(
1239 &self,
1240 head: &RequestHead,
1241 ) -> Result<(StreamRequestSealer, Vec<u8>), Error> {
1242 self.begin_stream_at_with_entropy(head, unix_time_seconds()?, &mut SystemEntropy)
1243 }
1244
1245 pub fn begin_stream_at_with_entropy(
1250 &self,
1251 head: &RequestHead,
1252 now_unix_s: u64,
1253 entropy: &mut impl EntropySource,
1254 ) -> Result<(StreamRequestSealer, Vec<u8>), Error> {
1255 let max_upload_bytes = self.limits.max_request_bytes;
1256 let content_length = message::stream_content_length(&head.headers)?;
1257 if content_length.is_some_and(|length| length > max_upload_bytes) {
1258 return Err(Error::LimitExceeded);
1259 }
1260 let clear_head = message::encode_stream_head(head, self.limits)?;
1261 let header = encode_request_header(&self.recipient_key_id, &self.psk_id, now_unix_s)?;
1262 let psk_bundle = PskBundle::new(self.psk.as_slice(), &self.psk_id)
1263 .map_err(|_| Error::InvalidConfiguration)?;
1264 let mut random_seed = Zeroizing::new([0_u8; 32]);
1265 entropy.fill(random_seed.as_mut())?;
1266 let mut random = ChaCha20Rng::from_seed(*random_seed);
1267 let (encapped_key, mut context) = setup_sender_with_rng::<HpkeAead, Kdf, Kem>(
1268 &OpModeS::Psk(psk_bundle),
1269 &self.recipient_public_key,
1270 &stream_request_info(&header),
1271 &mut random,
1272 )
1273 .map_err(|_| Error::CryptoFailure)?;
1274 let enc = encapped_key.to_bytes();
1275 let response_material =
1276 export_response_material(&context, enc.as_ref(), head.method, self.limits)?;
1277 let start = seal_stream_record(&mut context, &header, 0, STREAM_START, None, &clear_head)?;
1278 let mut first = Vec::with_capacity(header.len() + ENC_LEN + start.len());
1279 first.extend_from_slice(&header);
1280 first.extend_from_slice(enc.as_ref());
1281 first.extend_from_slice(&start);
1282 Ok((
1283 StreamRequestSealer {
1284 context: Some(context),
1285 header,
1286 sequence: 1,
1287 data_records: 0,
1288 total_bytes: 0,
1289 content_length,
1290 max_upload_bytes,
1291 pending: Vec::with_capacity(STREAM_DATA_LEN),
1292 response_token: Some(ResponseToken(response_material)),
1293 },
1294 first,
1295 ))
1296 }
1297}
1298
1299#[must_use]
1301pub struct PreparsedStreamRequest {
1302 pub credential: CredentialRequest,
1304 pub token: StreamStartToken,
1306}
1307
1308#[must_use]
1310pub struct StreamStartToken {
1311 first: Vec<u8>,
1312}
1313
1314#[must_use]
1316pub struct AuthenticatedStreamRequest {
1317 pub replay: ReplayRequest,
1319 pub token: StreamReplayToken,
1321}
1322
1323#[must_use]
1325pub struct StreamReplayToken {
1326 replay_id: [u8; 32],
1327 retain_until_exclusive: u64,
1328 head: RequestHead,
1329 reader: StreamRequestOpener,
1330}
1331
1332impl StreamReplayToken {
1333 pub fn admit(self, decision: ReplayDecision) -> Result<OpenedStreamRequest, Error> {
1338 self.admit_at(decision, unix_time_seconds()?)
1339 }
1340
1341 pub fn admit_at(
1346 self,
1347 decision: ReplayDecision,
1348 now_unix_s: u64,
1349 ) -> Result<OpenedStreamRequest, Error> {
1350 check_replay_decision(
1351 self.replay_id,
1352 self.retain_until_exclusive,
1353 decision,
1354 now_unix_s,
1355 )?;
1356 Ok(OpenedStreamRequest {
1357 head: self.head,
1358 reader: self.reader,
1359 })
1360 }
1361}
1362
1363#[must_use]
1366pub struct OpenedStreamRequest {
1367 pub head: RequestHead,
1369 pub reader: StreamRequestOpener,
1371}
1372
1373#[derive(Debug, Eq, PartialEq)]
1375pub enum StreamRequestRecord {
1376 Data(Vec<u8>),
1378 End,
1380}
1381
1382pub struct StreamRequestOpener {
1384 context: Option<RecipientContext>,
1385 header: Vec<u8>,
1386 sequence: u64,
1387 data_records: u64,
1388 total_bytes: u64,
1389 content_length: Option<u64>,
1390 max_upload_bytes: u64,
1391 frame: Vec<u8>,
1392 ended: bool,
1393 response_material: Option<ResponseMaterial>,
1394}
1395
1396impl fmt::Debug for StreamRequestOpener {
1397 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1398 formatter
1399 .debug_struct("StreamRequestOpener")
1400 .field("sequence", &self.sequence)
1401 .field("total_bytes", &self.total_bytes)
1402 .field("ended", &self.ended)
1403 .finish_non_exhaustive()
1404 }
1405}
1406
1407impl StreamRequestOpener {
1408 pub fn feed(&mut self, input: &[u8]) -> Result<(usize, Option<StreamRequestRecord>), Error> {
1415 let result = self.feed_inner(input);
1416 if result.is_err() {
1417 self.context = None;
1418 self.response_material = None;
1419 self.frame.clear();
1420 }
1421 result
1422 }
1423
1424 fn feed_inner(&mut self, input: &[u8]) -> Result<(usize, Option<StreamRequestRecord>), Error> {
1425 if self.context.is_none() || (self.ended && !input.is_empty()) {
1426 return Err(Error::MalformedEnvelope);
1427 }
1428 let mut used = 0;
1429 if self.frame.len() < 4 {
1430 let take = (4 - self.frame.len()).min(input.len());
1431 self.frame.extend_from_slice(&input[..take]);
1432 used += take;
1433 if self.frame.len() < 4 {
1434 return Ok((used, None));
1435 }
1436 }
1437 let ciphertext_len = u32::from_be_bytes(
1438 self.frame[..4]
1439 .try_into()
1440 .map_err(|_| Error::MalformedEnvelope)?,
1441 ) as usize;
1442 if ciphertext_len < 1 + TAG_LEN {
1443 return Err(Error::MalformedEnvelope);
1444 }
1445 if ciphertext_len > STREAM_DATA_LEN + 2 + TAG_LEN {
1446 return Err(Error::LimitExceeded);
1447 }
1448 let frame_len = 4 + ciphertext_len;
1449 let take = (frame_len - self.frame.len()).min(input.len() - used);
1450 self.frame.extend_from_slice(&input[used..used + take]);
1451 used += take;
1452 if self.frame.len() < frame_len {
1453 return Ok((used, None));
1454 }
1455 let plain_end = frame_len - TAG_LEN;
1456 let tag = AeadTag::<HpkeAead>::from_bytes(&self.frame[plain_end..])
1457 .map_err(|_| Error::AuthenticationFailed)?;
1458 let aad = stream_record_aad(
1459 &self.header,
1460 self.sequence,
1461 u32::try_from(ciphertext_len).map_err(|_| Error::LimitExceeded)?,
1462 );
1463 self.context
1464 .as_mut()
1465 .ok_or(Error::MalformedEnvelope)?
1466 .open_inout_detached(InOutBuf::from(&mut self.frame[4..plain_end]), &aad, &tag)
1467 .map_err(|_| Error::AuthenticationFailed)?;
1468 let kind = self.frame[4];
1469 let body = &self.frame[5..plain_end];
1470 let record = match kind {
1471 STREAM_DATA => {
1472 if body.len() < 2 || self.data_records >= STREAM_MAX_DATA_RECORDS {
1473 return Err(if body.len() < 2 {
1474 Error::MalformedEnvelope
1475 } else {
1476 Error::LimitExceeded
1477 });
1478 }
1479 let clear = compression::decode(body[0], &body[1..], STREAM_DATA_LEN)?;
1480 let next_total = self
1481 .total_bytes
1482 .checked_add(clear.len() as u64)
1483 .ok_or(Error::LimitExceeded)?;
1484 if next_total > self.max_upload_bytes
1485 || self
1486 .content_length
1487 .is_some_and(|length| next_total > length)
1488 {
1489 return Err(Error::LimitExceeded);
1490 }
1491 self.total_bytes = next_total;
1492 self.data_records += 1;
1493 self.sequence += 1;
1494 StreamRequestRecord::Data(clear)
1495 }
1496 STREAM_END => {
1497 if !body.is_empty()
1498 || self
1499 .content_length
1500 .is_some_and(|length| self.total_bytes != length)
1501 {
1502 return Err(Error::MalformedEnvelope);
1503 }
1504 self.ended = true;
1505 StreamRequestRecord::End
1506 }
1507 _ => return Err(Error::MalformedEnvelope),
1508 };
1509 self.frame.clear();
1510 Ok((used, Some(record)))
1511 }
1512
1513 pub fn finish_eof(mut self) -> Result<ResponseCapability, Error> {
1519 if !self.ended || !self.frame.is_empty() || self.context.is_none() {
1520 return Err(Error::MalformedEnvelope);
1521 }
1522 Ok(ResponseCapability(
1523 self.response_material
1524 .take()
1525 .ok_or(Error::MalformedEnvelope)?,
1526 ))
1527 }
1528}
1529
1530impl Server {
1531 pub fn stream_start_length(&self, input: &[u8]) -> Result<Option<usize>, Error> {
1536 stream_start_length(input, max_stream_start_ciphertext(self.limits))
1537 }
1538
1539 pub fn preparse_stream(&self, first: &[u8]) -> Result<PreparsedStreamRequest, Error> {
1544 let parsed = parse_stream_start(first, max_stream_start_ciphertext(self.limits))?;
1545 self.private_key_for(parsed.key_id)?;
1546 Ok(PreparsedStreamRequest {
1547 credential: CredentialRequest {
1548 psk_id: parsed.psk_id.to_vec(),
1549 },
1550 token: StreamStartToken {
1551 first: first.to_vec(),
1552 },
1553 })
1554 }
1555
1556 pub fn authenticate_stream(
1561 &self,
1562 token: StreamStartToken,
1563 psk: &[u8],
1564 ) -> Result<AuthenticatedStreamRequest, Error> {
1565 self.authenticate_stream_at(token, psk, unix_time_seconds()?)
1566 }
1567
1568 pub fn authenticate_stream_at(
1573 &self,
1574 token: StreamStartToken,
1575 psk: &[u8],
1576 now_unix_s: u64,
1577 ) -> Result<AuthenticatedStreamRequest, Error> {
1578 let StreamStartToken { first } = token;
1579 let max_upload_bytes = self.limits.max_request_bytes;
1580 let parsed = parse_stream_start(&first, max_stream_start_ciphertext(self.limits))?;
1581 let private_key = self.private_key_for(parsed.key_id)?;
1582 validate_credential(psk, parsed.psk_id).map_err(|_| Error::InvalidCredential)?;
1583 let encapped_key = <Kem as KemTrait>::EncappedKey::from_bytes(parsed.enc)
1584 .map_err(|_| Error::AuthenticationFailed)?;
1585 let psk_bundle =
1586 PskBundle::new(psk, parsed.psk_id).map_err(|_| Error::InvalidCredential)?;
1587 let mut context = setup_receiver::<HpkeAead, Kdf, Kem>(
1588 &OpModeR::Psk(psk_bundle),
1589 private_key,
1590 &encapped_key,
1591 &stream_request_info(parsed.header),
1592 )
1593 .map_err(|_| Error::AuthenticationFailed)?;
1594 let mut clear = parsed.ciphertext.to_vec();
1595 let plain_end = clear.len() - TAG_LEN;
1596 let tag = AeadTag::<HpkeAead>::from_bytes(&clear[plain_end..])
1597 .map_err(|_| Error::AuthenticationFailed)?;
1598 let aad = stream_record_aad(
1599 parsed.header,
1600 0,
1601 u32::try_from(clear.len()).map_err(|_| Error::LimitExceeded)?,
1602 );
1603 context
1604 .open_inout_detached(InOutBuf::from(&mut clear[..plain_end]), &aad, &tag)
1605 .map_err(|_| Error::AuthenticationFailed)?;
1606 if clear.first() != Some(&STREAM_START) {
1607 return Err(Error::MalformedEnvelope);
1608 }
1609 let head = message::decode_stream_head(&clear[1..plain_end], self.limits)?;
1610 let content_length = message::stream_content_length(&head.headers)?;
1611 if content_length.is_some_and(|length| length > max_upload_bytes) {
1612 return Err(Error::LimitExceeded);
1613 }
1614 let retain_until_exclusive =
1615 replay_retention_deadline(parsed.issued_at_unix_s, now_unix_s)?;
1616 let replay_id = replay_id(parsed.header, parsed.enc);
1617 let response_material =
1618 export_response_material(&context, parsed.enc, head.method, self.limits)?;
1619 Ok(AuthenticatedStreamRequest {
1620 replay: ReplayRequest {
1621 id: replay_id,
1622 retain_until_exclusive,
1623 },
1624 token: StreamReplayToken {
1625 replay_id,
1626 retain_until_exclusive,
1627 head,
1628 reader: StreamRequestOpener {
1629 context: Some(context),
1630 header: parsed.header.to_vec(),
1631 sequence: 1,
1632 data_records: 0,
1633 total_bytes: 0,
1634 content_length,
1635 max_upload_bytes,
1636 frame: Vec::new(),
1637 ended: false,
1638 response_material: Some(response_material),
1639 },
1640 },
1641 })
1642 }
1643}