Skip to main content

memberlist_core/
keyring.rs

1use std::iter::once;
2
3use indexmap::IndexSet;
4use memberlist_proto::SecretKey;
5use parking_lot::RwLock;
6use triomphe::Arc;
7
8/// Error for [`Keyring`]
9#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
10pub enum KeyringError {
11  /// Secret key is not in the keyring
12  #[error("secret key is not in the keyring")]
13  SecretKeyNotFound,
14  /// Removing the primary key is not allowed
15  #[error("removing the primary key is not allowed")]
16  RemovePrimaryKey,
17}
18
19#[derive(Debug)]
20pub(super) struct KeyringInner {
21  pub(super) primary_key: SecretKey,
22  pub(super) keys: IndexSet<SecretKey>,
23}
24
25/// A lock-free and thread-safe container for a set of encryption keys.
26/// The keyring contains all key data used internally by memberlist.
27///
28/// If creating a keyring with multiple keys, one key must be designated
29/// primary by passing it as the primaryKey. If the primaryKey does not exist in
30/// the list of secondary keys, it will be automatically added at position 0.
31#[derive(Debug, Clone)]
32#[repr(transparent)]
33pub struct Keyring {
34  pub(super) inner: Arc<RwLock<KeyringInner>>,
35}
36
37impl Keyring {
38  /// Constructs a new container for a primary key. The
39  /// keyring contains all key data used internally by memberlist.
40  ///
41  /// If only a primary key is passed, then it will be automatically added to the
42  /// keyring.
43  ///
44  /// A key should be either 16, 24, or 32 bytes to select AES-128,
45  /// AES-192, or AES-256.
46  #[inline]
47  pub fn new(primary_key: SecretKey) -> Self {
48    Self {
49      inner: Arc::new(RwLock::new(KeyringInner {
50        primary_key,
51        keys: IndexSet::new(),
52      })),
53    }
54  }
55
56  /// Constructs a new container for a set of encryption keys. The
57  /// keyring contains all key data used internally by memberlist.
58  ///
59  /// If only a primary key is passed, then it will be automatically added to the
60  /// keyring. If creating a keyring with multiple keys, one key must be designated
61  /// primary by passing it as the primaryKey. If the primaryKey does not exist in
62  /// the list of secondary keys, it will be automatically added.
63  ///
64  /// A key should be either 16, 24, or 32 bytes to select AES-128,
65  /// AES-192, or AES-256.
66  #[inline]
67  pub fn with_keys(
68    primary_key: SecretKey,
69    keys: impl Iterator<Item = impl Into<SecretKey>>,
70  ) -> Self {
71    if keys.size_hint().0 != 0 {
72      return Self {
73        inner: Arc::new(RwLock::new(KeyringInner {
74          primary_key,
75          keys: keys
76            .filter_map(|k| {
77              let k = k.into();
78              if k == primary_key { None } else { Some(k) }
79            })
80            .collect(),
81        })),
82      };
83    }
84
85    Self::new(primary_key)
86  }
87
88  /// Returns the key on the ring at position 0. This is the key used
89  /// for encrypting messages, and is the first key tried for decrypting messages.
90  #[inline]
91  pub fn primary_key(&self) -> SecretKey {
92    self.inner.read().primary_key
93  }
94
95  /// Drops a key from the keyring. This will return an error if the key
96  /// requested for removal is currently at position 0 (primary key).
97  #[inline]
98  pub fn remove(&self, key: &[u8]) -> Result<(), KeyringError> {
99    let mut inner = self.inner.write();
100    if &inner.primary_key == key {
101      return Err(KeyringError::RemovePrimaryKey);
102    }
103    inner.keys.shift_remove(key);
104    Ok(())
105  }
106
107  /// Install a new key on the ring. Adding a key to the ring will make
108  /// it available for use in decryption. If the key already exists on the ring,
109  /// this function will just return noop.
110  ///
111  /// key should be either 16, 24, or 32 bytes to select AES-128,
112  /// AES-192, or AES-256.
113  #[inline]
114  pub fn insert(&self, key: SecretKey) {
115    self.inner.write().keys.insert(key);
116  }
117
118  /// Changes the key used to encrypt messages. This is the only key used to
119  /// encrypt messages, so peers should know this key before this method is called.
120  #[inline]
121  pub fn use_key(&self, key_data: &[u8]) -> Result<(), KeyringError> {
122    let mut inner = self.inner.write();
123    if key_data == inner.primary_key.as_ref() {
124      return Ok(());
125    }
126
127    // Try to find the key to set as primary
128    let Some(&key) = inner.keys.get(key_data) else {
129      return Err(KeyringError::SecretKeyNotFound);
130    };
131
132    let old_pk = inner.primary_key;
133    inner.keys.insert(old_pk);
134    inner.primary_key = key;
135    inner.keys.swap_remove(key_data);
136    Ok(())
137  }
138
139  /// Returns the current set of keys on the ring.
140  #[inline]
141  pub fn keys(&self) -> impl Iterator<Item = SecretKey> + Send + 'static {
142    let inner = self.inner.read();
143
144    // we must promise the first key is the primary key
145    // so that when decrypt messages, we can try the primary key first
146    once(inner.primary_key).chain(inner.keys.clone())
147  }
148}
149
150#[cfg(feature = "serde")]
151const _: () = {
152  use memberlist_proto::SecretKeys;
153  use serde::{Deserialize, Serialize};
154
155  impl Serialize for Keyring {
156    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
157    where
158      S: serde::Serializer,
159    {
160      let keys = self.keys();
161      serializer.collect_seq(keys)
162    }
163  }
164
165  impl<'de> Deserialize<'de> for Keyring {
166    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
167    where
168      D: serde::Deserializer<'de>,
169    {
170      let keys = SecretKeys::deserialize(deserializer)?;
171      if keys.is_empty() {
172        return Err(serde::de::Error::custom(
173          "keyring must have at least one key",
174        ));
175      }
176
177      Ok(Keyring::with_keys(keys[0], keys.into_iter().skip(1)))
178    }
179  }
180};
181
182#[cfg(test)]
183mod tests {
184  use super::*;
185
186  const TEST_KEYS: &[SecretKey] = &[
187    SecretKey::Aes128([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]),
188    SecretKey::Aes128([15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]),
189    SecretKey::Aes128([8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7]),
190  ];
191
192  #[test]
193  fn test_primary_only() {
194    let keyring = Keyring::new(TEST_KEYS[1]);
195    assert_eq!(keyring.keys().collect::<Vec<_>>().len(), 1);
196  }
197
198  #[test]
199  fn test_get_primary_key() {
200    let keyring = Keyring::with_keys(TEST_KEYS[1], TEST_KEYS.iter().copied());
201    assert_eq!(keyring.primary_key().as_ref(), TEST_KEYS[1].as_ref());
202  }
203
204  #[test]
205  fn test_insert_remove_use() {
206    let keyring = Keyring::new(TEST_KEYS[1]);
207
208    // Use non-existent key throws error
209    keyring.use_key(&TEST_KEYS[2]).unwrap_err();
210
211    // Add key to ring
212    keyring.insert(TEST_KEYS[2]);
213    assert_eq!(keyring.inner.read().keys.len() + 1, 2);
214    assert_eq!(keyring.keys().next().unwrap(), TEST_KEYS[1]);
215
216    // Use key that exists should succeed
217    keyring.use_key(&TEST_KEYS[2]).unwrap();
218    assert_eq!(keyring.keys().next().unwrap(), TEST_KEYS[2]);
219
220    let primary_key = keyring.primary_key();
221    assert_eq!(primary_key.as_ref(), TEST_KEYS[2].as_ref());
222
223    // Removing primary key should fail
224    keyring.remove(&TEST_KEYS[2]).unwrap_err();
225
226    // Removing non-primary key should succeed
227    keyring.remove(&TEST_KEYS[1]).unwrap();
228    assert_eq!(keyring.inner.read().keys.len() + 1, 1);
229  }
230}