1#[cfg(not(feature = "extensions-draft"))]
92use crate::extensions::LastResortExtension;
93use crate::{
94 ciphersuite::{
95 hash_ref::{make_key_package_ref, KeyPackageRef},
96 signable::*,
97 *,
98 },
99 credentials::*,
100 error::LibraryError,
101 extensions::{Extension, ExtensionType, Extensions},
102 storage::OpenMlsProvider,
103 treesync::{
104 node::{
105 encryption_keys::{EncryptionKeyPair, EncryptionPrivateKey},
106 leaf_node::{
107 resolve_capabilities, Capabilities, CapabilitiesPolicy, LeafNodeConstraints,
108 LeafNodeSource, NewLeafNodeParams, TreeInfoTbs,
109 },
110 },
111 LeafNode,
112 },
113 versions::ProtocolVersion,
114};
115#[cfg(feature = "extensions-draft")]
116use crate::{
117 component::{ComponentId, ComponentType},
118 extensions::AppDataDictionaryExtension,
119};
120use openmls_traits::{
121 crypto::OpenMlsCrypto, signatures::Signer, storage::StorageProvider, types::Ciphersuite,
122};
123use serde::{Deserialize, Serialize};
124use tls_codec::{
125 Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
126};
127
128use errors::*;
130
131pub mod errors;
133pub mod key_package_in;
134
135mod lifetime;
136#[cfg(feature = "virtual-clients-draft")]
137mod vc;
138
139#[cfg(test)]
141pub(crate) mod tests;
142
143pub use key_package_in::KeyPackageIn;
145pub use lifetime::Lifetime;
146#[cfg(feature = "virtual-clients-draft")]
147pub use vc::{VcKeyPackageBatch, VcKeyPackageBatchBuilder};
148
149#[derive(Debug, Clone, PartialEq, TlsSize, TlsSerialize, Serialize, Deserialize)]
163struct KeyPackageTbs {
164 protocol_version: ProtocolVersion,
165 ciphersuite: Ciphersuite,
166 init_key: InitKey,
167 leaf_node: LeafNode,
168 extensions: Extensions<KeyPackage>,
169}
170
171impl Signable for KeyPackageTbs {
172 type SignedOutput = KeyPackage;
173
174 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
175 self.tls_serialize_detached()
176 }
177
178 fn label(&self) -> &str {
179 SIGNATURE_KEY_PACKAGE_LABEL
180 }
181}
182
183impl From<KeyPackage> for KeyPackageTbs {
184 fn from(kp: KeyPackage) -> Self {
185 kp.payload
186 }
187}
188
189#[derive(Debug, Clone, Serialize, Deserialize, TlsSize)]
191pub struct KeyPackage {
192 payload: KeyPackageTbs,
193 signature: Signature,
194 #[serde(skip)]
195 #[tls_codec(skip)]
196 serialized_payload: Option<Vec<u8>>,
197}
198
199impl TlsSerializeTrait for KeyPackage {
200 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
201 let mut written = 0;
202 if let Some(ref bytes) = self.serialized_payload {
203 writer.write_all(bytes)?;
204 written += bytes.len();
205 } else {
206 written += self.payload.tls_serialize(writer)?;
207 }
208 written += self.signature.tls_serialize(writer)?;
209 Ok(written)
210 }
211}
212
213impl PartialEq for KeyPackage {
214 fn eq(&self, other: &Self) -> bool {
215 self.payload == other.payload
218 }
219}
220
221impl SignedStruct<KeyPackageTbs> for KeyPackage {
222 fn from_payload(
223 payload: KeyPackageTbs,
224 signature: Signature,
225 serialized_payload: Vec<u8>,
226 ) -> Self {
227 Self {
228 payload,
229 signature,
230 serialized_payload: Some(serialized_payload),
231 }
232 }
233}
234
235const SIGNATURE_KEY_PACKAGE_LABEL: &str = "KeyPackageTBS";
236
237#[cfg(feature = "extensions-draft")]
238fn last_resort_component_id() -> ComponentId {
239 ComponentType::LastResortKeyPackage.into()
240}
241
242pub(crate) fn has_last_resort_marker(extensions: &Extensions<KeyPackage>) -> bool {
245 #[cfg(feature = "extensions-draft")]
246 if matches!(
247 extensions
248 .app_data_dictionary()
249 .and_then(|extension| extension.dictionary().get(&last_resort_component_id())),
250 Some(data) if data.is_empty()
251 ) {
252 return true;
253 }
254
255 extensions.contains(ExtensionType::LastResort)
256}
257
258pub(crate) struct KeyPackageLeafNodeParams {
260 pub(crate) lifetime: Lifetime,
261 pub(crate) capabilities: Capabilities,
262 pub(crate) extensions: Extensions<LeafNode>,
263 pub(crate) capabilities_policy: CapabilitiesPolicy,
267}
268
269pub(crate) struct KeyPackageCreationResult {
271 pub key_package: KeyPackage,
272 pub encryption_keypair: EncryptionKeyPair,
273 pub init_private_key: HpkePrivateKey,
274}
275
276#[derive(
278 Debug,
279 Clone,
280 PartialEq,
281 TlsSize,
282 TlsSerialize,
283 Serialize,
284 Deserialize,
285 TlsDeserialize,
286 TlsDeserializeBytes,
287)]
288pub struct InitKey {
289 key: HpkePublicKey,
290}
291
292impl InitKey {
293 pub fn key(&self) -> &HpkePublicKey {
295 &self.key
296 }
297
298 pub fn as_slice(&self) -> &[u8] {
300 self.key.as_slice()
301 }
302}
303
304impl From<Vec<u8>> for InitKey {
305 fn from(key: Vec<u8>) -> Self {
306 Self {
307 key: HpkePublicKey::from(key),
308 }
309 }
310}
311
312impl From<HpkePublicKey> for InitKey {
313 fn from(key: HpkePublicKey) -> Self {
314 Self { key }
315 }
316}
317
318impl KeyPackage {
320 pub fn builder() -> KeyPackageBuilder {
324 KeyPackageBuilder::new()
325 }
326
327 pub(crate) fn create(
329 ciphersuite: Ciphersuite,
330 provider: &impl OpenMlsProvider,
331 signer: &impl Signer,
332 credential_with_key: CredentialWithKey,
333 extensions: Extensions<KeyPackage>,
334 leaf_node_params: KeyPackageLeafNodeParams,
335 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
336 if ciphersuite.signature_algorithm() != signer.signature_scheme() {
337 return Err(KeyPackageNewError::CiphersuiteSignatureSchemeMismatch);
338 }
339
340 provider
341 .crypto()
342 .supports(ciphersuite)
343 .map_err(|_| KeyPackageNewError::UnsupportedCiphersuite(ciphersuite))?;
344
345 let ikm = Secret::random(ciphersuite, provider.rand())
347 .map_err(LibraryError::unexpected_crypto_error)?;
348 let init_key = provider
349 .crypto()
350 .derive_hpke_keypair(ciphersuite.hpke_config(), ikm.as_slice())
351 .map_err(|e| {
352 KeyPackageNewError::LibraryError(LibraryError::unexpected_crypto_error(e))
353 })?;
354 let (key_package, encryption_keypair) = Self::new_from_keys(
355 ciphersuite,
356 provider,
357 signer,
358 credential_with_key,
359 extensions,
360 leaf_node_params,
361 init_key.public.into(),
362 )?;
363
364 Ok(KeyPackageCreationResult {
365 key_package,
366 encryption_keypair,
367 init_private_key: init_key.private,
368 })
369 }
370
371 fn new_from_keys(
381 ciphersuite: Ciphersuite,
382 provider: &impl OpenMlsProvider,
383 signer: &impl Signer,
384 credential_with_key: CredentialWithKey,
385 extensions: Extensions<KeyPackage>,
386 leaf_node_params: KeyPackageLeafNodeParams,
387 init_key: InitKey,
388 ) -> Result<(Self, EncryptionKeyPair), KeyPackageNewError> {
389 let KeyPackageLeafNodeParams {
393 lifetime,
394 mut capabilities,
395 extensions: leaf_node_extensions,
396 capabilities_policy,
397 } = leaf_node_params;
398
399 if matches!(capabilities_policy, CapabilitiesPolicy::Widen) {
400 capabilities.widen_for_key_package(&extensions);
401 }
402
403 let new_leaf_node_params = NewLeafNodeParams {
404 ciphersuite,
405 credential_with_key,
406 leaf_node_source: LeafNodeSource::KeyPackage(lifetime),
407 capabilities,
408 extensions: leaf_node_extensions,
409 tree_info_tbs: TreeInfoTbs::KeyPackage,
410 constraints: LeafNodeConstraints::default(),
413 capabilities_policy,
414 };
415
416 let (leaf_node, encryption_key_pair) =
417 LeafNode::new(provider, signer, new_leaf_node_params)?;
418
419 let key_package_tbs = KeyPackageTbs {
420 protocol_version: ProtocolVersion::default(),
421 ciphersuite,
422 init_key,
423 leaf_node,
424 extensions,
425 };
426
427 let key_package = key_package_tbs.sign(signer)?;
428
429 Ok((key_package, encryption_key_pair))
430 }
431
432 #[cfg(feature = "virtual-clients-draft")]
439 fn new_from_vc_keys(
440 ciphersuite: Ciphersuite,
441 signer: &impl Signer,
442 credential_with_key: CredentialWithKey,
443 extensions: Extensions<KeyPackage>,
444 leaf_node_params: KeyPackageLeafNodeParams,
445 init_key: InitKey,
446 encryption_key_pair: EncryptionKeyPair,
447 ) -> Result<(Self, EncryptionKeyPair), KeyPackageNewError> {
448 let KeyPackageLeafNodeParams {
449 lifetime,
450 mut capabilities,
451 extensions: leaf_node_extensions,
452 capabilities_policy,
453 } = leaf_node_params;
454
455 if matches!(capabilities_policy, CapabilitiesPolicy::Widen) {
456 capabilities.widen_for_key_package(&extensions);
457 }
458
459 let new_leaf_node_params = NewLeafNodeParams {
460 ciphersuite,
461 credential_with_key,
462 leaf_node_source: LeafNodeSource::KeyPackage(lifetime),
463 capabilities,
464 extensions: leaf_node_extensions,
465 tree_info_tbs: TreeInfoTbs::KeyPackage,
466 constraints: LeafNodeConstraints::default(),
469 capabilities_policy,
470 };
471
472 let (leaf_node, encryption_key_pair) = LeafNode::new_with_encryption_key_pair(
473 signer,
474 new_leaf_node_params,
475 encryption_key_pair,
476 )?;
477
478 let key_package_tbs = KeyPackageTbs {
479 protocol_version: ProtocolVersion::default(),
480 ciphersuite,
481 init_key,
482 leaf_node,
483 extensions,
484 };
485
486 let key_package = key_package_tbs.sign(signer)?;
487
488 Ok((key_package, encryption_key_pair))
489 }
490
491 pub fn extensions(&self) -> &Extensions<KeyPackage> {
493 &self.payload.extensions
494 }
495
496 pub fn check_extension_support(
499 &self,
500 required_extensions: &[ExtensionType],
501 ) -> Result<(), KeyPackageExtensionSupportError> {
502 for required_extension in required_extensions.iter() {
503 if !self.extensions().contains(*required_extension) {
504 return Err(KeyPackageExtensionSupportError::UnsupportedExtension);
505 }
506 }
507
508 Ok(())
509 }
510
511 pub fn hash_ref(&self, crypto: &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError> {
515 make_key_package_ref(
516 &self
517 .tls_serialize_detached()
518 .map_err(LibraryError::missing_bound_check)?,
519 self.payload.ciphersuite,
520 crypto,
521 )
522 .map_err(LibraryError::unexpected_crypto_error)
523 }
524
525 pub fn ciphersuite(&self) -> Ciphersuite {
527 self.payload.ciphersuite
528 }
529
530 pub fn leaf_node(&self) -> &LeafNode {
532 &self.payload.leaf_node
533 }
534
535 pub fn hpke_init_key(&self) -> &InitKey {
537 &self.payload.init_key
538 }
539
540 pub fn last_resort(&self) -> bool {
547 has_last_resort_marker(&self.payload.extensions)
548 }
549
550 #[cfg(feature = "extensions-draft")]
551 fn has_malformed_last_resort_component(&self) -> bool {
552 matches!(
553 self.payload
554 .extensions
555 .app_data_dictionary()
556 .and_then(|extension| extension.dictionary().get(&last_resort_component_id())),
557 Some(data) if !data.is_empty()
558 )
559 }
560
561 pub fn life_time(&self) -> &Lifetime {
563 self.payload.leaf_node.life_time().unwrap()
567 }
568}
569
570impl KeyPackage {
572 pub(crate) fn protocol_version(&self) -> ProtocolVersion {
574 self.payload.protocol_version
575 }
576}
577
578#[derive(Default, Debug, Clone, Serialize, Deserialize)]
580pub struct KeyPackageBuilder {
581 key_package_lifetime: Option<Lifetime>,
582 key_package_extensions: Option<Extensions<KeyPackage>>,
583 leaf_node_capabilities: Option<Capabilities>,
584 leaf_node_extensions: Option<Extensions<LeafNode>>,
585 last_resort: bool,
586 capabilities_policy: Option<CapabilitiesPolicy>,
587}
588
589impl KeyPackageBuilder {
590 pub fn new() -> Self {
592 Self {
593 key_package_lifetime: None,
594 key_package_extensions: None,
595 leaf_node_capabilities: None,
596 leaf_node_extensions: None,
597 last_resort: false,
598 capabilities_policy: None,
599 }
600 }
601
602 pub fn key_package_lifetime(mut self, lifetime: Lifetime) -> Self {
604 self.key_package_lifetime.replace(lifetime);
605 self
606 }
607
608 pub fn key_package_extensions(mut self, extensions: Extensions<KeyPackage>) -> Self {
610 self.key_package_extensions.replace(extensions);
611 self
612 }
613
614 pub fn mark_as_last_resort(mut self) -> Self {
626 self.last_resort = true;
627 self
628 }
629
630 pub fn leaf_node_capabilities(mut self, capabilities: Capabilities) -> Self {
632 self.leaf_node_capabilities.replace(capabilities);
633 self
634 }
635
636 pub fn leaf_node_extensions(mut self, extensions: Extensions<LeafNode>) -> Self {
640 self.leaf_node_extensions.replace(extensions);
641 self
642 }
643
644 pub fn capabilities_policy(mut self, policy: CapabilitiesPolicy) -> Self {
651 self.capabilities_policy = Some(policy);
652 self
653 }
654
655 fn ensure_last_resort_capability(
660 &self,
661 extension_type: ExtensionType,
662 ) -> Result<(), KeyPackageNewError> {
663 let (capabilities, capabilities_policy) = resolve_capabilities(
664 self.leaf_node_capabilities.clone(),
665 self.capabilities_policy,
666 );
667 if matches!(capabilities_policy, CapabilitiesPolicy::Reject)
668 && !capabilities.extensions().contains(&extension_type)
669 {
670 return Err(KeyPackageNewError::MissingLastResortCapability(
671 extension_type,
672 ));
673 }
674 Ok(())
675 }
676
677 #[cfg(feature = "extensions-draft")]
684 fn ensure_last_resort(&mut self) -> Result<(), KeyPackageNewError> {
685 if !self.last_resort {
686 return Ok(());
687 }
688
689 self.ensure_last_resort_capability(ExtensionType::AppDataDictionary)?;
690
691 let mut dictionary = self
692 .key_package_extensions
693 .as_ref()
694 .and_then(Extensions::app_data_dictionary)
695 .map(|extension| extension.dictionary().clone())
696 .unwrap_or_default();
697 dictionary.insert(last_resort_component_id(), Vec::new());
698
699 let last_resort_component =
700 Extension::AppDataDictionary(AppDataDictionaryExtension::new(dictionary));
701 if let Some(extensions) = self.key_package_extensions.as_mut() {
702 extensions
703 .add_or_replace(last_resort_component)
704 .expect("AppDataDictionary extensions are allowed in KeyPackages");
705 } else {
706 self.key_package_extensions = Some(
707 Extensions::single(last_resort_component)
708 .expect("AppDataDictionary extensions are allowed in KeyPackages"),
709 );
710 }
711 Ok(())
712 }
713
714 #[cfg(not(feature = "extensions-draft"))]
715 fn ensure_last_resort(&mut self) -> Result<(), KeyPackageNewError> {
716 if !self.last_resort {
717 return Ok(());
718 }
719
720 self.ensure_last_resort_capability(ExtensionType::LastResort)?;
721
722 let last_resort_extension = Extension::LastResort(LastResortExtension::default());
723 if let Some(extensions) = self.key_package_extensions.as_mut() {
724 extensions
725 .add_or_replace(last_resort_extension)
726 .expect("LastResort extensions are allowed in KeyPackages");
727 } else {
728 self.key_package_extensions = Some(
729 Extensions::single(last_resort_extension)
730 .expect("LastResort extensions are allowed in KeyPackages"),
731 );
732 }
733 Ok(())
734 }
735
736 #[cfg(test)]
737 pub(crate) fn build_without_storage(
738 mut self,
739 ciphersuite: Ciphersuite,
740 provider: &impl OpenMlsProvider,
741 signer: &impl Signer,
742 credential_with_key: CredentialWithKey,
743 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
744 self.ensure_last_resort()?;
745 let (capabilities, capabilities_policy) =
746 resolve_capabilities(self.leaf_node_capabilities, self.capabilities_policy);
747 let leaf_node_params = KeyPackageLeafNodeParams {
748 lifetime: self.key_package_lifetime.unwrap_or_default(),
749 capabilities,
750 extensions: self.leaf_node_extensions.unwrap_or_default(),
751 capabilities_policy,
752 };
753 KeyPackage::create(
754 ciphersuite,
755 provider,
756 signer,
757 credential_with_key,
758 self.key_package_extensions.unwrap_or_default(),
759 leaf_node_params,
760 )
761 }
762
763 #[openmls_traits::maybe_async]
765 pub async fn build(
766 mut self,
767 ciphersuite: Ciphersuite,
768 provider: &impl OpenMlsProvider,
769 signer: &impl Signer,
770 credential_with_key: CredentialWithKey,
771 ) -> Result<KeyPackageBundle, KeyPackageNewError> {
772 self.ensure_last_resort()?;
773
774 let (capabilities, capabilities_policy) =
775 resolve_capabilities(self.leaf_node_capabilities, self.capabilities_policy);
776 let leaf_node_params = KeyPackageLeafNodeParams {
777 lifetime: self.key_package_lifetime.unwrap_or_default(),
778 capabilities,
779 extensions: self.leaf_node_extensions.unwrap_or_default(),
780 capabilities_policy,
781 };
782 let KeyPackageCreationResult {
783 key_package,
784 encryption_keypair,
785 init_private_key,
786 } = KeyPackage::create(
787 ciphersuite,
788 provider,
789 signer,
790 credential_with_key,
791 self.key_package_extensions.unwrap_or_default(),
792 leaf_node_params,
793 )?;
794
795 let full_kp = KeyPackageBundle {
798 key_package,
799 private_init_key: init_private_key,
800 private_encryption_key: encryption_keypair.private_key().clone(),
801 };
802 provider
803 .storage()
804 .write_key_package(&full_kp.key_package.hash_ref(provider.crypto())?, &full_kp)
805 .await
806 .map_err(|_| KeyPackageNewError::StorageError)?;
807
808 Ok(full_kp)
809 }
810
811 #[cfg(feature = "virtual-clients-draft")]
851 #[openmls_traits::maybe_async]
852 pub async fn build_vc_batch(
853 self,
854 ciphersuite: Ciphersuite,
855 provider: &impl OpenMlsProvider,
856 signer: &impl Signer,
857 credential_with_key: CredentialWithKey,
858 emulation_group_id: &crate::group::GroupId,
859 count: usize,
860 ) -> Result<VcKeyPackageBatch, KeyPackageNewError> {
861 provider
864 .crypto()
865 .supports(ciphersuite)
866 .map_err(|_| KeyPackageNewError::UnsupportedCiphersuite(ciphersuite))?;
867
868 if count == 0 {
869 return Err(KeyPackageNewError::EmptyBatch);
870 }
871 let mut builder =
872 VcKeyPackageBatchBuilder::with_capacity(provider, emulation_group_id, count).await?;
873 for _ in 0..count {
874 builder.add_key_package(
875 self.clone(),
876 ciphersuite,
877 provider.crypto(),
878 signer,
879 credential_with_key.clone(),
880 )?;
881 }
882 builder.finalize(provider).await
883 }
884}
885
886#[derive(Debug, Clone, Serialize, Deserialize)]
892pub struct KeyPackageBundle {
893 pub(crate) key_package: KeyPackage,
894 pub(crate) private_init_key: HpkePrivateKey,
895 pub(crate) private_encryption_key: EncryptionPrivateKey,
896}
897
898impl KeyPackageBundle {
900 pub fn key_package(&self) -> &KeyPackage {
902 &self.key_package
903 }
904
905 pub fn into_key_package(self) -> KeyPackage {
907 self.key_package
908 }
909
910 pub fn init_private_key(&self) -> &HpkePrivateKey {
912 &self.private_init_key
913 }
914
915 pub(crate) fn encryption_key_pair(&self) -> EncryptionKeyPair {
917 EncryptionKeyPair::from((
918 self.key_package.leaf_node().encryption_key().clone(),
919 self.private_encryption_key.clone(),
920 ))
921 }
922}
923
924#[cfg(any(test, feature = "test-utils"))]
925impl KeyPackageBundle {
926 pub fn new(
928 key_package: KeyPackage,
929 private_init_key: HpkePrivateKey,
930 private_encryption_key: EncryptionPrivateKey,
931 ) -> Self {
932 Self {
933 key_package,
934 private_init_key,
935 private_encryption_key,
936 }
937 }
938
939 pub fn encryption_private_key(&self) -> &HpkePrivateKey {
941 self.private_encryption_key.key()
942 }
943}
944
945#[cfg(test)]
946impl KeyPackageBundle {
947 pub(crate) fn generate(
948 provider: &impl OpenMlsProvider,
949 signer: &impl Signer,
950 ciphersuite: Ciphersuite,
951 credential_with_key: CredentialWithKey,
952 ) -> Self {
953 KeyPackage::builder()
954 .leaf_node_capabilities(
955 Capabilities::builder()
956 .ciphersuites(vec![ciphersuite])
957 .credentials(vec![CredentialType::Basic])
958 .build(),
959 )
960 .build(ciphersuite, provider, signer, credential_with_key)
961 .unwrap()
962 }
963}