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