twizzler_security/keys/
sign.rs

1#[cfg(feature = "log")]
2use log::{debug, error};
3#[cfg(feature = "user")]
4use {
5    twizzler::{
6        marker::BaseType,
7        object::{Object, ObjectBuilder},
8    },
9    twizzler_abi::syscall::ObjectCreate,
10};
11
12// 256 / 8 => 32 bytes for secret key length, since we are using curve p256, 256 bit curve
13const ECDSA_SECRET_KEY_LENGTH: usize = 32;
14
15use p256::ecdsa::{signature::Signer, Signature as EcdsaSignature, SigningKey as EcdsaSigningKey};
16use twizzler_rt_abi::error::TwzError;
17
18#[cfg(feature = "kernel")]
19use super::MAX_KEY_SIZE;
20use super::{KeyBuffer, Signature, VerifyingKey};
21use crate::{SecurityError, SigningScheme};
22
23/// Helper type for keybuffer
24
25/// An Objects `SigningKey`, used in creating `Cap`s and `Del`s.
26/// Is agnostic over SigningSchemes.
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct SigningKey {
29    /// The buffer that stores the raw key bytes.
30    key: KeyBuffer,
31    /// The signing scheme of this key
32    pub scheme: SigningScheme,
33}
34
35impl SigningKey {
36    #[cfg(feature = "user")]
37    /// Creates a new SigningKey / VerifyingKey object pairs.
38    pub fn new_keypair(
39        scheme: &SigningScheme,
40        obj_create_spec: ObjectCreate,
41    ) -> Result<(Object<Self>, Object<VerifyingKey>), TwzError> {
42        use alloc::borrow::ToOwned;
43
44        use getrandom::getrandom;
45
46        #[cfg(feature = "log")]
47        debug!("Creating new signing key with scheme: {:?}", scheme);
48
49        // first create the key using the signing scheme
50        let (signing_key, verifying_key): (SigningKey, VerifyingKey) = match scheme {
51            SigningScheme::Ecdsa => {
52                let mut rand_buf = [0_u8; ECDSA_SECRET_KEY_LENGTH];
53
54                if let Err(_e) = getrandom(&mut rand_buf) {
55                    #[cfg(feature = "log")]
56                    error!(
57                        "Failed to initialize buffer with random bytes, terminating
58                        key creation. Underlying error: {}",
59                        _e
60                    );
61
62                    return Err(TwzError::Generic(
63                        twizzler_rt_abi::error::GenericError::Internal,
64                    ));
65                }
66
67                let Ok(ecdsa_signing_key) = EcdsaSigningKey::from_slice(&rand_buf) else {
68                    #[cfg(feature = "log")]
69                    error!("Failed to create ecdsa signing key from bytes");
70
71                    return Err(TwzError::Generic(
72                        twizzler_rt_abi::error::GenericError::Internal,
73                    ));
74                };
75
76                let binding = ecdsa_signing_key.clone();
77
78                let ecdsa_verifying_key = binding.verifying_key().to_owned();
79
80                (ecdsa_signing_key.into(), ecdsa_verifying_key.into())
81            }
82        };
83
84        let s_object = ObjectBuilder::new(obj_create_spec.clone()).build(signing_key)?;
85        let v_object = ObjectBuilder::new(obj_create_spec).build(verifying_key)?;
86
87        return Ok((s_object, v_object));
88    }
89
90    #[cfg(feature = "kernel")]
91    /// Creates a new SigningKey / VerifyingKey object pairs.
92    pub fn new_kernel_keypair(
93        scheme: &SigningScheme,
94        random_bytes: [u8; MAX_KEY_SIZE],
95    ) -> Result<(SigningKey, VerifyingKey), TwzError> {
96        match scheme {
97            SigningScheme::Ecdsa => {
98                let Ok(ecdsa_signing_key) =
99                    EcdsaSigningKey::from_slice(&random_bytes[0..ECDSA_SECRET_KEY_LENGTH])
100                else {
101                    #[cfg(feature = "log")]
102                    error!("Failed to create ecdsa signing key from bytes");
103
104                    return Err(TwzError::Generic(
105                        twizzler_rt_abi::error::GenericError::Internal,
106                    ));
107                };
108
109                let binding = ecdsa_signing_key.clone();
110
111                let ecdsa_verifying_key = binding.verifying_key().clone();
112
113                Ok((ecdsa_signing_key.into(), ecdsa_verifying_key.into()))
114            }
115        }
116    }
117
118    /// Builds up a signing key from a slice of bytes and a specified signing scheme.
119    pub fn from_slice(slice: &[u8], scheme: SigningScheme) -> Result<Self, SecurityError> {
120        match scheme {
121            SigningScheme::Ecdsa => {
122                // the crate doesnt expose a const to verify key length,
123                // next best thing is to just ensure that key creation works
124                // instead of hardcoding in a key length?
125                let key = EcdsaSigningKey::from_slice(slice).map_err(|_e| {
126                    #[cfg(feature = "log")]
127                    error!(
128                        "Unable to create EcdsaSigningKey from slice due to: {:#?}!",
129                        _e
130                    );
131                    SecurityError::InvalidKey
132                })?;
133
134                let binding = key.to_bytes();
135
136                let key = KeyBuffer::from_slice(&binding)
137                    .expect("The ECDSA key cannot fit in the currently configured MAX_KEY_SIZE");
138
139                Ok(Self {
140                    key,
141                    scheme: SigningScheme::Ecdsa,
142                })
143            }
144        }
145    }
146
147    /// returns the inner signature as bytes
148    pub fn as_bytes(&self) -> &[u8] {
149        self.key.as_slice()
150    }
151
152    /// Sign the `msg` slice, returning a signature.
153    pub fn sign(&self, msg: &[u8]) -> Result<Signature, SecurityError> {
154        match self.scheme {
155            SigningScheme::Ecdsa => {
156                let signing_key: EcdsaSigningKey = self.try_into()?;
157                let sig: EcdsaSignature = signing_key.sign(msg);
158                Ok(sig.into())
159            }
160        }
161    }
162}
163
164impl TryFrom<&SigningKey> for EcdsaSigningKey {
165    type Error = SecurityError;
166    fn try_from(value: &SigningKey) -> Result<Self, Self::Error> {
167        if value.scheme != SigningScheme::Ecdsa {
168            #[cfg(feature = "log")]
169            error!("Cannot convert SigningKey to EcdsaSigningKey due to scheme mismatch. SigningKey scheme: {:?}", value.scheme);
170            return Err(SecurityError::InvalidScheme);
171        }
172
173        Ok(EcdsaSigningKey::from_slice(value.as_bytes()).map_err(|_e| {
174            #[cfg(feature = "log")]
175            error!("Cannot build EcdsaSigningKey from slice due to: {:?}", _e);
176            SecurityError::InvalidKey
177        })?)
178    }
179}
180
181impl From<EcdsaSigningKey> for SigningKey {
182    fn from(value: EcdsaSigningKey) -> Self {
183        let binding = value.to_bytes();
184
185        let key = KeyBuffer::from_slice(binding.as_slice())
186            .expect("The ECDSA key cannot fit in the currently configured MAX_KEY_SIZE");
187
188        SigningKey {
189            key,
190            scheme: SigningScheme::Ecdsa,
191        }
192    }
193}
194
195#[cfg(feature = "user")]
196#[allow(unused_imports)]
197mod tests {
198
199    use twizzler_abi::{object::Protections, syscall::ObjectCreate};
200
201    extern crate test;
202
203    use test::Bencher;
204
205    use super::SigningKey;
206    use crate::SigningScheme;
207
208    #[test]
209    fn test_key_creation() {
210        let object_create_spec = ObjectCreate::new(
211            Default::default(),
212            Default::default(),
213            Default::default(),
214            Default::default(),
215            Protections::all(),
216        );
217        let (_skey, _vkey) = SigningKey::new_keypair(&SigningScheme::Ecdsa, object_create_spec)
218            .expect("keys should be generated properly");
219    }
220
221    #[test]
222    fn test_signing_and_verification() {
223        use twizzler::object::TypedObject;
224        let object_create_spec = ObjectCreate::new(
225            Default::default(),
226            Default::default(),
227            Default::default(),
228            Default::default(),
229            Protections::all(),
230        );
231
232        let (s_obj, v_obj) = SigningKey::new_keypair(&SigningScheme::Ecdsa, object_create_spec)
233            .expect("Keys should be generated properly");
234        let message = "deadbeef".as_bytes();
235
236        let sig = s_obj
237            .base()
238            .sign(message)
239            .expect("Signature should succeed");
240
241        v_obj
242            .base()
243            .verify(message, &sig)
244            .expect("Should be verified properly");
245    }
246
247    #[bench]
248    //NOTE: currently we can only bench in user space, need to benchmark this in kernel space as
249    // well
250    fn bench_keypair_creation(b: &mut Bencher) {
251        let object_create_spec = ObjectCreate::new(
252            Default::default(),
253            Default::default(),
254            Default::default(),
255            Default::default(),
256            Protections::all(),
257        );
258        b.iter(|| {
259            let (_skey, _vkey) =
260                SigningKey::new_keypair(&SigningScheme::Ecdsa, object_create_spec.clone())
261                    .expect("Keys should be generated properly.");
262        });
263    }
264}
265
266#[cfg(feature = "user")]
267use twizzler::object::{MapFlags, ObjID, TypedObject};
268#[cfg(feature = "user")]
269impl TryFrom<ObjID> for SigningKey {
270    type Error = TwzError;
271    fn try_from(value: ObjID) -> Result<Self, Self::Error> {
272        let obj = Object::<SigningKey>::map(value, MapFlags::READ)?;
273        Ok(obj.base().clone())
274    }
275}
276
277#[cfg(feature = "user")]
278impl BaseType for SigningKey {
279    fn fingerprint() -> u64 {
280        return 6;
281    }
282}