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,
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, TlsSerialize)]
177pub struct KeyPackage {
178 payload: KeyPackageTbs,
179 signature: Signature,
180}
181
182impl PartialEq for KeyPackage {
183 fn eq(&self, other: &Self) -> bool {
184 self.payload == other.payload
187 }
188}
189
190impl SignedStruct<KeyPackageTbs> for KeyPackage {
191 fn from_payload(payload: KeyPackageTbs, signature: Signature) -> Self {
192 Self { payload, signature }
193 }
194}
195
196const SIGNATURE_KEY_PACKAGE_LABEL: &str = "KeyPackageTBS";
197
198pub(crate) struct KeyPackageCreationResult {
200 pub key_package: KeyPackage,
201 pub encryption_keypair: EncryptionKeyPair,
202 pub init_private_key: HpkePrivateKey,
203}
204
205#[derive(
207 Debug,
208 Clone,
209 PartialEq,
210 TlsSize,
211 TlsSerialize,
212 Serialize,
213 Deserialize,
214 TlsDeserialize,
215 TlsDeserializeBytes,
216)]
217pub struct InitKey {
218 key: HpkePublicKey,
219}
220
221impl InitKey {
222 pub fn key(&self) -> &HpkePublicKey {
224 &self.key
225 }
226
227 pub fn as_slice(&self) -> &[u8] {
229 self.key.as_slice()
230 }
231}
232
233impl From<Vec<u8>> for InitKey {
234 fn from(key: Vec<u8>) -> Self {
235 Self {
236 key: HpkePublicKey::from(key),
237 }
238 }
239}
240
241impl From<HpkePublicKey> for InitKey {
242 fn from(key: HpkePublicKey) -> Self {
243 Self { key }
244 }
245}
246
247impl KeyPackage {
249 pub fn builder() -> KeyPackageBuilder {
253 KeyPackageBuilder::new()
254 }
255
256 #[allow(clippy::too_many_arguments)]
257 pub(crate) fn create(
259 ciphersuite: Ciphersuite,
260 provider: &impl OpenMlsProvider,
261 signer: &impl Signer,
262 credential_with_key: CredentialWithKey,
263 lifetime: Lifetime,
264 extensions: Extensions,
265 leaf_node_capabilities: Capabilities,
266 leaf_node_extensions: Extensions,
267 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
268 if ciphersuite.signature_algorithm() != signer.signature_scheme() {
269 return Err(KeyPackageNewError::CiphersuiteSignatureSchemeMismatch);
270 }
271
272 let ikm = Secret::random(ciphersuite, provider.rand())
274 .map_err(LibraryError::unexpected_crypto_error)?;
275 let init_key = provider
276 .crypto()
277 .derive_hpke_keypair(ciphersuite.hpke_config(), ikm.as_slice())
278 .map_err(|e| {
279 KeyPackageNewError::LibraryError(LibraryError::unexpected_crypto_error(e))
280 })?;
281 let (key_package, encryption_keypair) = Self::new_from_keys(
282 ciphersuite,
283 provider,
284 signer,
285 credential_with_key,
286 lifetime,
287 extensions,
288 leaf_node_capabilities,
289 leaf_node_extensions,
290 init_key.public.into(),
291 )?;
292
293 Ok(KeyPackageCreationResult {
294 key_package,
295 encryption_keypair,
296 init_private_key: init_key.private,
297 })
298 }
299
300 #[allow(clippy::too_many_arguments)]
310 fn new_from_keys(
311 ciphersuite: Ciphersuite,
312 provider: &impl OpenMlsProvider,
313 signer: &impl Signer,
314 credential_with_key: CredentialWithKey,
315 lifetime: Lifetime,
316 extensions: Extensions,
317 capabilities: Capabilities,
318 leaf_node_extensions: Extensions,
319 init_key: InitKey,
320 ) -> Result<(Self, EncryptionKeyPair), KeyPackageNewError> {
321 let new_leaf_node_params = NewLeafNodeParams {
325 ciphersuite,
326 leaf_node_source: LeafNodeSource::KeyPackage(lifetime),
327 credential_with_key,
328 capabilities,
329 extensions: leaf_node_extensions,
330 tree_info_tbs: TreeInfoTbs::KeyPackage,
331 };
332
333 let (leaf_node, encryption_key_pair) =
334 LeafNode::new(provider, signer, new_leaf_node_params)?;
335
336 let key_package_tbs = KeyPackageTbs {
337 protocol_version: ProtocolVersion::default(),
338 ciphersuite,
339 init_key,
340 leaf_node,
341 extensions,
342 };
343
344 let key_package = key_package_tbs.sign(signer)?;
345
346 Ok((key_package, encryption_key_pair))
347 }
348
349 pub fn extensions(&self) -> &Extensions {
351 &self.payload.extensions
352 }
353
354 pub fn check_extension_support(
357 &self,
358 required_extensions: &[ExtensionType],
359 ) -> Result<(), KeyPackageExtensionSupportError> {
360 for required_extension in required_extensions.iter() {
361 if !self.extensions().contains(*required_extension) {
362 return Err(KeyPackageExtensionSupportError::UnsupportedExtension);
363 }
364 }
365
366 Ok(())
367 }
368
369 pub fn hash_ref(&self, crypto: &impl OpenMlsCrypto) -> Result<KeyPackageRef, LibraryError> {
373 make_key_package_ref(
374 &self
375 .tls_serialize_detached()
376 .map_err(LibraryError::missing_bound_check)?,
377 self.payload.ciphersuite,
378 crypto,
379 )
380 .map_err(LibraryError::unexpected_crypto_error)
381 }
382
383 pub fn ciphersuite(&self) -> Ciphersuite {
385 self.payload.ciphersuite
386 }
387
388 pub fn leaf_node(&self) -> &LeafNode {
390 &self.payload.leaf_node
391 }
392
393 pub fn hpke_init_key(&self) -> &InitKey {
395 &self.payload.init_key
396 }
397
398 pub fn last_resort(&self) -> bool {
400 self.payload.extensions.contains(ExtensionType::LastResort)
401 }
402
403 pub fn life_time(&self) -> &Lifetime {
405 self.payload.leaf_node.life_time().unwrap()
409 }
410}
411
412impl KeyPackage {
414 pub(crate) fn protocol_version(&self) -> ProtocolVersion {
416 self.payload.protocol_version
417 }
418}
419
420#[derive(Default, Debug, Clone, Serialize, Deserialize)]
422pub struct KeyPackageBuilder {
423 key_package_lifetime: Option<Lifetime>,
424 key_package_extensions: Option<Extensions>,
425 leaf_node_capabilities: Option<Capabilities>,
426 leaf_node_extensions: Option<Extensions>,
427 last_resort: bool,
428}
429
430impl KeyPackageBuilder {
431 pub fn new() -> Self {
433 Self {
434 key_package_lifetime: None,
435 key_package_extensions: None,
436 leaf_node_capabilities: None,
437 leaf_node_extensions: None,
438 last_resort: false,
439 }
440 }
441
442 pub fn key_package_lifetime(mut self, lifetime: Lifetime) -> Self {
444 self.key_package_lifetime.replace(lifetime);
445 self
446 }
447
448 pub fn key_package_extensions(mut self, extensions: Extensions) -> Self {
450 self.key_package_extensions.replace(extensions);
451 self
452 }
453
454 pub fn mark_as_last_resort(mut self) -> Self {
456 self.last_resort = true;
457 self
458 }
459
460 pub fn leaf_node_capabilities(mut self, capabilities: Capabilities) -> Self {
462 self.leaf_node_capabilities.replace(capabilities);
463 self
464 }
465
466 pub fn leaf_node_extensions(mut self, extensions: Extensions) -> Self {
468 self.leaf_node_extensions.replace(extensions);
469 self
470 }
471
472 fn ensure_last_resort(&mut self) {
475 if self.last_resort {
476 let last_resort_extension = Extension::LastResort(LastResortExtension::default());
477 if let Some(extensions) = self.key_package_extensions.as_mut() {
478 extensions.add_or_replace(last_resort_extension);
479 } else {
480 self.key_package_extensions = Some(Extensions::single(last_resort_extension));
481 }
482 }
483 }
484
485 #[cfg(test)]
486 pub(crate) fn build_without_storage(
487 mut self,
488 ciphersuite: Ciphersuite,
489 provider: &impl OpenMlsProvider,
490 signer: &impl Signer,
491 credential_with_key: CredentialWithKey,
492 ) -> Result<KeyPackageCreationResult, KeyPackageNewError> {
493 self.ensure_last_resort();
494 KeyPackage::create(
495 ciphersuite,
496 provider,
497 signer,
498 credential_with_key,
499 self.key_package_lifetime.unwrap_or_default(),
500 self.key_package_extensions.unwrap_or_default(),
501 self.leaf_node_capabilities.unwrap_or_default(),
502 self.leaf_node_extensions.unwrap_or_default(),
503 )
504 }
505
506 pub fn build(
508 mut self,
509 ciphersuite: Ciphersuite,
510 provider: &impl OpenMlsProvider,
511 signer: &impl Signer,
512 credential_with_key: CredentialWithKey,
513 ) -> Result<KeyPackageBundle, KeyPackageNewError> {
514 self.ensure_last_resort();
515 let KeyPackageCreationResult {
516 key_package,
517 encryption_keypair,
518 init_private_key,
519 } = KeyPackage::create(
520 ciphersuite,
521 provider,
522 signer,
523 credential_with_key,
524 self.key_package_lifetime.unwrap_or_default(),
525 self.key_package_extensions.unwrap_or_default(),
526 self.leaf_node_capabilities.unwrap_or_default(),
527 self.leaf_node_extensions.unwrap_or_default(),
528 )?;
529
530 let full_kp = KeyPackageBundle {
533 key_package,
534 private_init_key: init_private_key,
535 private_encryption_key: encryption_keypair.private_key().clone(),
536 };
537 provider
538 .storage()
539 .write_key_package(&full_kp.key_package.hash_ref(provider.crypto())?, &full_kp)
540 .map_err(|_| KeyPackageNewError::StorageError)?;
541
542 Ok(full_kp)
543 }
544}
545
546#[derive(Debug, Clone, Serialize, Deserialize)]
552pub struct KeyPackageBundle {
553 pub(crate) key_package: KeyPackage,
554 pub(crate) private_init_key: HpkePrivateKey,
555 pub(crate) private_encryption_key: EncryptionPrivateKey,
556}
557
558impl KeyPackageBundle {
560 pub fn key_package(&self) -> &KeyPackage {
562 &self.key_package
563 }
564
565 pub fn init_private_key(&self) -> &HpkePrivateKey {
567 &self.private_init_key
568 }
569
570 pub(crate) fn encryption_key_pair(&self) -> EncryptionKeyPair {
572 EncryptionKeyPair::from((
573 self.key_package.leaf_node().encryption_key().clone(),
574 self.private_encryption_key.clone(),
575 ))
576 }
577}
578
579#[cfg(any(test, feature = "test-utils"))]
580impl KeyPackageBundle {
581 pub fn new(
583 key_package: KeyPackage,
584 private_init_key: HpkePrivateKey,
585 private_encryption_key: EncryptionPrivateKey,
586 ) -> Self {
587 Self {
588 key_package,
589 private_init_key,
590 private_encryption_key,
591 }
592 }
593
594 pub fn encryption_private_key(&self) -> &HpkePrivateKey {
596 self.private_encryption_key.key()
597 }
598}
599
600#[cfg(test)]
601impl KeyPackageBundle {
602 pub(crate) fn generate(
603 provider: &impl OpenMlsProvider,
604 signer: &impl Signer,
605 ciphersuite: Ciphersuite,
606 credential_with_key: CredentialWithKey,
607 ) -> Self {
608 KeyPackage::builder()
609 .build(ciphersuite, provider, signer, credential_with_key)
610 .unwrap()
611 }
612}