1use crate::{
92 ciphersuite::{
93 hash_ref::{make_key_package_ref, KeyPackageRef},
94 signable::*,
95 *,
96 },
97 credentials::*,
98 error::LibraryError,
99 extensions::{
100 errors::InvalidExtensionError, Extension, ExtensionType, Extensions, LastResortExtension,
101 },
102 storage::OpenMlsProvider,
103 treesync::{
104 node::{
105 encryption_keys::{EncryptionKeyPair, EncryptionPrivateKey},
106 leaf_node::{Capabilities, LeafNodeSource, NewLeafNodeParams, TreeInfoTbs},
107 },
108 LeafNode,
109 },
110 versions::ProtocolVersion,
111};
112use openmls_traits::{
113 crypto::OpenMlsCrypto, signatures::Signer, storage::StorageProvider, types::Ciphersuite,
114};
115use serde::{Deserialize, Serialize};
116use tls_codec::{
117 Serialize as TlsSerializeTrait, TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSize,
118};
119
120use errors::*;
122
123pub mod errors;
125pub mod key_package_in;
126
127mod lifetime;
128
129#[cfg(test)]
131pub(crate) mod tests;
132
133pub use key_package_in::KeyPackageIn;
135pub use lifetime::Lifetime;
136
137#[derive(Debug, Clone, PartialEq, TlsSize, TlsSerialize, Serialize, Deserialize)]
151struct KeyPackageTbs {
152 protocol_version: ProtocolVersion,
153 ciphersuite: Ciphersuite,
154 init_key: InitKey,
155 leaf_node: LeafNode,
156 extensions: Extensions,
157}
158
159impl Signable for KeyPackageTbs {
160 type SignedOutput = KeyPackage;
161
162 fn unsigned_payload(&self) -> Result<Vec<u8>, tls_codec::Error> {
163 self.tls_serialize_detached()
164 }
165
166 fn label(&self) -> &str {
167 SIGNATURE_KEY_PACKAGE_LABEL
168 }
169}
170
171impl From<KeyPackage> for KeyPackageTbs {
172 fn from(kp: KeyPackage) -> Self {
173 kp.payload
174 }
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize, TlsSize, TlsSerialize)]
179pub struct KeyPackage {
180 payload: KeyPackageTbs,
181 signature: Signature,
182}
183
184impl PartialEq for KeyPackage {
185 fn eq(&self, other: &Self) -> bool {
186 self.payload == other.payload
189 }
190}
191
192impl SignedStruct<KeyPackageTbs> for KeyPackage {
193 fn from_payload(payload: KeyPackageTbs, signature: Signature) -> Self {
194 Self { payload, signature }
195 }
196}
197
198const SIGNATURE_KEY_PACKAGE_LABEL: &str = "KeyPackageTBS";
199
200pub(crate) struct KeyPackageCreationResult {
202 pub key_package: KeyPackage,
203 pub encryption_keypair: EncryptionKeyPair,
204 pub init_private_key: HpkePrivateKey,
205}
206
207#[derive(
209 Debug,
210 Clone,
211 PartialEq,
212 TlsSize,
213 TlsSerialize,
214 Serialize,
215 Deserialize,
216 TlsDeserialize,
217 TlsDeserializeBytes,
218)]
219pub struct InitKey {
220 key: HpkePublicKey,
221}
222
223impl InitKey {
224 pub fn key(&self) -> &HpkePublicKey {
226 &self.key
227 }
228
229 pub fn as_slice(&self) -> &[u8] {
231 self.key.as_slice()
232 }
233}
234
235impl From<Vec<u8>> for InitKey {
236 fn from(key: Vec<u8>) -> Self {
237 Self {
238 key: HpkePublicKey::from(key),
239 }
240 }
241}
242
243impl From<HpkePublicKey> for InitKey {
244 fn from(key: HpkePublicKey) -> Self {
245 Self { key }
246 }
247}
248
249impl KeyPackage {
251 pub fn builder() -> KeyPackageBuilder {
255 KeyPackageBuilder::new()
256 }
257
258 #[allow(clippy::too_many_arguments)]
259 pub(crate) fn create(
261 ciphersuite: Ciphersuite,
262 provider: &impl OpenMlsProvider,
263 signer: &impl Signer,
264 credential_with_key: CredentialWithKey,
265 lifetime: Lifetime,
266 extensions: Extensions,
267 leaf_node_capabilities: Capabilities,
268 leaf_node_extensions: Extensions,
269 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
270 if ciphersuite.signature_algorithm() != signer.signature_scheme() {
271 return Err(KeyPackageNewError::CiphersuiteSignatureSchemeMismatch);
272 }
273
274 let ikm = Secret::random(ciphersuite, provider.rand())
276 .map_err(LibraryError::unexpected_crypto_error)?;
277 let init_key = provider
278 .crypto()
279 .derive_hpke_keypair(ciphersuite.hpke_config(), ikm.as_slice())
280 .map_err(|e| {
281 KeyPackageNewError::LibraryError(LibraryError::unexpected_crypto_error(e))
282 })?;
283 let (key_package, encryption_keypair) = Self::new_from_keys(
284 ciphersuite,
285 provider,
286 signer,
287 credential_with_key,
288 lifetime,
289 extensions,
290 leaf_node_capabilities,
291 leaf_node_extensions,
292 init_key.public.into(),
293 )?;
294
295 Ok(KeyPackageCreationResult {
296 key_package,
297 encryption_keypair,
298 init_private_key: init_key.private,
299 })
300 }
301
302 #[allow(clippy::too_many_arguments)]
312 fn new_from_keys(
313 ciphersuite: Ciphersuite,
314 provider: &impl OpenMlsProvider,
315 signer: &impl Signer,
316 credential_with_key: CredentialWithKey,
317 lifetime: Lifetime,
318 extensions: Extensions,
319 capabilities: Capabilities,
320 leaf_node_extensions: Extensions,
321 init_key: InitKey,
322 ) -> Result<(Self, EncryptionKeyPair), KeyPackageNewError> {
323 let new_leaf_node_params = NewLeafNodeParams {
327 ciphersuite,
328 leaf_node_source: LeafNodeSource::KeyPackage(lifetime),
329 credential_with_key,
330 capabilities,
331 extensions: leaf_node_extensions,
332 tree_info_tbs: TreeInfoTbs::KeyPackage,
333 };
334
335 let (leaf_node, encryption_key_pair) =
336 LeafNode::new(provider, signer, new_leaf_node_params)?;
337
338 let key_package_tbs = KeyPackageTbs {
339 protocol_version: ProtocolVersion::default(),
340 ciphersuite,
341 init_key,
342 leaf_node,
343 extensions,
344 };
345
346 let key_package = key_package_tbs.sign(signer)?;
347
348 Ok((key_package, encryption_key_pair))
349 }
350
351 pub fn extensions(&self) -> &Extensions {
353 &self.payload.extensions
354 }
355
356 pub fn check_extension_support(
359 &self,
360 required_extensions: &[ExtensionType],
361 ) -> Result<(), KeyPackageExtensionSupportError> {
362 for required_extension in required_extensions.iter() {
363 if !self.extensions().contains(*required_extension) {
364 return Err(KeyPackageExtensionSupportError::UnsupportedExtension);
365 }
366 }
367
368 Ok(())
369 }
370
371 pub fn hash_ref(&self, crypto: &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError> {
375 make_key_package_ref(
376 &self
377 .tls_serialize_detached()
378 .map_err(LibraryError::missing_bound_check)?,
379 self.payload.ciphersuite,
380 crypto,
381 )
382 .map_err(LibraryError::unexpected_crypto_error)
383 }
384
385 pub fn ciphersuite(&self) -> Ciphersuite {
387 self.payload.ciphersuite
388 }
389
390 pub fn leaf_node(&self) -> &LeafNode {
392 &self.payload.leaf_node
393 }
394
395 pub fn hpke_init_key(&self) -> &InitKey {
397 &self.payload.init_key
398 }
399
400 pub fn last_resort(&self) -> bool {
402 self.payload.extensions.contains(ExtensionType::LastResort)
403 }
404
405 pub fn life_time(&self) -> &Lifetime {
407 self.payload.leaf_node.life_time().unwrap()
411 }
412}
413
414impl KeyPackage {
416 pub(crate) fn protocol_version(&self) -> ProtocolVersion {
418 self.payload.protocol_version
419 }
420}
421
422#[derive(Default, Debug, Clone, Serialize, Deserialize)]
424pub struct KeyPackageBuilder {
425 key_package_lifetime: Option<Lifetime>,
426 key_package_extensions: Option<Extensions>,
427 leaf_node_capabilities: Option<Capabilities>,
428 leaf_node_extensions: Option<Extensions>,
429 last_resort: bool,
430}
431
432impl KeyPackageBuilder {
433 pub fn new() -> Self {
435 Self {
436 key_package_lifetime: None,
437 key_package_extensions: None,
438 leaf_node_capabilities: None,
439 leaf_node_extensions: None,
440 last_resort: false,
441 }
442 }
443
444 pub fn key_package_lifetime(mut self, lifetime: Lifetime) -> Self {
446 self.key_package_lifetime.replace(lifetime);
447 self
448 }
449
450 pub fn key_package_extensions(mut self, extensions: Extensions) -> Self {
452 self.key_package_extensions.replace(extensions);
453 self
454 }
455
456 pub fn mark_as_last_resort(mut self) -> Self {
458 self.last_resort = true;
459 self
460 }
461
462 pub fn leaf_node_capabilities(mut self, capabilities: Capabilities) -> Self {
464 self.leaf_node_capabilities.replace(capabilities);
465 self
466 }
467
468 pub fn leaf_node_extensions(
472 mut self,
473 extensions: Extensions,
474 ) -> Result<Self, InvalidExtensionError> {
475 extensions.validate_extension_types_for_leaf_node()?;
477 self.leaf_node_extensions.replace(extensions);
478
479 Ok(self)
480 }
481
482 fn ensure_last_resort(&mut self) {
485 if self.last_resort {
486 let last_resort_extension = Extension::LastResort(LastResortExtension::default());
487 if let Some(extensions) = self.key_package_extensions.as_mut() {
488 extensions.add_or_replace(last_resort_extension);
489 } else {
490 self.key_package_extensions = Some(Extensions::single(last_resort_extension));
491 }
492 }
493 }
494
495 #[cfg(test)]
496 pub(crate) fn build_without_storage(
497 mut self,
498 ciphersuite: Ciphersuite,
499 provider: &impl OpenMlsProvider,
500 signer: &impl Signer,
501 credential_with_key: CredentialWithKey,
502 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
503 self.ensure_last_resort();
504 KeyPackage::create(
505 ciphersuite,
506 provider,
507 signer,
508 credential_with_key,
509 self.key_package_lifetime.unwrap_or_default(),
510 self.key_package_extensions.unwrap_or_default(),
511 self.leaf_node_capabilities.unwrap_or_default(),
512 self.leaf_node_extensions.unwrap_or_default(),
513 )
514 }
515
516 pub fn build(
518 mut self,
519 ciphersuite: Ciphersuite,
520 provider: &impl OpenMlsProvider,
521 signer: &impl Signer,
522 credential_with_key: CredentialWithKey,
523 ) -> Result<KeyPackageBundle, KeyPackageNewError> {
524 self.ensure_last_resort();
525 let KeyPackageCreationResult {
526 key_package,
527 encryption_keypair,
528 init_private_key,
529 } = KeyPackage::create(
530 ciphersuite,
531 provider,
532 signer,
533 credential_with_key,
534 self.key_package_lifetime.unwrap_or_default(),
535 self.key_package_extensions.unwrap_or_default(),
536 self.leaf_node_capabilities.unwrap_or_default(),
537 self.leaf_node_extensions.unwrap_or_default(),
538 )?;
539
540 let full_kp = KeyPackageBundle {
543 key_package,
544 private_init_key: init_private_key,
545 private_encryption_key: encryption_keypair.private_key().clone(),
546 };
547 provider
548 .storage()
549 .write_key_package(&full_kp.key_package.hash_ref(provider.crypto())?, &full_kp)
550 .map_err(|_| KeyPackageNewError::StorageError)?;
551
552 Ok(full_kp)
553 }
554}
555
556#[derive(Debug, Clone, Serialize, Deserialize)]
562pub struct KeyPackageBundle {
563 pub(crate) key_package: KeyPackage,
564 pub(crate) private_init_key: HpkePrivateKey,
565 pub(crate) private_encryption_key: EncryptionPrivateKey,
566}
567
568impl KeyPackageBundle {
570 pub fn key_package(&self) -> &KeyPackage {
572 &self.key_package
573 }
574
575 pub fn init_private_key(&self) -> &HpkePrivateKey {
577 &self.private_init_key
578 }
579
580 pub(crate) fn encryption_key_pair(&self) -> EncryptionKeyPair {
582 EncryptionKeyPair::from((
583 self.key_package.leaf_node().encryption_key().clone(),
584 self.private_encryption_key.clone(),
585 ))
586 }
587}
588
589#[cfg(any(test, feature = "test-utils"))]
590impl KeyPackageBundle {
591 pub fn new(
593 key_package: KeyPackage,
594 private_init_key: HpkePrivateKey,
595 private_encryption_key: EncryptionPrivateKey,
596 ) -> Self {
597 Self {
598 key_package,
599 private_init_key,
600 private_encryption_key,
601 }
602 }
603
604 pub fn encryption_private_key(&self) -> &HpkePrivateKey {
606 self.private_encryption_key.key()
607 }
608}
609
610#[cfg(test)]
611impl KeyPackageBundle {
612 pub(crate) fn generate(
613 provider: &impl OpenMlsProvider,
614 signer: &impl Signer,
615 ciphersuite: Ciphersuite,
616 credential_with_key: CredentialWithKey,
617 ) -> Self {
618 KeyPackage::builder()
619 .build(ciphersuite, provider, signer, credential_with_key)
620 .unwrap()
621 }
622}