Skip to content

Commit b1de50d

Browse files
committed
ecdsa: implement key import
Signed-off-by: Arthur Gautier <[email protected]>
1 parent 5254651 commit b1de50d

File tree

5 files changed

+111
-10
lines changed

5 files changed

+111
-10
lines changed

Cargo.lock

+2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cryptoki-rustcrypto/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ x509-cert = "0.2.4"
2727
thiserror = "1.0"
2828

2929
[dev-dependencies]
30+
rand = "0.8.5"
3031
serial_test = "0.5.1"
3132
testresult = "0.2.0"
3233
x509-cert = { version = "0.2.4", features = ["builder"] }

cryptoki-rustcrypto/src/ecdsa.rs

+58-7
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,21 @@ use cryptoki::{
66
object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle},
77
};
88
use der::{
9-
asn1::{ObjectIdentifier, OctetStringRef},
9+
asn1::{ObjectIdentifier, OctetString, OctetStringRef},
1010
oid::AssociatedOid,
1111
AnyRef, Decode, Encode,
1212
};
1313
use ecdsa::{
1414
elliptic_curve::{
1515
generic_array::ArrayLength,
16+
ops::Invert,
17+
point::PointCompression,
1618
sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint},
17-
AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey,
19+
subtle::CtOption,
20+
AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, Scalar,
1821
},
19-
hazmat::DigestPrimitive,
20-
PrimeCurve, Signature, VerifyingKey,
22+
hazmat::{DigestPrimitive, SignPrimitive},
23+
PrimeCurve, Signature, SignatureSize, SigningKey, VerifyingKey,
2124
};
2225
use signature::{digest::Digest, DigestSigner};
2326
use spki::{
@@ -27,7 +30,7 @@ use spki::{
2730
use std::{convert::TryFrom, ops::Add};
2831
use thiserror::Error;
2932

30-
use crate::SessionLike;
33+
use crate::{CryptokiImport, SessionLike};
3134

3235
pub fn read_key<S: SessionLike, C: SignAlgorithm>(
3336
session: &S,
@@ -70,6 +73,56 @@ where
7073
}
7174
}
7275

76+
impl<C> CryptokiImport for SigningKey<C>
77+
where
78+
C: PrimeCurve + CurveArithmetic,
79+
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
80+
SignatureSize<C>: ArrayLength<u8>,
81+
82+
C: AssociatedOid,
83+
{
84+
fn put_key<S: SessionLike>(
85+
&self,
86+
session: &S,
87+
template: impl Into<Vec<Attribute>>,
88+
) -> cryptoki::error::Result<ObjectHandle> {
89+
let mut template = template.into();
90+
template.push(Attribute::Class(ObjectClass::PRIVATE_KEY));
91+
template.push(Attribute::KeyType(KeyType::EC));
92+
template.push(Attribute::EcParams(C::OID.to_der().unwrap()));
93+
template.push(Attribute::Value(self.to_bytes().as_slice().to_vec()));
94+
95+
let handle = session.create_object(&template)?;
96+
97+
Ok(handle)
98+
}
99+
}
100+
101+
impl<C> CryptokiImport for VerifyingKey<C>
102+
where
103+
C: PrimeCurve + CurveArithmetic + PointCompression,
104+
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
105+
FieldBytesSize<C>: ModulusSize,
106+
C: AssociatedOid,
107+
{
108+
fn put_key<S: SessionLike>(
109+
&self,
110+
session: &S,
111+
template: impl Into<Vec<Attribute>>,
112+
) -> cryptoki::error::Result<ObjectHandle> {
113+
let mut template = template.into();
114+
template.push(Attribute::Class(ObjectClass::PUBLIC_KEY));
115+
template.push(Attribute::KeyType(KeyType::EC));
116+
template.push(Attribute::EcParams(C::OID.to_der().unwrap()));
117+
let ec_point = OctetString::new(self.to_sec1_bytes()).unwrap();
118+
template.push(Attribute::EcPoint(ec_point.to_der().unwrap()));
119+
120+
let handle = session.create_object(&template)?;
121+
122+
Ok(handle)
123+
}
124+
}
125+
73126
#[derive(Error, Debug)]
74127
pub enum Error {
75128
#[error("Cryptoki error: {0}")]
@@ -119,8 +172,6 @@ where
119172
pub fn new(session: S, label: &[u8]) -> Result<Self, Error> {
120173
// First we'll lookup a private key with that label.
121174
let template = vec![
122-
Attribute::Token(true),
123-
Attribute::Private(true),
124175
Attribute::Label(label.to_vec()),
125176
Attribute::Class(ObjectClass::PRIVATE_KEY),
126177
Attribute::KeyType(KeyType::EC),

cryptoki-rustcrypto/src/lib.rs

+8
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,11 @@ impl<'s> SessionLike for &'s Session {
6868
Session::generate_random_slice(self, random_data)
6969
}
7070
}
71+
72+
pub trait CryptokiImport {
73+
fn put_key<S: SessionLike>(
74+
&self,
75+
session: &S,
76+
template: impl Into<Vec<Attribute>>,
77+
) -> Result<ObjectHandle>;
78+
}

cryptoki-rustcrypto/tests/ecdsa.rs

+42-3
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use cryptoki::{
1111
session::UserType,
1212
types::AuthPin,
1313
};
14-
use cryptoki_rustcrypto::ecdsa;
14+
use cryptoki_rustcrypto::{ecdsa, CryptokiImport};
1515
use der::Encode;
1616
use p256::pkcs8::AssociatedOid;
1717
use serial_test::serial;
@@ -39,7 +39,7 @@ fn sign_verify() -> TestResult {
3939

4040
// pub key template
4141
let pub_key_template = vec![
42-
Attribute::Token(true),
42+
Attribute::Token(false),
4343
Attribute::Private(false),
4444
Attribute::KeyType(KeyType::EC),
4545
Attribute::Verify(true),
@@ -49,7 +49,7 @@ fn sign_verify() -> TestResult {
4949

5050
// priv key template
5151
let priv_key_template = vec![
52-
Attribute::Token(true),
52+
Attribute::Token(false),
5353
Attribute::Private(true),
5454
Attribute::Sign(true),
5555
Attribute::Label(label.to_vec()),
@@ -76,3 +76,42 @@ fn sign_verify() -> TestResult {
7676

7777
Ok(())
7878
}
79+
80+
#[test]
81+
#[serial]
82+
fn test_import() -> TestResult {
83+
let (pkcs11, slot) = init_pins();
84+
85+
// open a session
86+
let session = pkcs11.open_rw_session(slot)?;
87+
88+
// log in the session
89+
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;
90+
91+
let mut rng = rand::thread_rng();
92+
let private = p256::ecdsa::SigningKey::random(&mut rng);
93+
94+
let label = b"demo-import";
95+
96+
let template = vec![Attribute::Token(false), Attribute::Label(label.to_vec())];
97+
98+
let private_handle = private.put_key(&session, template.clone())?;
99+
let public_handle = private.verifying_key().put_key(&session, template)?;
100+
101+
// data to sign
102+
let data = [0xFF, 0x55, 0xDD];
103+
104+
let signer =
105+
ecdsa::Signer::<p256::NistP256, _>::new(&session, label).expect("Lookup keys from HSM");
106+
107+
let signature: p256::ecdsa::Signature = signer.sign(&data);
108+
109+
let verifying_key = private.verifying_key();
110+
verifying_key.verify(&data, &signature)?;
111+
112+
// delete keys
113+
session.destroy_object(private_handle)?;
114+
session.destroy_object(public_handle)?;
115+
116+
Ok(())
117+
}

0 commit comments

Comments
 (0)