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
127#[cfg(test)]
129pub(crate) mod tests;
130
131pub use key_package_in::KeyPackageIn;
133pub use lifetime::Lifetime;
134
135#[derive(Debug, Clone, PartialEq, TlsSize, TlsSerialize, Serialize, Deserialize)]
149struct KeyPackageTbs {
150 protocol_version: ProtocolVersion,
151 ciphersuite: Ciphersuite,
152 init_key: InitKey,
153 leaf_node: LeafNode,
154 extensions: Extensions<KeyPackage>,
155}
156
157impl Signable for KeyPackageTbs {
158 type SignedOutput = KeyPackage;
159
160 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
161 self.tls_serialize_detached()
162 }
163
164 fn label(&self) -> &str {
165 SIGNATURE_KEY_PACKAGE_LABEL
166 }
167}
168
169impl From<KeyPackage> for KeyPackageTbs {
170 fn from(kp: KeyPackage) -> Self {
171 kp.payload
172 }
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize, TlsSize)]
177pub struct KeyPackage {
178 payload: KeyPackageTbs,
179 signature: Signature,
180 #[serde(skip)]
181 #[tls_codec(skip)]
182 serialized_payload: Option<Vec<u8>>,
183}
184
185impl TlsSerializeTrait for KeyPackage {
186 fn tls_serialize<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, tls_codec::Error> {
187 let mut written = 0;
188 if let Some(ref bytes) = self.serialized_payload {
189 written += writer.write(bytes)?;
190 } else {
191 written += self.payload.tls_serialize(writer)?;
192 }
193 written += self.signature.tls_serialize(writer)?;
194 Ok(written)
195 }
196}
197
198impl PartialEq for KeyPackage {
199 fn eq(&self, other: &Self) -> bool {
200 self.payload == other.payload
203 }
204}
205
206impl SignedStruct<KeyPackageTbs> for KeyPackage {
207 fn from_payload(
208 payload: KeyPackageTbs,
209 signature: Signature,
210 serialized_payload: Vec<u8>,
211 ) -> Self {
212 Self {
213 payload,
214 signature,
215 serialized_payload: Some(serialized_payload),
216 }
217 }
218}
219
220const SIGNATURE_KEY_PACKAGE_LABEL: &str = "KeyPackageTBS";
221
222pub(crate) struct KeyPackageCreationResult {
224 pub key_package: KeyPackage,
225 pub encryption_keypair: EncryptionKeyPair,
226 pub init_private_key: HpkePrivateKey,
227}
228
229#[derive(
231 Debug,
232 Clone,
233 PartialEq,
234 TlsSize,
235 TlsSerialize,
236 Serialize,
237 Deserialize,
238 TlsDeserialize,
239 TlsDeserializeBytes,
240)]
241pub struct InitKey {
242 key: HpkePublicKey,
243}
244
245impl InitKey {
246 pub fn key(&self) -> &HpkePublicKey {
248 &self.key
249 }
250
251 pub fn as_slice(&self) -> &[u8] {
253 self.key.as_slice()
254 }
255}
256
257impl From<Vec<u8>> for InitKey {
258 fn from(key: Vec<u8>) -> Self {
259 Self {
260 key: HpkePublicKey::from(key),
261 }
262 }
263}
264
265impl From<HpkePublicKey> for InitKey {
266 fn from(key: HpkePublicKey) -> Self {
267 Self { key }
268 }
269}
270
271impl KeyPackage {
273 pub fn builder() -> KeyPackageBuilder {
277 KeyPackageBuilder::new()
278 }
279
280 #[allow(clippy::too_many_arguments)]
281 pub(crate) fn create(
283 ciphersuite: Ciphersuite,
284 provider: &impl OpenMlsProvider,
285 signer: &impl Signer,
286 credential_with_key: CredentialWithKey,
287 lifetime: Lifetime,
288 extensions: Extensions<KeyPackage>,
289 leaf_node_capabilities: Capabilities,
290 leaf_node_extensions: Extensions<LeafNode>,
291 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
292 if ciphersuite.signature_algorithm() != signer.signature_scheme() {
293 return Err(KeyPackageNewError::CiphersuiteSignatureSchemeMismatch);
294 }
295
296 let ikm = Secret::random(ciphersuite, provider.rand())
298 .map_err(LibraryError::unexpected_crypto_error)?;
299 let init_key = provider
300 .crypto()
301 .derive_hpke_keypair(ciphersuite.hpke_config(), ikm.as_slice())
302 .map_err(|e| {
303 KeyPackageNewError::LibraryError(LibraryError::unexpected_crypto_error(e))
304 })?;
305 let (key_package, encryption_keypair) = Self::new_from_keys(
306 ciphersuite,
307 provider,
308 signer,
309 credential_with_key,
310 lifetime,
311 extensions,
312 leaf_node_capabilities,
313 leaf_node_extensions,
314 init_key.public.into(),
315 )?;
316
317 Ok(KeyPackageCreationResult {
318 key_package,
319 encryption_keypair,
320 init_private_key: init_key.private,
321 })
322 }
323
324 #[allow(clippy::too_many_arguments)]
334 fn new_from_keys(
335 ciphersuite: Ciphersuite,
336 provider: &impl OpenMlsProvider,
337 signer: &impl Signer,
338 credential_with_key: CredentialWithKey,
339 lifetime: Lifetime,
340 extensions: Extensions<KeyPackage>,
341 capabilities: Capabilities,
342 leaf_node_extensions: Extensions<LeafNode>,
343 init_key: InitKey,
344 ) -> Result<(Self, EncryptionKeyPair), KeyPackageNewError> {
345 let new_leaf_node_params = NewLeafNodeParams {
349 ciphersuite,
350 leaf_node_source: LeafNodeSource::KeyPackage(lifetime),
351 credential_with_key,
352 capabilities,
353 extensions: leaf_node_extensions,
354 tree_info_tbs: TreeInfoTbs::KeyPackage,
355 };
356
357 let (leaf_node, encryption_key_pair) =
358 LeafNode::new(provider, signer, new_leaf_node_params)?;
359
360 let key_package_tbs = KeyPackageTbs {
361 protocol_version: ProtocolVersion::default(),
362 ciphersuite,
363 init_key,
364 leaf_node,
365 extensions,
366 };
367
368 let key_package = key_package_tbs.sign(signer)?;
369
370 Ok((key_package, encryption_key_pair))
371 }
372
373 pub fn extensions(&self) -> &Extensions<KeyPackage> {
375 &self.payload.extensions
376 }
377
378 pub fn check_extension_support(
381 &self,
382 required_extensions: &[ExtensionType],
383 ) -> Result<(), KeyPackageExtensionSupportError> {
384 for required_extension in required_extensions.iter() {
385 if !self.extensions().contains(*required_extension) {
386 return Err(KeyPackageExtensionSupportError::UnsupportedExtension);
387 }
388 }
389
390 Ok(())
391 }
392
393 pub fn hash_ref(&self, crypto: &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError> {
397 make_key_package_ref(
398 &self
399 .tls_serialize_detached()
400 .map_err(LibraryError::missing_bound_check)?,
401 self.payload.ciphersuite,
402 crypto,
403 )
404 .map_err(LibraryError::unexpected_crypto_error)
405 }
406
407 pub fn ciphersuite(&self) -> Ciphersuite {
409 self.payload.ciphersuite
410 }
411
412 pub fn leaf_node(&self) -> &LeafNode {
414 &self.payload.leaf_node
415 }
416
417 pub fn hpke_init_key(&self) -> &InitKey {
419 &self.payload.init_key
420 }
421
422 pub fn last_resort(&self) -> bool {
424 self.payload.extensions.contains(ExtensionType::LastResort)
425 }
426
427 pub fn life_time(&self) -> &Lifetime {
429 self.payload.leaf_node.life_time().unwrap()
433 }
434}
435
436impl KeyPackage {
438 pub(crate) fn protocol_version(&self) -> ProtocolVersion {
440 self.payload.protocol_version
441 }
442}
443
444#[derive(Default, Debug, Clone, Serialize, Deserialize)]
446pub struct KeyPackageBuilder {
447 key_package_lifetime: Option<Lifetime>,
448 key_package_extensions: Option<Extensions<KeyPackage>>,
449 leaf_node_capabilities: Option<Capabilities>,
450 leaf_node_extensions: Option<Extensions<LeafNode>>,
451 last_resort: bool,
452}
453
454impl KeyPackageBuilder {
455 pub fn new() -> Self {
457 Self {
458 key_package_lifetime: None,
459 key_package_extensions: None,
460 leaf_node_capabilities: None,
461 leaf_node_extensions: None,
462 last_resort: false,
463 }
464 }
465
466 pub fn key_package_lifetime(mut self, lifetime: Lifetime) -> Self {
468 self.key_package_lifetime.replace(lifetime);
469 self
470 }
471
472 pub fn key_package_extensions(mut self, extensions: Extensions<KeyPackage>) -> Self {
474 self.key_package_extensions.replace(extensions);
475 self
476 }
477
478 pub fn mark_as_last_resort(mut self) -> Self {
480 self.last_resort = true;
481 self
482 }
483
484 pub fn leaf_node_capabilities(mut self, capabilities: Capabilities) -> Self {
486 self.leaf_node_capabilities.replace(capabilities);
487 self
488 }
489
490 pub fn leaf_node_extensions(mut self, extensions: Extensions<LeafNode>) -> Self {
494 self.leaf_node_extensions.replace(extensions);
495 self
496 }
497
498 fn ensure_last_resort(&mut self) {
501 if self.last_resort {
502 let last_resort_extension = Extension::LastResort(LastResortExtension::default());
503 if let Some(extensions) = self.key_package_extensions.as_mut() {
504 extensions
505 .add_or_replace(last_resort_extension)
506 .expect("LastResort extensions are allowed in key packages");
507 } else {
508 self.key_package_extensions = Some(
509 Extensions::single(last_resort_extension)
510 .expect("LastResort extensions are allowed in key packages"),
511 );
512 }
513 }
514 }
515
516 #[cfg(test)]
517 pub(crate) fn build_without_storage(
518 mut self,
519 ciphersuite: Ciphersuite,
520 provider: &impl OpenMlsProvider,
521 signer: &impl Signer,
522 credential_with_key: CredentialWithKey,
523 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
524 self.ensure_last_resort();
525 KeyPackage::create(
526 ciphersuite,
527 provider,
528 signer,
529 credential_with_key,
530 self.key_package_lifetime.unwrap_or_default(),
531 self.key_package_extensions.unwrap_or_default(),
532 self.leaf_node_capabilities.unwrap_or_default(),
533 self.leaf_node_extensions.unwrap_or_default(),
534 )
535 }
536
537 pub fn build(
539 mut self,
540 ciphersuite: Ciphersuite,
541 provider: &impl OpenMlsProvider,
542 signer: &impl Signer,
543 credential_with_key: CredentialWithKey,
544 ) -> Result<KeyPackageBundle, KeyPackageNewError> {
545 self.ensure_last_resort();
546
547 let KeyPackageCreationResult {
548 key_package,
549 encryption_keypair,
550 init_private_key,
551 } = KeyPackage::create(
552 ciphersuite,
553 provider,
554 signer,
555 credential_with_key,
556 self.key_package_lifetime.unwrap_or_default(),
557 self.key_package_extensions.unwrap_or_default(),
558 self.leaf_node_capabilities.unwrap_or_default(),
559 self.leaf_node_extensions.unwrap_or_default(),
560 )?;
561
562 let full_kp = KeyPackageBundle {
565 key_package,
566 private_init_key: init_private_key,
567 private_encryption_key: encryption_keypair.private_key().clone(),
568 };
569 provider
570 .storage()
571 .write_key_package(&full_kp.key_package.hash_ref(provider.crypto())?, &full_kp)
572 .map_err(|_| KeyPackageNewError::StorageError)?;
573
574 Ok(full_kp)
575 }
576}
577
578#[derive(Debug, Clone, Serialize, Deserialize)]
584pub struct KeyPackageBundle {
585 pub(crate) key_package: KeyPackage,
586 pub(crate) private_init_key: HpkePrivateKey,
587 pub(crate) private_encryption_key: EncryptionPrivateKey,
588}
589
590impl KeyPackageBundle {
592 pub fn key_package(&self) -> &KeyPackage {
594 &self.key_package
595 }
596
597 pub fn init_private_key(&self) -> &HpkePrivateKey {
599 &self.private_init_key
600 }
601
602 pub(crate) fn encryption_key_pair(&self) -> EncryptionKeyPair {
604 EncryptionKeyPair::from((
605 self.key_package.leaf_node().encryption_key().clone(),
606 self.private_encryption_key.clone(),
607 ))
608 }
609}
610
611#[cfg(any(test, feature = "test-utils"))]
612impl KeyPackageBundle {
613 pub fn new(
615 key_package: KeyPackage,
616 private_init_key: HpkePrivateKey,
617 private_encryption_key: EncryptionPrivateKey,
618 ) -> Self {
619 Self {
620 key_package,
621 private_init_key,
622 private_encryption_key,
623 }
624 }
625
626 pub fn encryption_private_key(&self) -> &HpkePrivateKey {
628 self.private_encryption_key.key()
629 }
630}
631
632#[cfg(test)]
633impl KeyPackageBundle {
634 pub(crate) fn generate(
635 provider: &impl OpenMlsProvider,
636 signer: &impl Signer,
637 ciphersuite: Ciphersuite,
638 credential_with_key: CredentialWithKey,
639 ) -> Self {
640 KeyPackage::builder()
641 .build(ciphersuite, provider, signer, credential_with_key)
642 .unwrap()
643 }
644}