1use crate::{
6 error::*,
7 pk11::{
8 self,
9 context::HashAlgorithm,
10 slot,
11 types::{Pkcs11Object, PrivateKey as PK11PrivateKey, PublicKey as PK11PublicKey},
12 },
13 util::{assert_nss_initialized, map_nss_secstatus, sec_item_as_slice, ScopedPtr},
14};
15use serde_derive::{Deserialize, Serialize};
16use std::{
17 mem,
18 ops::Deref,
19 os::raw::{c_uchar, c_uint, c_void},
20 ptr,
21};
22
23#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
24#[repr(u8)]
25pub enum Curve {
26 P256,
27 P384,
28}
29
30impl Curve {
31 pub fn get_field_len(&self) -> u32 {
32 match &self {
33 Curve::P256 => 32,
34 Curve::P384 => 48,
35 }
36 }
37}
38
39const CRV_P256: &str = "P-256";
40const CRV_P384: &str = "P-384";
41
42#[derive(Serialize, Deserialize, Clone, Debug)]
43pub struct EcKey {
44 curve: String,
45 private_key: Vec<u8>,
47 public_key: Vec<u8>,
49}
50
51impl EcKey {
52 pub fn new(curve: Curve, private_key: &[u8], public_key: &[u8]) -> Self {
53 let curve = match curve {
54 Curve::P256 => CRV_P256,
55 Curve::P384 => CRV_P384,
56 };
57 Self {
58 curve: curve.to_owned(),
59 private_key: private_key.to_vec(),
60 public_key: public_key.to_vec(),
61 }
62 }
63
64 pub fn from_coordinates(curve: Curve, d: &[u8], x: &[u8], y: &[u8]) -> Result<Self> {
65 let ec_point = create_ec_point_for_coordinates(x, y)?;
66 Ok(EcKey::new(curve, d, &ec_point))
67 }
68
69 pub fn curve(&self) -> Curve {
70 if self.curve == CRV_P256 {
71 return Curve::P256;
72 } else if self.curve == CRV_P384 {
73 return Curve::P384;
74 }
75 unimplemented!("It is impossible to create a curve object with a different CRV.")
76 }
77
78 pub fn public_key(&self) -> &[u8] {
79 &self.public_key
80 }
81
82 pub fn private_key(&self) -> &[u8] {
83 &self.private_key
84 }
85}
86
87fn create_ec_point_for_coordinates(x: &[u8], y: &[u8]) -> Result<Vec<u8>> {
88 if x.len() != y.len() {
89 return Err(ErrorKind::InternalError.into());
90 }
91 let mut buf = vec![0u8; x.len() + y.len() + 1];
92 buf[0] = u8::try_from(nss_sys::EC_POINT_FORM_UNCOMPRESSED)?;
93 let mut offset = 1;
94 buf[offset..offset + x.len()].copy_from_slice(x);
95 offset += x.len();
96 buf[offset..offset + y.len()].copy_from_slice(y);
97 Ok(buf)
98}
99
100pub fn generate_keypair(curve: Curve) -> Result<(PrivateKey, PublicKey)> {
101 assert_nss_initialized();
102 let params_buf = create_ec_params_for_curve(curve)?;
104 let mut params = nss_sys::SECItem {
105 type_: nss_sys::SECItemType::siBuffer as u32,
106 data: params_buf.as_ptr() as *mut c_uchar,
107 len: c_uint::try_from(params_buf.len())?,
108 };
109
110 let mech = nss_sys::CKM_EC_KEY_PAIR_GEN;
114 let slot = slot::get_internal_slot()?;
115 let mut pub_key: *mut nss_sys::SECKEYPublicKey = ptr::null_mut();
116 let prv_key = PrivateKey::from(curve, unsafe {
117 PK11PrivateKey::from_ptr(nss_sys::PK11_GenerateKeyPair(
118 slot.as_mut_ptr(),
119 mech.into(),
120 &mut params as *mut _ as *mut c_void,
121 &mut pub_key,
122 nss_sys::PR_FALSE,
123 nss_sys::PR_FALSE,
124 ptr::null_mut(),
125 ))?
126 });
127 let pub_key = PublicKey::from(curve, unsafe { PK11PublicKey::from_ptr(pub_key)? });
128 Ok((prv_key, pub_key))
129}
130
131pub struct PrivateKey {
132 curve: Curve,
133 wrapped: PK11PrivateKey,
134}
135
136impl Deref for PrivateKey {
137 type Target = PK11PrivateKey;
138 #[inline]
139 fn deref(&self) -> &PK11PrivateKey {
140 &self.wrapped
141 }
142}
143
144impl PrivateKey {
145 pub fn convert_to_public_key(&self) -> Result<PublicKey> {
146 let mut pub_key = self.wrapped.convert_to_public_key()?;
147
148 let field_len = self.curve.get_field_len();
150 let expected_len = 2 * field_len + 1;
151 let mut pub_value = unsafe { (*pub_key.as_ptr()).u.ec.publicValue };
152 if pub_value.len == expected_len - 2 {
153 let old_pub_value_raw = unsafe { sec_item_as_slice(&mut pub_value)?.to_vec() };
154 let mut new_pub_value_raw = vec![0u8; usize::try_from(expected_len)?];
155 new_pub_value_raw[0] = u8::try_from(nss_sys::EC_POINT_FORM_UNCOMPRESSED)?;
156 new_pub_value_raw[1] = u8::try_from(old_pub_value_raw.len())?;
157 new_pub_value_raw[2..].copy_from_slice(&old_pub_value_raw);
158 pub_key = PublicKey::from_bytes(self.curve, &new_pub_value_raw)?.wrapped;
159 }
160 Ok(PublicKey {
161 wrapped: pub_key,
162 curve: self.curve,
163 })
164 }
165
166 #[inline]
167 pub(crate) fn from(curve: Curve, key: PK11PrivateKey) -> Self {
168 Self {
169 curve,
170 wrapped: key,
171 }
172 }
173
174 pub fn curve(&self) -> Curve {
175 self.curve
176 }
177
178 pub fn private_value(&self) -> Result<Vec<u8>> {
179 let mut private_value = self.read_raw_attribute(nss_sys::CKA_VALUE.into()).unwrap();
180 let private_key = unsafe { sec_item_as_slice(private_value.as_mut_ref())?.to_vec() };
181 Ok(private_key)
182 }
183
184 fn from_nss_params(
185 curve: Curve,
186 ec_params: &[u8],
187 ec_point: &[u8],
188 private_value: &[u8],
189 ) -> Result<Self> {
190 let mut private_key_value: nss_sys::CK_OBJECT_CLASS = nss_sys::CKO_PRIVATE_KEY.into();
195 let mut false_value: nss_sys::CK_BBOOL = nss_sys::CK_FALSE;
196 let mut ec_value: nss_sys::CK_KEY_TYPE = nss_sys::CKK_EC.into();
197 let bbool_size = mem::size_of::<nss_sys::CK_BBOOL>();
198 let key_template = vec![
199 ck_attribute(
200 nss_sys::CKA_CLASS.into(),
201 &mut private_key_value as *mut _ as *mut c_void,
202 mem::size_of::<nss_sys::CK_OBJECT_CLASS>(),
203 )?,
204 ck_attribute(
205 nss_sys::CKA_KEY_TYPE.into(),
206 &mut ec_value as *mut _ as *mut c_void,
207 mem::size_of::<nss_sys::CK_KEY_TYPE>(),
208 )?,
209 ck_attribute(
210 nss_sys::CKA_TOKEN.into(),
211 &mut false_value as *mut _ as *mut c_void,
212 bbool_size,
213 )?,
214 ck_attribute(
215 nss_sys::CKA_SENSITIVE.into(),
216 &mut false_value as *mut _ as *mut c_void,
217 bbool_size,
218 )?,
219 ck_attribute(
220 nss_sys::CKA_PRIVATE.into(),
221 &mut false_value as *mut _ as *mut c_void,
222 bbool_size,
223 )?,
224 ck_attribute(nss_sys::CKA_ID.into(), ptr::null_mut(), 0)?,
226 ck_attribute(
227 nss_sys::CKA_EC_PARAMS.into(),
228 ec_params.as_ptr() as *mut c_void,
229 ec_params.len(),
230 )?,
231 ck_attribute(
232 nss_sys::CKA_EC_POINT.into(),
233 ec_point.as_ptr() as *mut c_void,
234 ec_point.len(),
235 )?,
236 ck_attribute(
237 nss_sys::CKA_VALUE.into(),
238 private_value.as_ptr() as *mut c_void,
239 private_value.len(),
240 )?,
241 ];
242 Ok(Self::from(
243 curve,
244 PK11PrivateKey::from_private_key_template(key_template)?,
245 ))
246 }
247
248 pub fn import(ec_key: &EcKey) -> Result<Self> {
249 assert_nss_initialized();
252 let curve = ec_key.curve();
253 let ec_params = create_ec_params_for_curve(curve)?;
254 Self::from_nss_params(curve, &ec_params, &ec_key.public_key, &ec_key.private_key)
255 }
256
257 pub fn export(&self) -> Result<EcKey> {
258 let public_key = self.convert_to_public_key()?;
259 let public_key_bytes = public_key.to_bytes()?;
260 let private_key_bytes = self.private_value()?;
261 Ok(EcKey::new(
262 self.curve,
263 &private_key_bytes,
264 &public_key_bytes,
265 ))
266 }
267}
268
269#[inline]
270fn ck_attribute(
271 r#type: nss_sys::CK_ATTRIBUTE_TYPE,
272 p_value: nss_sys::CK_VOID_PTR,
273 value_len: usize,
274) -> Result<nss_sys::CK_ATTRIBUTE> {
275 Ok(nss_sys::CK_ATTRIBUTE {
276 type_: r#type,
277 pValue: p_value,
278 ulValueLen: nss_sys::CK_ULONG::try_from(value_len)?,
279 })
280}
281
282pub struct PublicKey {
283 curve: Curve,
284 wrapped: PK11PublicKey,
285}
286
287impl Deref for PublicKey {
288 type Target = PK11PublicKey;
289 #[inline]
290 fn deref(&self) -> &PK11PublicKey {
291 &self.wrapped
292 }
293}
294
295impl PublicKey {
296 #[inline]
297 pub(crate) fn from(curve: Curve, key: PK11PublicKey) -> Self {
298 Self {
299 curve,
300 wrapped: key,
301 }
302 }
303
304 pub fn curve(&self) -> Curve {
305 self.curve
306 }
307
308 pub fn verify(
310 &self,
311 message: &[u8],
312 signature: &[u8],
313 hash_algorithm: HashAlgorithm,
314 ) -> Result<()> {
315 let signature = nss_sys::SECItem {
318 len: u32::try_from(signature.len())?,
319 data: signature.as_ptr() as *mut u8,
320 type_: 0,
321 };
322 let hash = pk11::context::hash_buf(&hash_algorithm, message)?;
323 let hash = nss_sys::SECItem {
324 len: u32::try_from(hash.len())?,
325 data: hash.as_ptr() as *mut u8,
326 type_: 0,
327 };
328 map_nss_secstatus(|| unsafe {
329 nss_sys::PK11_VerifyWithMechanism(
330 self.as_mut_ptr(),
331 nss_sys::PK11_MapSignKeyType((*self.wrapped.as_ptr()).keyType),
332 ptr::null(),
333 &signature,
334 &hash,
335 ptr::null_mut(),
336 )
337 })?;
338 Ok(())
339 }
340
341 pub fn to_bytes(&self) -> Result<Vec<u8>> {
342 let mut ec_point = unsafe { (*self.as_ptr()).u.ec.publicValue };
346 let public_key = unsafe { sec_item_as_slice(&mut ec_point)?.to_vec() };
347 check_pub_key_bytes(&public_key, self.curve)?;
348 Ok(public_key)
349 }
350
351 pub fn from_bytes(curve: Curve, bytes: &[u8]) -> Result<PublicKey> {
352 check_pub_key_bytes(bytes, curve)?;
355 let key_data = nss_sys::SECItem {
356 type_: nss_sys::SECItemType::siBuffer as u32,
357 data: bytes.as_ptr() as *mut c_uchar,
358 len: c_uint::try_from(bytes.len())?,
359 };
360 let params_buf = create_ec_params_for_curve(curve)?;
361 let params = nss_sys::SECItem {
362 type_: nss_sys::SECItemType::siBuffer as u32,
363 data: params_buf.as_ptr() as *mut c_uchar,
364 len: c_uint::try_from(params_buf.len())?,
365 };
366
367 let pub_key = nss_sys::SECKEYPublicKey {
368 arena: ptr::null_mut(),
369 keyType: nss_sys::KeyType::ecKey as u32,
370 pkcs11Slot: ptr::null_mut(),
371 pkcs11ID: nss_sys::CK_INVALID_HANDLE.into(),
372 u: nss_sys::SECKEYPublicKeyStr_u {
373 ec: nss_sys::SECKEYECPublicKey {
374 DEREncodedParams: params,
375 publicValue: key_data,
376 encoding: nss_sys::ECPointEncoding::ECPoint_Uncompressed as u32,
377 size: 0,
378 },
379 },
380 };
381 Ok(Self::from(curve, unsafe {
382 PK11PublicKey::from_ptr(nss_sys::SECKEY_CopyPublicKey(&pub_key))?
383 }))
384 }
385}
386
387fn check_pub_key_bytes(bytes: &[u8], curve: Curve) -> Result<()> {
388 let field_len = curve.get_field_len();
389 if bytes.len() != usize::try_from(2 * field_len + 1)? {
392 return Err(ErrorKind::InternalError.into());
393 }
394 if bytes[0] != u8::try_from(nss_sys::EC_POINT_FORM_UNCOMPRESSED)? {
396 return Err(ErrorKind::InternalError.into());
397 }
398 Ok(())
399}
400
401fn create_ec_params_for_curve(curve: Curve) -> Result<Vec<u8>> {
402 let curve_oid_tag = match curve {
405 Curve::P256 => nss_sys::SECOidTag::SEC_OID_SECG_EC_SECP256R1,
406 Curve::P384 => nss_sys::SECOidTag::SEC_OID_SECG_EC_SECP384R1,
407 };
408 let oid_data = unsafe { nss_sys::SECOID_FindOIDByTag(curve_oid_tag as u32) };
410 if oid_data.is_null() {
411 return Err(ErrorKind::InternalError.into());
412 }
413 let oid_data_len = unsafe { (*oid_data).oid.len };
415 let mut buf = vec![0u8; usize::try_from(oid_data_len)? + 2];
416 buf[0] = c_uchar::try_from(nss_sys::SEC_ASN1_OBJECT_ID)?;
417 buf[1] = c_uchar::try_from(oid_data_len)?;
418 let oid_data_data =
419 unsafe { std::slice::from_raw_parts((*oid_data).oid.data, usize::try_from(oid_data_len)?) };
420 buf[2..].copy_from_slice(oid_data_data);
421 Ok(buf)
422}