diff --git a/Cargo.lock b/Cargo.lock index cca99134..96dfc352 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,6 +188,7 @@ dependencies = [ "p224", "p256", "p384", + "rand", "rsa", "serial_test", "sha1", @@ -727,6 +728,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ + "libc", "rand_chacha", "rand_core", ] diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index 74fa9c99..d00d2097 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -27,6 +27,7 @@ x509-cert = "0.2.4" thiserror = "1.0" [dev-dependencies] +rand = "0.8.5" serial_test = "0.5.1" testresult = "0.2.0" x509-cert = { version = "0.2.4", features = ["builder"] } diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index 1895e8d6..43ecfd22 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -6,18 +6,21 @@ use cryptoki::{ object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, }; use der::{ - asn1::{ObjectIdentifier, OctetStringRef}, + asn1::{ObjectIdentifier, OctetString, OctetStringRef}, oid::AssociatedOid, AnyRef, Decode, Encode, }; use ecdsa::{ elliptic_curve::{ generic_array::ArrayLength, + ops::Invert, + point::PointCompression, sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, - AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, + subtle::CtOption, + AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, Scalar, }, - hazmat::DigestPrimitive, - PrimeCurve, Signature, VerifyingKey, + hazmat::{DigestPrimitive, SignPrimitive}, + PrimeCurve, Signature, SignatureSize, SigningKey, VerifyingKey, }; use signature::{digest::Digest, DigestSigner}; use spki::{ @@ -27,7 +30,7 @@ use spki::{ use std::{convert::TryFrom, ops::Add}; use thiserror::Error; -use crate::SessionLike; +use crate::{CryptokiImport, SessionLike}; pub fn read_key( session: &S, @@ -70,6 +73,56 @@ where } } +impl CryptokiImport for SigningKey +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + + C: AssociatedOid, +{ + fn put_key( + &self, + session: &S, + template: impl Into>, + ) -> cryptoki::error::Result { + let mut template = template.into(); + template.push(Attribute::Class(ObjectClass::PRIVATE_KEY)); + template.push(Attribute::KeyType(KeyType::EC)); + template.push(Attribute::EcParams(C::OID.to_der().unwrap())); + template.push(Attribute::Value(self.to_bytes().as_slice().to_vec())); + + let handle = session.create_object(&template)?; + + Ok(handle) + } +} + +impl CryptokiImport for VerifyingKey +where + C: PrimeCurve + CurveArithmetic + PointCompression, + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + C: AssociatedOid, +{ + fn put_key( + &self, + session: &S, + template: impl Into>, + ) -> cryptoki::error::Result { + let mut template = template.into(); + template.push(Attribute::Class(ObjectClass::PUBLIC_KEY)); + template.push(Attribute::KeyType(KeyType::EC)); + template.push(Attribute::EcParams(C::OID.to_der().unwrap())); + let ec_point = OctetString::new(self.to_sec1_bytes()).unwrap(); + template.push(Attribute::EcPoint(ec_point.to_der().unwrap())); + + let handle = session.create_object(&template)?; + + Ok(handle) + } +} + #[derive(Error, Debug)] pub enum Error { #[error("Cryptoki error: {0}")] @@ -119,8 +172,6 @@ where pub fn new(session: S, label: &[u8]) -> Result { // First we'll lookup a private key with that label. let template = vec![ - Attribute::Token(true), - Attribute::Private(true), Attribute::Label(label.to_vec()), Attribute::Class(ObjectClass::PRIVATE_KEY), Attribute::KeyType(KeyType::EC), diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index 1500192c..ac2dd57a 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -68,3 +68,11 @@ impl<'s> SessionLike for &'s Session { Session::generate_random_slice(self, random_data) } } + +pub trait CryptokiImport { + fn put_key( + &self, + session: &S, + template: impl Into>, + ) -> Result; +} diff --git a/cryptoki-rustcrypto/tests/ecdsa.rs b/cryptoki-rustcrypto/tests/ecdsa.rs index c4c66d42..5db5c7ff 100644 --- a/cryptoki-rustcrypto/tests/ecdsa.rs +++ b/cryptoki-rustcrypto/tests/ecdsa.rs @@ -11,7 +11,7 @@ use cryptoki::{ session::UserType, types::AuthPin, }; -use cryptoki_rustcrypto::ecdsa; +use cryptoki_rustcrypto::{ecdsa, CryptokiImport}; use der::Encode; use p256::pkcs8::AssociatedOid; use serial_test::serial; @@ -39,7 +39,7 @@ fn sign_verify() -> TestResult { // pub key template let pub_key_template = vec![ - Attribute::Token(true), + Attribute::Token(false), Attribute::Private(false), Attribute::KeyType(KeyType::EC), Attribute::Verify(true), @@ -49,7 +49,7 @@ fn sign_verify() -> TestResult { // priv key template let priv_key_template = vec![ - Attribute::Token(true), + Attribute::Token(false), Attribute::Private(true), Attribute::Sign(true), Attribute::Label(label.to_vec()), @@ -76,3 +76,42 @@ fn sign_verify() -> TestResult { Ok(()) } + +#[test] +#[serial] +fn test_import() -> TestResult { + let (pkcs11, slot) = init_pins(); + + // open a session + let session = pkcs11.open_rw_session(slot)?; + + // log in the session + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + let mut rng = rand::thread_rng(); + let private = p256::ecdsa::SigningKey::random(&mut rng); + + let label = b"demo-import"; + + let template = vec![Attribute::Token(false), Attribute::Label(label.to_vec())]; + + let private_handle = private.put_key(&session, template.clone())?; + let public_handle = private.verifying_key().put_key(&session, template)?; + + // data to sign + let data = [0xFF, 0x55, 0xDD]; + + let signer = + ecdsa::Signer::::new(&session, label).expect("Lookup keys from HSM"); + + let signature: p256::ecdsa::Signature = signer.sign(&data); + + let verifying_key = private.verifying_key(); + verifying_key.verify(&data, &signature)?; + + // delete keys + session.destroy_object(private_handle)?; + session.destroy_object(public_handle)?; + + Ok(()) +}