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