twizzler_security/keys/
sign.rs1#[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
12const 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#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct SigningKey {
29 key: KeyBuffer,
31 pub scheme: SigningScheme,
33}
34
35impl SigningKey {
36 #[cfg(feature = "user")]
37 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 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 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 pub fn from_slice(slice: &[u8], scheme: SigningScheme) -> Result<Self, SecurityError> {
120 match scheme {
121 SigningScheme::Ecdsa => {
122 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 pub fn as_bytes(&self) -> &[u8] {
149 self.key.as_slice()
150 }
151
152 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 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}