1use crate::{
92 ciphersuite::{
93 hash_ref::{make_key_package_ref, KeyPackageRef},
94 signable::*,
95 *,
96 },
97 credentials::*,
98 error::LibraryError,
99 extensions::{Extension, ExtensionType, Extensions, LastResortExtension},
100 storage::OpenMlsProvider,
101 treesync::{
102 node::{
103 encryption_keys::{EncryptionKeyPair, EncryptionPrivateKey},
104 leaf_node::{Capabilities, LeafNodeSource, NewLeafNodeParams, TreeInfoTbs},
105 },
106 LeafNode,
107 },
108 versions::ProtocolVersion,
109};
110use openmls_traits::{
111 crypto::OpenMlsCrypto, signatures::Signer, storage::StorageProvider, types::Ciphersuite,
112};
113use serde::{Deserialize, Serialize};
114use tls_codec::{
115 Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
116};
117
118use errors::*;
120
121pub mod errors;
123pub mod key_package_in;
124
125mod lifetime;
126#[cfg(feature = "virtual-clients-draft")]
127mod vc;
128
129#[cfg(test)]
131pub(crate) mod tests;
132
133pub use key_package_in::KeyPackageIn;
135pub use lifetime::Lifetime;
136#[cfg(feature = "virtual-clients-draft")]
137pub use vc::{VcKeyPackageBatch, VcKeyPackageBatchBuilder};
138
139#[derive(Debug, Clone, PartialEq, TlsSize, TlsSerialize, Serialize, Deserialize)]
153struct KeyPackageTbs {
154 protocol_version: ProtocolVersion,
155 ciphersuite: Ciphersuite,
156 init_key: InitKey,
157 leaf_node: LeafNode,
158 extensions: Extensions<KeyPackage>,
159}
160
161impl Signable for KeyPackageTbs {
162 type SignedOutput = KeyPackage;
163
164 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
165 self.tls_serialize_detached()
166 }
167
168 fn label(&self) -> &str {
169 SIGNATURE_KEY_PACKAGE_LABEL
170 }
171}
172
173impl From<KeyPackage> for KeyPackageTbs {
174 fn from(kp: KeyPackage) -> Self {
175 kp.payload
176 }
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize, TlsSize)]
181pub struct KeyPackage {
182 payload: KeyPackageTbs,
183 signature: Signature,
184 #[serde(skip)]
185 #[tls_codec(skip)]
186 serialized_payload: Option<Vec<u8>>,
187}
188
189impl TlsSerializeTrait for KeyPackage {
190 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
191 let mut written = 0;
192 if let Some(ref bytes) = self.serialized_payload {
193 written += writer.write(bytes)?;
194 } else {
195 written += self.payload.tls_serialize(writer)?;
196 }
197 written += self.signature.tls_serialize(writer)?;
198 Ok(written)
199 }
200}
201
202impl PartialEq for KeyPackage {
203 fn eq(&self, other: &Self) -> bool {
204 self.payload == other.payload
207 }
208}
209
210impl SignedStruct<KeyPackageTbs> for KeyPackage {
211 fn from_payload(
212 payload: KeyPackageTbs,
213 signature: Signature,
214 serialized_payload: Vec<u8>,
215 ) -> Self {
216 Self {
217 payload,
218 signature,
219 serialized_payload: Some(serialized_payload),
220 }
221 }
222}
223
224const SIGNATURE_KEY_PACKAGE_LABEL: &str = "KeyPackageTBS";
225
226pub(crate) struct KeyPackageLeafNodeParams {
228 pub(crate) lifetime: Lifetime,
229 pub(crate) capabilities: Capabilities,
230 pub(crate) extensions: Extensions<LeafNode>,
231}
232
233pub(crate) struct KeyPackageCreationResult {
235 pub key_package: KeyPackage,
236 pub encryption_keypair: EncryptionKeyPair,
237 pub init_private_key: HpkePrivateKey,
238}
239
240#[derive(
242 Debug,
243 Clone,
244 PartialEq,
245 TlsSize,
246 TlsSerialize,
247 Serialize,
248 Deserialize,
249 TlsDeserialize,
250 TlsDeserializeBytes,
251)]
252pub struct InitKey {
253 key: HpkePublicKey,
254}
255
256impl InitKey {
257 pub fn key(&self) -> &HpkePublicKey {
259 &self.key
260 }
261
262 pub fn as_slice(&self) -> &[u8] {
264 self.key.as_slice()
265 }
266}
267
268impl From<Vec<u8>> for InitKey {
269 fn from(key: Vec<u8>) -> Self {
270 Self {
271 key: HpkePublicKey::from(key),
272 }
273 }
274}
275
276impl From<HpkePublicKey> for InitKey {
277 fn from(key: HpkePublicKey) -> Self {
278 Self { key }
279 }
280}
281
282impl KeyPackage {
284 pub fn builder() -> KeyPackageBuilder {
288 KeyPackageBuilder::new()
289 }
290
291 pub(crate) fn create(
293 ciphersuite: Ciphersuite,
294 provider: &impl OpenMlsProvider,
295 signer: &impl Signer,
296 credential_with_key: CredentialWithKey,
297 extensions: Extensions<KeyPackage>,
298 leaf_node_params: KeyPackageLeafNodeParams,
299 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
300 if ciphersuite.signature_algorithm() != signer.signature_scheme() {
301 return Err(KeyPackageNewError::CiphersuiteSignatureSchemeMismatch);
302 }
303
304 provider
305 .crypto()
306 .supports(ciphersuite)
307 .map_err(|_| KeyPackageNewError::UnsupportedCiphersuite(ciphersuite))?;
308
309 let ikm = Secret::random(ciphersuite, provider.rand())
311 .map_err(LibraryError::unexpected_crypto_error)?;
312 let init_key = provider
313 .crypto()
314 .derive_hpke_keypair(ciphersuite.hpke_config(), ikm.as_slice())
315 .map_err(|e| {
316 KeyPackageNewError::LibraryError(LibraryError::unexpected_crypto_error(e))
317 })?;
318 let (key_package, encryption_keypair) = Self::new_from_keys(
319 ciphersuite,
320 provider,
321 signer,
322 credential_with_key,
323 extensions,
324 leaf_node_params,
325 init_key.public.into(),
326 )?;
327
328 Ok(KeyPackageCreationResult {
329 key_package,
330 encryption_keypair,
331 init_private_key: init_key.private,
332 })
333 }
334
335 fn new_from_keys(
345 ciphersuite: Ciphersuite,
346 provider: &impl OpenMlsProvider,
347 signer: &impl Signer,
348 credential_with_key: CredentialWithKey,
349 extensions: Extensions<KeyPackage>,
350 leaf_node_params: KeyPackageLeafNodeParams,
351 init_key: InitKey,
352 ) -> Result<(Self, EncryptionKeyPair), KeyPackageNewError> {
353 let KeyPackageLeafNodeParams {
357 lifetime,
358 capabilities,
359 extensions: leaf_node_extensions,
360 } = leaf_node_params;
361
362 let new_leaf_node_params = NewLeafNodeParams {
363 ciphersuite,
364 credential_with_key,
365 leaf_node_source: LeafNodeSource::KeyPackage(lifetime),
366 capabilities,
367 extensions: leaf_node_extensions,
368 tree_info_tbs: TreeInfoTbs::KeyPackage,
369 };
370
371 let (leaf_node, encryption_key_pair) =
372 LeafNode::new(provider, signer, new_leaf_node_params)?;
373
374 let key_package_tbs = KeyPackageTbs {
375 protocol_version: ProtocolVersion::default(),
376 ciphersuite,
377 init_key,
378 leaf_node,
379 extensions,
380 };
381
382 let key_package = key_package_tbs.sign(signer)?;
383
384 Ok((key_package, encryption_key_pair))
385 }
386
387 #[cfg(feature = "virtual-clients-draft")]
394 fn new_from_vc_keys(
395 ciphersuite: Ciphersuite,
396 signer: &impl Signer,
397 credential_with_key: CredentialWithKey,
398 extensions: Extensions<KeyPackage>,
399 leaf_node_params: KeyPackageLeafNodeParams,
400 init_key: InitKey,
401 encryption_key_pair: EncryptionKeyPair,
402 ) -> Result<(Self, EncryptionKeyPair), KeyPackageNewError> {
403 let KeyPackageLeafNodeParams {
404 lifetime,
405 capabilities,
406 extensions: leaf_node_extensions,
407 } = leaf_node_params;
408
409 let new_leaf_node_params = NewLeafNodeParams {
410 ciphersuite,
411 credential_with_key,
412 leaf_node_source: LeafNodeSource::KeyPackage(lifetime),
413 capabilities,
414 extensions: leaf_node_extensions,
415 tree_info_tbs: TreeInfoTbs::KeyPackage,
416 };
417
418 let (leaf_node, encryption_key_pair) = LeafNode::new_with_encryption_key_pair(
419 signer,
420 new_leaf_node_params,
421 encryption_key_pair,
422 )?;
423
424 let key_package_tbs = KeyPackageTbs {
425 protocol_version: ProtocolVersion::default(),
426 ciphersuite,
427 init_key,
428 leaf_node,
429 extensions,
430 };
431
432 let key_package = key_package_tbs.sign(signer)?;
433
434 Ok((key_package, encryption_key_pair))
435 }
436
437 pub fn extensions(&self) -> &Extensions<KeyPackage> {
439 &self.payload.extensions
440 }
441
442 pub fn check_extension_support(
445 &self,
446 required_extensions: &[ExtensionType],
447 ) -> Result<(), KeyPackageExtensionSupportError> {
448 for required_extension in required_extensions.iter() {
449 if !self.extensions().contains(*required_extension) {
450 return Err(KeyPackageExtensionSupportError::UnsupportedExtension);
451 }
452 }
453
454 Ok(())
455 }
456
457 pub fn hash_ref(&self, crypto: &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError> {
461 make_key_package_ref(
462 &self
463 .tls_serialize_detached()
464 .map_err(LibraryError::missing_bound_check)?,
465 self.payload.ciphersuite,
466 crypto,
467 )
468 .map_err(LibraryError::unexpected_crypto_error)
469 }
470
471 pub fn ciphersuite(&self) -> Ciphersuite {
473 self.payload.ciphersuite
474 }
475
476 pub fn leaf_node(&self) -> &LeafNode {
478 &self.payload.leaf_node
479 }
480
481 pub fn hpke_init_key(&self) -> &InitKey {
483 &self.payload.init_key
484 }
485
486 pub fn last_resort(&self) -> bool {
488 self.payload.extensions.contains(ExtensionType::LastResort)
489 }
490
491 pub fn life_time(&self) -> &Lifetime {
493 self.payload.leaf_node.life_time().unwrap()
497 }
498}
499
500impl KeyPackage {
502 pub(crate) fn protocol_version(&self) -> ProtocolVersion {
504 self.payload.protocol_version
505 }
506}
507
508#[derive(Default, Debug, Clone, Serialize, Deserialize)]
510pub struct KeyPackageBuilder {
511 key_package_lifetime: Option<Lifetime>,
512 key_package_extensions: Option<Extensions<KeyPackage>>,
513 leaf_node_capabilities: Option<Capabilities>,
514 leaf_node_extensions: Option<Extensions<LeafNode>>,
515 last_resort: bool,
516}
517
518impl KeyPackageBuilder {
519 pub fn new() -> Self {
521 Self {
522 key_package_lifetime: None,
523 key_package_extensions: None,
524 leaf_node_capabilities: None,
525 leaf_node_extensions: None,
526 last_resort: false,
527 }
528 }
529
530 pub fn key_package_lifetime(mut self, lifetime: Lifetime) -> Self {
532 self.key_package_lifetime.replace(lifetime);
533 self
534 }
535
536 pub fn key_package_extensions(mut self, extensions: Extensions<KeyPackage>) -> Self {
538 self.key_package_extensions.replace(extensions);
539 self
540 }
541
542 pub fn mark_as_last_resort(mut self) -> Self {
544 self.last_resort = true;
545 self
546 }
547
548 pub fn leaf_node_capabilities(mut self, capabilities: Capabilities) -> Self {
550 self.leaf_node_capabilities.replace(capabilities);
551 self
552 }
553
554 pub fn leaf_node_extensions(mut self, extensions: Extensions<LeafNode>) -> Self {
558 self.leaf_node_extensions.replace(extensions);
559 self
560 }
561
562 fn ensure_last_resort(&mut self) {
565 if self.last_resort {
566 let last_resort_extension = Extension::LastResort(LastResortExtension::default());
567 if let Some(extensions) = self.key_package_extensions.as_mut() {
568 extensions
569 .add_or_replace(last_resort_extension)
570 .expect("LastResort extensions are allowed in key packages");
571 } else {
572 self.key_package_extensions = Some(
573 Extensions::single(last_resort_extension)
574 .expect("LastResort extensions are allowed in key packages"),
575 );
576 }
577 }
578 }
579
580 #[cfg(test)]
581 pub(crate) fn build_without_storage(
582 mut self,
583 ciphersuite: Ciphersuite,
584 provider: &impl OpenMlsProvider,
585 signer: &impl Signer,
586 credential_with_key: CredentialWithKey,
587 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
588 self.ensure_last_resort();
589 let leaf_node_params = KeyPackageLeafNodeParams {
590 lifetime: self.key_package_lifetime.unwrap_or_default(),
591 capabilities: self.leaf_node_capabilities.unwrap_or_default(),
592 extensions: self.leaf_node_extensions.unwrap_or_default(),
593 };
594 KeyPackage::create(
595 ciphersuite,
596 provider,
597 signer,
598 credential_with_key,
599 self.key_package_extensions.unwrap_or_default(),
600 leaf_node_params,
601 )
602 }
603
604 pub fn build(
606 mut self,
607 ciphersuite: Ciphersuite,
608 provider: &impl OpenMlsProvider,
609 signer: &impl Signer,
610 credential_with_key: CredentialWithKey,
611 ) -> Result<KeyPackageBundle, KeyPackageNewError> {
612 self.ensure_last_resort();
613
614 let leaf_node_params = KeyPackageLeafNodeParams {
615 lifetime: self.key_package_lifetime.unwrap_or_default(),
616 capabilities: self.leaf_node_capabilities.unwrap_or_default(),
617 extensions: self.leaf_node_extensions.unwrap_or_default(),
618 };
619 let KeyPackageCreationResult {
620 key_package,
621 encryption_keypair,
622 init_private_key,
623 } = KeyPackage::create(
624 ciphersuite,
625 provider,
626 signer,
627 credential_with_key,
628 self.key_package_extensions.unwrap_or_default(),
629 leaf_node_params,
630 )?;
631
632 let full_kp = KeyPackageBundle {
635 key_package,
636 private_init_key: init_private_key,
637 private_encryption_key: encryption_keypair.private_key().clone(),
638 };
639 provider
640 .storage()
641 .write_key_package(&full_kp.key_package.hash_ref(provider.crypto())?, &full_kp)
642 .map_err(|_| KeyPackageNewError::StorageError)?;
643
644 Ok(full_kp)
645 }
646
647 #[cfg(feature = "virtual-clients-draft")]
681 pub fn build_vc_batch(
682 self,
683 ciphersuite: Ciphersuite,
684 provider: &impl OpenMlsProvider,
685 signer: &impl Signer,
686 credential_with_key: CredentialWithKey,
687 epoch_id: crate::components::vc_derivation_info::EpochId,
688 count: usize,
689 ) -> Result<VcKeyPackageBatch, KeyPackageNewError> {
690 provider
693 .crypto()
694 .supports(ciphersuite)
695 .map_err(|_| KeyPackageNewError::UnsupportedCiphersuite(ciphersuite))?;
696
697 if count == 0 {
698 return Err(KeyPackageNewError::EmptyBatch);
699 }
700 let mut builder = VcKeyPackageBatchBuilder::with_capacity(provider, epoch_id, count)?;
701 for _ in 0..count {
702 builder.add_key_package(
703 self.clone(),
704 ciphersuite,
705 provider.crypto(),
706 signer,
707 credential_with_key.clone(),
708 )?;
709 }
710 builder.finalize(provider)
711 }
712}
713
714#[derive(Debug, Clone, Serialize, Deserialize)]
720pub struct KeyPackageBundle {
721 pub(crate) key_package: KeyPackage,
722 pub(crate) private_init_key: HpkePrivateKey,
723 pub(crate) private_encryption_key: EncryptionPrivateKey,
724}
725
726impl KeyPackageBundle {
728 pub fn key_package(&self) -> &KeyPackage {
730 &self.key_package
731 }
732
733 pub fn into_key_package(self) -> KeyPackage {
735 self.key_package
736 }
737
738 pub fn init_private_key(&self) -> &HpkePrivateKey {
740 &self.private_init_key
741 }
742
743 pub(crate) fn encryption_key_pair(&self) -> EncryptionKeyPair {
745 EncryptionKeyPair::from((
746 self.key_package.leaf_node().encryption_key().clone(),
747 self.private_encryption_key.clone(),
748 ))
749 }
750}
751
752#[cfg(any(test, feature = "test-utils"))]
753impl KeyPackageBundle {
754 pub fn new(
756 key_package: KeyPackage,
757 private_init_key: HpkePrivateKey,
758 private_encryption_key: EncryptionPrivateKey,
759 ) -> Self {
760 Self {
761 key_package,
762 private_init_key,
763 private_encryption_key,
764 }
765 }
766
767 pub fn encryption_private_key(&self) -> &HpkePrivateKey {
769 self.private_encryption_key.key()
770 }
771}
772
773#[cfg(test)]
774impl KeyPackageBundle {
775 pub(crate) fn generate(
776 provider: &impl OpenMlsProvider,
777 signer: &impl Signer,
778 ciphersuite: Ciphersuite,
779 credential_with_key: CredentialWithKey,
780 ) -> Self {
781 KeyPackage::builder()
782 .build(ciphersuite, provider, signer, credential_with_key)
783 .unwrap()
784 }
785}