tink_core/keyset/
manager.rs

1// Copyright 2020 The Tink-Rust Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15////////////////////////////////////////////////////////////////////////////////
16
17//! Utilities for managing keys in a keyset.
18
19use crate::{utils::wrap_err, KeyId, TinkError};
20use rand::Rng;
21use std::convert::TryFrom;
22use tink_proto::{KeyStatusType, OutputPrefixType};
23
24/// Manager manages a [`Keyset`](tink_proto::Keyset)-proto, with convenience methods that rotate,
25/// disable, enable or destroy keys. Note: It is not thread-safe.
26#[derive(Default)]
27pub struct Manager {
28    ks: tink_proto::Keyset,
29}
30
31impl Manager {
32    /// Create a new instance with an empty [`Keyset`](tink_proto::Keyset).
33    pub fn new() -> Self {
34        Self {
35            ks: tink_proto::Keyset::default(),
36        }
37    }
38
39    /// Create a new instance from the given [`Handle`](super::Handle).
40    pub fn new_from_handle(kh: super::Handle) -> Self {
41        Self {
42            ks: kh.into_inner(),
43        }
44    }
45
46    /// Generate a fresh key using the given key template and set the new key as the primary key.
47    /// The key that was primary prior to rotation remains `Enabled`. Returns the key ID of the
48    /// new primary key.
49    pub fn rotate(&mut self, kt: &tink_proto::KeyTemplate) -> Result<KeyId, TinkError> {
50        self.add(kt, true)
51    }
52
53    /// Generate a fresh key using the given key template, and optionally set the new key as the
54    /// primary key. Returns the key ID of the added key.
55    pub fn add(
56        &mut self,
57        kt: &tink_proto::KeyTemplate,
58        as_primary: bool,
59    ) -> Result<KeyId, TinkError> {
60        let key_data = crate::registry::new_key_data(kt)
61            .map_err(|e| wrap_err("keyset::Manager: cannot create KeyData", e))?;
62        let key_id = self.new_key_id();
63        let output_prefix_type = match OutputPrefixType::try_from(kt.output_prefix_type) {
64            Err(_) | Ok(OutputPrefixType::UnknownPrefix) => {
65                return Err("keyset::Manager: unknown output prefix type".into())
66            }
67            Ok(p) => p,
68        };
69        let key = tink_proto::keyset::Key {
70            key_data: Some(key_data),
71            status: tink_proto::KeyStatusType::Enabled as i32,
72            key_id,
73            output_prefix_type: output_prefix_type as i32,
74        };
75        self.ks.key.push(key);
76        if as_primary {
77            // Set the new key as the primary key
78            self.ks.primary_key_id = key_id;
79        }
80        Ok(key_id)
81    }
82
83    /// Create a new [`Handle`](super::Handle) for the managed keyset.
84    pub fn handle(&self) -> Result<super::Handle, TinkError> {
85        super::Handle::from_keyset(self.ks.clone())
86    }
87
88    /// Sets the status of the specified key to [`KeyStatusType::Enabled`].  Succeeds only if before
89    /// the call the specified key has status [`KeyStatusType::Disabled`] or
90    /// [`KeyStatusType::Enabled`].
91    pub fn enable(&mut self, key_id: KeyId) -> Result<(), TinkError> {
92        for key in &mut self.ks.key {
93            if key.key_id == key_id {
94                return match KeyStatusType::try_from(key.status) {
95                    Ok(KeyStatusType::Enabled) | Ok(KeyStatusType::Disabled) => {
96                        key.status = KeyStatusType::Enabled as i32;
97                        Ok(())
98                    }
99                    _ => Err(format!(
100                        "Cannot enable key with key_id {} and status {}",
101                        key_id, key.status
102                    )
103                    .into()),
104                };
105            }
106        }
107        Err(format!("Key {key_id} not found").into())
108    }
109
110    /// Sets the status of the specified key to [`KeyStatusType::Disabled`].
111    /// Succeeds only if before the call the specified key
112    /// is not primary and has status [`KeyStatusType::Disabled`] or [`KeyStatusType::Enabled`].
113    pub fn disable(&mut self, key_id: KeyId) -> Result<(), TinkError> {
114        if self.ks.primary_key_id == key_id {
115            return Err(format!("Cannot disable primary key (key_id {key_id})").into());
116        }
117        for key in &mut self.ks.key {
118            if key.key_id == key_id {
119                return match KeyStatusType::try_from(key.status) {
120                    Ok(KeyStatusType::Enabled) | Ok(KeyStatusType::Disabled) => {
121                        key.status = KeyStatusType::Disabled as i32;
122                        Ok(())
123                    }
124                    _ => Err(format!(
125                        "Cannot disable key with key_id {} and status {}",
126                        key_id, key.status
127                    )
128                    .into()),
129                };
130            }
131        }
132        Err(format!("Key {key_id} not found").into())
133    }
134
135    /// Sets the status of the specified key to [`KeyStatusType::Destroyed`], and removes the
136    /// corresponding key material, if any.  Succeeds only if before the call the specified key
137    /// is not primary and has status [`KeyStatusType::Disabled`], or
138    /// [`KeyStatusType::Enabled`], or [`KeyStatusType::Destroyed`].
139    pub fn destroy(&mut self, key_id: KeyId) -> Result<(), TinkError> {
140        if self.ks.primary_key_id == key_id {
141            return Err(format!("Cannot destroy primary key (key_id {key_id})").into());
142        }
143        for key in &mut self.ks.key {
144            if key.key_id == key_id {
145                return match KeyStatusType::try_from(key.status) {
146                    Ok(KeyStatusType::Enabled)
147                    | Ok(KeyStatusType::Disabled)
148                    | Ok(KeyStatusType::Destroyed) => {
149                        key.key_data = None;
150                        key.status = KeyStatusType::Destroyed as i32;
151                        Ok(())
152                    }
153                    _ => Err(format!(
154                        "Cannot destroy key with key_id {} and status {}",
155                        key_id, key.status
156                    )
157                    .into()),
158                };
159            }
160        }
161        Err(format!("Key {key_id} not found").into())
162    }
163
164    /// Removes the specifed key from the managed keyset.  Succeeds only if the specified key is not
165    /// primary.  After deletion the keyset contains one key fewer.
166    pub fn delete(&mut self, key_id: KeyId) -> Result<(), TinkError> {
167        if self.ks.primary_key_id == key_id {
168            return Err(format!("Cannot delete primary key (key_id {key_id})").into());
169        }
170        let mut idx: Option<usize> = None;
171        for (i, key) in self.ks.key.iter().enumerate() {
172            if key.key_id == key_id {
173                idx = Some(i);
174                break;
175            }
176        }
177        match idx {
178            Some(i) => {
179                self.ks.key.remove(i);
180                Ok(())
181            }
182            None => Err(format!("Key {key_id} not found").into()),
183        }
184    }
185
186    /// Sets the specified key as the primary.  Succeeds only if the specified key is `Enabled`.
187    pub fn set_primary(&mut self, key_id: KeyId) -> Result<(), TinkError> {
188        for key in &self.ks.key {
189            if key.key_id == key_id {
190                return match KeyStatusType::try_from(key.status) {
191                    Ok(KeyStatusType::Enabled) => {
192                        self.ks.primary_key_id = key_id;
193                        Ok(())
194                    }
195                    _ => Err(format!(
196                        "The candidate (key_id {}) for the primary key must be Enabled (status {})",
197                        key_id, key.status
198                    )
199                    .into()),
200                };
201            }
202        }
203        Err(format!("Key {key_id} not found").into())
204    }
205
206    /// Return the count of all keys in the keyset.
207    pub fn key_count(&self) -> usize {
208        self.ks.key.len()
209    }
210
211    /// Generate a key id that has not been used by any key in the [`Keyset`](tink_proto::Keyset).
212    fn new_key_id(&self) -> KeyId {
213        let mut rng = rand::thread_rng();
214
215        loop {
216            let ret = rng.gen::<u32>();
217            if self.ks.key.iter().any(|x| x.key_id == ret) {
218                continue;
219            }
220            return ret;
221        }
222    }
223}