From 1db24aa6cea4b566af6f519be4eff3db80b42c6e Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 22 Nov 2023 20:42:55 -0800 Subject: [PATCH 01/19] rustcrypto: initial commit Signed-off-by: Arthur Gautier --- Cargo.toml | 2 +- cryptoki-rustcrypto/Cargo.toml | 24 ++++ cryptoki-rustcrypto/src/lib.rs | 4 + cryptoki-rustcrypto/src/rsa/mod.rs | 78 +++++++++++++ cryptoki-rustcrypto/src/rsa/pkcs1v15.rs | 127 +++++++++++++++++++++ cryptoki-rustcrypto/src/rsa/pss.rs | 145 ++++++++++++++++++++++++ cryptoki-rustcrypto/tests/common.rs | 44 +++++++ cryptoki-rustcrypto/tests/rsa.rs | 121 ++++++++++++++++++++ 8 files changed, 544 insertions(+), 1 deletion(-) create mode 100644 cryptoki-rustcrypto/Cargo.toml create mode 100644 cryptoki-rustcrypto/src/lib.rs create mode 100644 cryptoki-rustcrypto/src/rsa/mod.rs create mode 100644 cryptoki-rustcrypto/src/rsa/pkcs1v15.rs create mode 100644 cryptoki-rustcrypto/src/rsa/pss.rs create mode 100644 cryptoki-rustcrypto/tests/common.rs create mode 100644 cryptoki-rustcrypto/tests/rsa.rs diff --git a/Cargo.toml b/Cargo.toml index 99938e6c..740a8e6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["cryptoki", "cryptoki-sys"] +members = ["cryptoki", "cryptoki-sys", "cryptoki-rustcrypto"] diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml new file mode 100644 index 00000000..dc35c4d7 --- /dev/null +++ b/cryptoki-rustcrypto/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "cryptoki-rustcrypto" +version = "0.1.0" +edition = "2018" +authors = ["Contributors to the Parsec project"] +description = "Compatibility layer from PKCS #11 to the RustCrypto ecosystem" +readme = "README.md" +keywords = ["pkcs11", "cryptoki", "hsm"] +categories = ["cryptography", "hardware-support"] +license = "Apache-2.0" + +[dependencies] +cryptoki = { path = "../cryptoki", version = "0.6.1" } +der = "0.7.8" +rsa = "0.9" +signature = { version = "2.2.0", features = ["digest"] } +sha1 = { version = "0.10", features = ["oid"] } +sha2 = { version = "0.10", features = ["oid"] } +spki = "0.7.2" +thiserror = "1.0" + +[dev-dependencies] +serial_test = "0.5.1" +testresult = "0.2.0" diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs new file mode 100644 index 00000000..be249b9e --- /dev/null +++ b/cryptoki-rustcrypto/src/lib.rs @@ -0,0 +1,4 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +pub mod rsa; diff --git a/cryptoki-rustcrypto/src/rsa/mod.rs b/cryptoki-rustcrypto/src/rsa/mod.rs new file mode 100644 index 00000000..ed91014a --- /dev/null +++ b/cryptoki-rustcrypto/src/rsa/mod.rs @@ -0,0 +1,78 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use cryptoki::mechanism::{ + rsa::{PkcsMgfType, PkcsPssParams}, + Mechanism, MechanismType, +}; +use cryptoki::object::AttributeType; +use der::oid::AssociatedOid; +use signature::digest::Digest; +use std::convert::TryInto; +use thiserror::Error; + +pub mod pkcs1v15; + +pub mod pss; + +#[derive(Debug, Error)] +pub enum Error { + #[error("Cryptoki error: {0}")] + Cryptoki(#[from] cryptoki::error::Error), + + #[error("Private key missing attribute: {0}")] + MissingAttribute(AttributeType), + + #[error("RSA error: {0}")] + Rsa(#[from] rsa::Error), +} + +pub trait DigestSigning: Digest + AssociatedOid { + fn pkcs_mechanism() -> Mechanism<'static>; + + fn pss_mechanism() -> Mechanism<'static>; +} + +macro_rules! impl_digest_signing { + ($d:ty, $pkcs_mech:ident, $pss_mech:ident, $mt:ident, $mgf:ident) => { + impl DigestSigning for $d { + fn pkcs_mechanism() -> Mechanism<'static> { + Mechanism::$pkcs_mech + } + + fn pss_mechanism() -> Mechanism<'static> { + Mechanism::$pss_mech(PkcsPssParams { + hash_alg: MechanismType::$mt, + mgf: PkcsMgfType::$mgf, + // Safety: + // the output_size of an hash function will not go over 2^32, + // this unwrap is safe. + s_len: Self::output_size().try_into().unwrap(), + }) + } + } + }; +} + +impl_digest_signing!(sha1::Sha1, Sha1RsaPkcs, Sha1RsaPkcsPss, SHA1, MGF1_SHA1); +impl_digest_signing!( + sha2::Sha256, + Sha256RsaPkcs, + Sha256RsaPkcsPss, + SHA256, + MGF1_SHA256 +); +impl_digest_signing!( + sha2::Sha384, + Sha384RsaPkcs, + Sha384RsaPkcsPss, + SHA384, + MGF1_SHA384 +); +impl_digest_signing!( + sha2::Sha512, + Sha512RsaPkcs, + Sha512RsaPkcsPss, + SHA512, + MGF1_SHA512 +); diff --git a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs new file mode 100644 index 00000000..754ecbec --- /dev/null +++ b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs @@ -0,0 +1,127 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use cryptoki::{ + object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, + session::Session, +}; +use der::AnyRef; +use rsa::{ + pkcs1, + pkcs1v15::{Signature, VerifyingKey}, + BigUint, RsaPublicKey, +}; +use spki::{AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}; +use std::convert::TryFrom; + +use super::{DigestSigning, Error}; + +pub struct Signer { + session: Session, + _public_key: ObjectHandle, + private_key: ObjectHandle, + verifying_key: VerifyingKey, +} + +impl Signer { + pub fn new(session: Session, 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::RSA), + Attribute::Sign(true), + ]; + + let private_key = session.find_objects(&template)?.remove(0); + let attribute_pk = session.get_attributes( + private_key, + &[AttributeType::Modulus, AttributeType::PublicExponent], + )?; + + // Second we'll lookup a public key with the same label/modulus/public exponent + let mut template = vec![ + Attribute::Private(false), + Attribute::Label(label.to_vec()), + Attribute::Class(ObjectClass::PUBLIC_KEY), + Attribute::KeyType(KeyType::RSA), + ]; + let mut modulus = None; + let mut public_exponent = None; + for attribute in attribute_pk { + match attribute { + Attribute::Modulus(m) if modulus.is_none() => { + modulus = Some(m.clone()); + template.push(Attribute::Modulus(m)); + } + Attribute::PublicExponent(e) if public_exponent.is_none() => { + public_exponent = Some(e.clone()); + template.push(Attribute::PublicExponent(e)); + } + _ => {} + } + } + + let modulus = modulus + .ok_or(Error::MissingAttribute(AttributeType::Modulus)) + .map(|v| BigUint::from_bytes_be(v.as_slice()))?; + let public_exponent = public_exponent + .ok_or(Error::MissingAttribute(AttributeType::PublicExponent)) + .map(|v| BigUint::from_bytes_be(v.as_slice()))?; + + let public_key = session.find_objects(&template)?.remove(0); + + let verifying_key = VerifyingKey::new(RsaPublicKey::new(modulus, public_exponent)?); + + Ok(Self { + session, + private_key, + _public_key: public_key, + verifying_key, + }) + } + + pub fn into_session(self) -> Session { + self.session + } +} + +impl AssociatedAlgorithmIdentifier for Signer { + type Params = AnyRef<'static>; + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +} + +impl signature::Keypair for Signer { + type VerifyingKey = VerifyingKey; + + fn verifying_key(&self) -> Self::VerifyingKey { + self.verifying_key.clone() + } +} + +impl signature::Signer for Signer { + fn try_sign(&self, msg: &[u8]) -> Result { + let bytes = self + .session + .sign(&D::pkcs_mechanism(), self.private_key, msg) + .map_err(Error::Cryptoki) + .map_err(Box::new) + .map_err(signature::Error::from_source)?; + + let signature = Signature::try_from(bytes.as_slice())?; + + Ok(signature) + } +} + +impl SignatureAlgorithmIdentifier for Signer { + type Params = AnyRef<'static>; + + const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = + AlgorithmIdentifierRef { + oid: D::OID, + parameters: Some(AnyRef::NULL), + }; +} diff --git a/cryptoki-rustcrypto/src/rsa/pss.rs b/cryptoki-rustcrypto/src/rsa/pss.rs new file mode 100644 index 00000000..20acdbf8 --- /dev/null +++ b/cryptoki-rustcrypto/src/rsa/pss.rs @@ -0,0 +1,145 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use cryptoki::{ + object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, + session::Session, +}; +use der::{asn1::ObjectIdentifier, oid::AssociatedOid, Any, AnyRef}; +use rsa::{ + pkcs1::{self, RsaPssParams}, + pkcs8::{self}, + pss::{Signature, VerifyingKey}, + BigUint, RsaPublicKey, +}; +use signature::digest::Digest; +use spki::{ + AlgorithmIdentifierOwned, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, + DynSignatureAlgorithmIdentifier, +}; +use std::convert::TryFrom; + +use super::{DigestSigning, Error}; + +pub struct Signer { + session: Session, + _public_key: ObjectHandle, + private_key: ObjectHandle, + verifying_key: VerifyingKey, + salt_len: usize, +} + +impl Signer { + pub fn new(session: Session, 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::RSA), + Attribute::Sign(true), + ]; + + let private_key = session.find_objects(&template)?.remove(0); + let attribute_pk = session.get_attributes( + private_key, + &[AttributeType::Modulus, AttributeType::PublicExponent], + )?; + + // Second we'll lookup a public key with the same label/modulus/public exponent + let mut template = vec![ + Attribute::Private(false), + Attribute::Label(label.to_vec()), + Attribute::Class(ObjectClass::PUBLIC_KEY), + Attribute::KeyType(KeyType::RSA), + ]; + let mut modulus = None; + let mut public_exponent = None; + for attribute in attribute_pk { + match attribute { + Attribute::Modulus(m) if modulus.is_none() => { + modulus = Some(m.clone()); + template.push(Attribute::Modulus(m)); + } + Attribute::PublicExponent(e) if public_exponent.is_none() => { + public_exponent = Some(e.clone()); + template.push(Attribute::PublicExponent(e)); + } + _ => {} + } + } + + let modulus = modulus + .ok_or(Error::MissingAttribute(AttributeType::Modulus)) + .map(|v| BigUint::from_bytes_be(v.as_slice()))?; + let public_exponent = public_exponent + .ok_or(Error::MissingAttribute(AttributeType::PublicExponent)) + .map(|v| BigUint::from_bytes_be(v.as_slice()))?; + + let public_key = session.find_objects(&template)?.remove(0); + + let verifying_key = VerifyingKey::new(RsaPublicKey::new(modulus, public_exponent)?); + let salt_len = ::output_size(); + + Ok(Self { + session, + private_key, + _public_key: public_key, + verifying_key, + salt_len, + }) + } + + pub fn into_session(self) -> Session { + self.session + } +} + +impl AssociatedAlgorithmIdentifier for Signer { + type Params = AnyRef<'static>; + const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +} + +impl signature::Keypair for Signer { + type VerifyingKey = VerifyingKey; + + fn verifying_key(&self) -> Self::VerifyingKey { + self.verifying_key.clone() + } +} + +impl signature::Signer for Signer { + fn try_sign(&self, msg: &[u8]) -> Result { + let bytes = self + .session + .sign(&D::pss_mechanism(), self.private_key, msg) + .map_err(Error::Cryptoki) + .map_err(Box::new) + .map_err(signature::Error::from_source)?; + + let signature = Signature::try_from(bytes.as_slice())?; + + Ok(signature) + } +} + +impl DynSignatureAlgorithmIdentifier for Signer { + fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result { + get_pss_signature_algo_id::(self.salt_len as u8) + } +} + +fn get_pss_signature_algo_id(salt_len: u8) -> pkcs8::spki::Result +where + D: Digest + AssociatedOid, +{ + const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"); + + let pss_params = RsaPssParams::new::(salt_len); + + Ok(AlgorithmIdentifierOwned { + oid: ID_RSASSA_PSS, + parameters: Some(Any::encode_from(&pss_params)?), + }) +} diff --git a/cryptoki-rustcrypto/tests/common.rs b/cryptoki-rustcrypto/tests/common.rs new file mode 100644 index 00000000..9da0703b --- /dev/null +++ b/cryptoki-rustcrypto/tests/common.rs @@ -0,0 +1,44 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use cryptoki::context::{CInitializeArgs, Pkcs11}; +use cryptoki::session::UserType; +use cryptoki::slot::Slot; +use cryptoki::types::AuthPin; +use std::env; + +// The default user pin +pub static USER_PIN: &str = "fedcba"; +// The default SO pin +pub static SO_PIN: &str = "abcdef"; + +pub fn get_pkcs11() -> Pkcs11 { + Pkcs11::new( + env::var("PKCS11_SOFTHSM2_MODULE") + .unwrap_or_else(|_| "/usr/local/lib/softhsm/libsofthsm2.so".to_string()), + ) + .unwrap() +} + +pub fn init_pins() -> (Pkcs11, Slot) { + let pkcs11 = get_pkcs11(); + + // initialize the library + pkcs11.initialize(CInitializeArgs::OsThreads).unwrap(); + + // find a slot, get the first one + let slot = pkcs11.get_slots_with_token().unwrap().remove(0); + + let so_pin = AuthPin::new(SO_PIN.into()); + pkcs11.init_token(slot, &so_pin, "Test Token").unwrap(); + + { + // open a session + let session = pkcs11.open_rw_session(slot).unwrap(); + // log in the session + session.login(UserType::So, Some(&so_pin)).unwrap(); + session.init_pin(&AuthPin::new(USER_PIN.into())).unwrap(); + } + + (pkcs11, slot) +} diff --git a/cryptoki-rustcrypto/tests/rsa.rs b/cryptoki-rustcrypto/tests/rsa.rs new file mode 100644 index 00000000..8bb146a8 --- /dev/null +++ b/cryptoki-rustcrypto/tests/rsa.rs @@ -0,0 +1,121 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +mod common; + +use crate::common::USER_PIN; +use common::init_pins; +use cryptoki::{mechanism::Mechanism, object::Attribute, session::UserType, types::AuthPin}; +use cryptoki_rustcrypto::rsa::{pkcs1v15, pss}; +use serial_test::serial; +use signature::{Keypair, Signer, Verifier}; +use testresult::TestResult; + +#[test] +#[serial] +fn pkcs1v15_sign_verify() -> 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())))?; + + // get mechanism + let mechanism = Mechanism::RsaPkcsKeyPairGen; + + let public_exponent: Vec = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let label = b"demo-signer"; + + // pub key template + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Label(label.to_vec()), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + ]; + + // priv key template + let priv_key_template = vec![Attribute::Token(true), Attribute::Label(label.to_vec())]; + + // generate a key pair + let (public, private) = + session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; + + // data to sign + let data = [0xFF, 0x55, 0xDD]; + + let signer = + pkcs1v15::Signer::::new(session, label).expect("Lookup keys from HSM"); + + let signature = signer.sign(&data); + + let verifying_key = signer.verifying_key(); + verifying_key.verify(&data, &signature)?; + + let session = signer.into_session(); + + // delete keys + session.destroy_object(public)?; + session.destroy_object(private)?; + + Ok(()) +} + +#[test] +#[serial] +fn pss_sign_verify() -> 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())))?; + + // get mechanism + let mechanism = Mechanism::RsaPkcsKeyPairGen; + + let public_exponent: Vec = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let label = b"demo-signer"; + + // pub key template + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Label(label.to_vec()), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + ]; + + // priv key template + let priv_key_template = vec![Attribute::Token(true), Attribute::Label(label.to_vec())]; + + // generate a key pair + let (public, private) = + session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; + + // data to sign + let data = [0xFF, 0x55, 0xDD]; + + let signer = pss::Signer::::new(session, label).expect("Lookup keys from HSM"); + + let signature = signer.sign(&data); + + let verifying_key = signer.verifying_key(); + verifying_key.verify(&data, &signature)?; + + let session = signer.into_session(); + + // delete keys + session.destroy_object(public)?; + session.destroy_object(private)?; + + Ok(()) +} From 90e734cb355837513e89ab281fc6198a715cd3a0 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Thu, 23 Nov 2023 01:29:20 -0800 Subject: [PATCH 02/19] ecdsa support Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 3 + cryptoki-rustcrypto/src/ecdsa.rs | 184 +++++++++++++++++++++++++++++ cryptoki-rustcrypto/src/lib.rs | 1 + cryptoki-rustcrypto/tests/ecdsa.rs | 84 +++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 cryptoki-rustcrypto/src/ecdsa.rs create mode 100644 cryptoki-rustcrypto/tests/ecdsa.rs diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index dc35c4d7..44849564 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -8,10 +8,13 @@ readme = "README.md" keywords = ["pkcs11", "cryptoki", "hsm"] categories = ["cryptography", "hardware-support"] license = "Apache-2.0" +repository = "https://github.com/parallaxsecond/rust-cryptoki" [dependencies] cryptoki = { path = "../cryptoki", version = "0.6.1" } der = "0.7.8" +ecdsa = "0.16.9" +p256 = { version = "0.13.2", features = ["pkcs8"] } rsa = "0.9" signature = { version = "2.2.0", features = ["digest"] } sha1 = { version = "0.10", features = ["oid"] } diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs new file mode 100644 index 00000000..25f03bc3 --- /dev/null +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -0,0 +1,184 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use cryptoki::{ + mechanism::Mechanism, + object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, + session::Session, +}; +use der::{ + asn1::{ObjectIdentifier, OctetStringRef}, + oid::AssociatedOid, + AnyRef, Decode, Encode, +}; +use ecdsa::{ + elliptic_curve::{ + generic_array::ArrayLength, + sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, + AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, + }, + hazmat::DigestPrimitive, + PrimeCurve, Signature, VerifyingKey, +}; +use signature::digest::Digest; +use spki::{ + AlgorithmIdentifier, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, + SignatureAlgorithmIdentifier, +}; +use std::{convert::TryFrom, ops::Add}; +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("Cryptoki error: {0}")] + Cryptoki(#[from] cryptoki::error::Error), + + #[error("Private key missing attribute: {0}")] + MissingAttribute(AttributeType), + + #[error("Elliptic curve error: {0}")] + Ecdsa(#[from] ecdsa::elliptic_curve::Error), +} + +pub trait SignAlgorithm: PrimeCurve + CurveArithmetic + AssociatedOid + DigestPrimitive { + fn sign_mechanism() -> Mechanism<'static>; +} + +impl SignAlgorithm for p256::NistP256 { + fn sign_mechanism() -> Mechanism<'static> { + Mechanism::Ecdsa + } +} + +pub struct Signer { + session: Session, + _public_key: ObjectHandle, + private_key: ObjectHandle, + verifying_key: VerifyingKey, +} + +impl Signer +where + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + pub fn new(session: Session, 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), + Attribute::EcParams(C::OID.to_der().unwrap()), + Attribute::Sign(true), + ]; + + let private_key = session.find_objects(&template)?.remove(0); + let attribute_pk = session.get_attributes(private_key, &[AttributeType::Id])?; + + // Second we'll lookup a public key with the same label/ec params/ec point + let mut template = vec![ + Attribute::Private(false), + Attribute::Label(label.to_vec()), + Attribute::Class(ObjectClass::PUBLIC_KEY), + Attribute::KeyType(KeyType::EC), + Attribute::EcParams(C::OID.to_der().unwrap()), + ]; + let mut id = None; + for attribute in attribute_pk { + match attribute { + Attribute::Id(i) if id.is_none() => { + template.push(Attribute::Id(i.clone())); + id = Some(i); + } + _ => {} + } + } + + let public_key = session.find_objects(&template)?.remove(0); + let attribute_pk = session.get_attributes(public_key, &[AttributeType::EcPoint])?; + + let mut ec_point = None; + for attribute in attribute_pk { + match attribute { + Attribute::EcPoint(p) if ec_point.is_none() => { + ec_point = Some(p); + } + _ => {} + } + } + + let ec_point = ec_point.ok_or(Error::MissingAttribute(AttributeType::EcPoint))?; + + // documented as "DER-encoding of ANSI X9.62 ECPoint value Q" + // https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203418 + // https://www.rfc-editor.org/rfc/rfc5480#section-2.2 + let ec_point = OctetStringRef::from_der(&ec_point).unwrap(); + let public = PublicKey::::from_sec1_bytes(ec_point.as_bytes())?; + let verifying_key = public.into(); + + Ok(Self { + session, + private_key, + _public_key: public_key, + verifying_key, + }) + } + + pub fn into_session(self) -> Session { + self.session + } +} + +impl AssociatedAlgorithmIdentifier for Signer +where + C: AssociatedOid, +{ + type Params = ObjectIdentifier; + + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = + PublicKey::::ALGORITHM_IDENTIFIER; +} + +impl signature::Keypair for Signer { + type VerifyingKey = VerifyingKey; + + fn verifying_key(&self) -> Self::VerifyingKey { + self.verifying_key + } +} + +impl signature::Signer> for Signer +where + <::FieldBytesSize as Add>::Output: ArrayLength, +{ + fn try_sign(&self, msg: &[u8]) -> Result, signature::Error> { + println!("try sign"); + + let msg = C::Digest::digest(msg); + + let bytes = self + .session + .sign(&C::sign_mechanism(), self.private_key, &msg) + .map_err(Error::Cryptoki) + .map_err(Box::new) + .map_err(signature::Error::from_source)?; + + let signature = Signature::try_from(bytes.as_slice())?; + + Ok(signature) + } +} + +impl SignatureAlgorithmIdentifier for Signer +where + AffinePoint: FromEncodedPoint + ToEncodedPoint, + FieldBytesSize: ModulusSize, + Signature: AssociatedAlgorithmIdentifier>, +{ + type Params = AnyRef<'static>; + + const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = + Signature::::ALGORITHM_IDENTIFIER; +} diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index be249b9e..28aebb25 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -1,4 +1,5 @@ // Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 +pub mod ecdsa; pub mod rsa; diff --git a/cryptoki-rustcrypto/tests/ecdsa.rs b/cryptoki-rustcrypto/tests/ecdsa.rs new file mode 100644 index 00000000..eb083907 --- /dev/null +++ b/cryptoki-rustcrypto/tests/ecdsa.rs @@ -0,0 +1,84 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +mod common; + +use crate::common::USER_PIN; +use common::init_pins; +use cryptoki::{ + mechanism::Mechanism, + object::{Attribute, KeyType}, + session::UserType, + types::AuthPin, +}; +use cryptoki_rustcrypto::ecdsa; +use der::Encode; +use p256::pkcs8::AssociatedOid; +use serial_test::serial; +use signature::{Keypair, Signer, Verifier}; +use testresult::TestResult; + +#[test] +#[serial] +fn sign_verify() -> 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())))?; + + // get mechanism + let mechanism = Mechanism::EccKeyPairGen; + + let secp256r1_oid: Vec = p256::NistP256::OID.to_der().unwrap(); + println!("oid: {:x?}", secp256r1_oid); + + let label = b"demo-signer"; + + // pub key template + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::KeyType(KeyType::EC), + Attribute::Verify(true), + Attribute::EcParams(secp256r1_oid.clone()), + Attribute::Label(label.to_vec()), + ]; + + // priv key template + let priv_key_template = vec![ + Attribute::Token(true), + Attribute::Private(true), + //Attribute::KeyType(KeyType::EC), + //Attribute::EcParams(secp256r1_oid), + //Attribute::Sensitive(true), + //Attribute::Extractable(false), + Attribute::Sign(true), + Attribute::Label(label.to_vec()), + ]; + + // generate a key pair + let (public, private) = + session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; + + // data to sign + let data = [0xFF, 0x55, 0xDD]; + + let signer = + ecdsa::Signer::::new(session, label).expect("Lookup keys from HSM"); + + let signature = signer.sign(&data); + + let verifying_key = signer.verifying_key(); + verifying_key.verify(&data, &signature)?; + + let session = signer.into_session(); + + // delete keys + session.destroy_object(public)?; + session.destroy_object(private)?; + + Ok(()) +} From a229227d3ab94bfada200b0946b908819109b5b6 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Thu, 23 Nov 2023 22:27:33 -0800 Subject: [PATCH 03/19] demo x509 builder usage Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 4 +- cryptoki-rustcrypto/tests/x509-ca.rs | 83 ++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 cryptoki-rustcrypto/tests/x509-ca.rs diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index 44849564..ef75b9a8 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -19,9 +19,11 @@ rsa = "0.9" signature = { version = "2.2.0", features = ["digest"] } sha1 = { version = "0.10", features = ["oid"] } sha2 = { version = "0.10", features = ["oid"] } -spki = "0.7.2" +spki = "0.7.3" +x509-cert = "0.2.4" thiserror = "1.0" [dev-dependencies] serial_test = "0.5.1" testresult = "0.2.0" +x509-cert = { version = "0.2.4", features = ["builder"] } diff --git a/cryptoki-rustcrypto/tests/x509-ca.rs b/cryptoki-rustcrypto/tests/x509-ca.rs new file mode 100644 index 00000000..bd77a86e --- /dev/null +++ b/cryptoki-rustcrypto/tests/x509-ca.rs @@ -0,0 +1,83 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +mod common; + +use crate::common::USER_PIN; +use common::init_pins; +use cryptoki::{mechanism::Mechanism, object::Attribute, session::UserType, types::AuthPin}; +use cryptoki_rustcrypto::rsa::pss; +use der::{pem::LineEnding, EncodePem}; +use serial_test::serial; +use signature::Keypair; +use spki::SubjectPublicKeyInfoOwned; +use std::{str::FromStr, time::Duration}; +use testresult::TestResult; +use x509_cert::{ + builder::{Builder, CertificateBuilder, Profile}, + name::Name, + serial_number::SerialNumber, + time::Validity, +}; + +#[test] +#[serial] +fn pss_create_ca() -> 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())))?; + + // get mechanism + let mechanism = Mechanism::RsaPkcsKeyPairGen; + + let public_exponent: Vec = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let label = b"demo-signer"; + + // pub key template + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Label(label.to_vec()), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + ]; + + // priv key template + let priv_key_template = vec![Attribute::Token(true), Attribute::Label(label.to_vec())]; + + // generate a key pair + let (public, private) = + session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; + + let signer = pss::Signer::::new(session, label).expect("Lookup keys from HSM"); + + let serial_number = SerialNumber::from(42u32); + let validity = Validity::from_now(Duration::new(5, 0)).unwrap(); + let profile = Profile::Root; + let subject = + Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap(); + let pub_key = SubjectPublicKeyInfoOwned::from_key(signer.verifying_key()).unwrap(); + + let builder = + CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) + .expect("Create certificate"); + + let certificate = builder.build().unwrap(); + + let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); + println!("{}", pem); + + let session = signer.into_session(); + + // delete keys + session.destroy_object(public)?; + session.destroy_object(private)?; + + Ok(()) +} From ca7b17350468984d5e70c13f159548680ab0666a Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Thu, 23 Nov 2023 22:52:50 -0800 Subject: [PATCH 04/19] use a session ref Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/ecdsa.rs | 21 ++++++----- cryptoki-rustcrypto/src/lib.rs | 49 +++++++++++++++++++++++++ cryptoki-rustcrypto/src/rsa/pkcs1v15.rs | 24 ++++++------ cryptoki-rustcrypto/src/rsa/pss.rs | 24 ++++++------ cryptoki-rustcrypto/tests/ecdsa.rs | 4 +- cryptoki-rustcrypto/tests/rsa.rs | 9 ++--- cryptoki-rustcrypto/tests/x509-ca.rs | 5 +-- 7 files changed, 88 insertions(+), 48 deletions(-) diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index 25f03bc3..df8b7013 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -4,7 +4,6 @@ use cryptoki::{ mechanism::Mechanism, object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, - session::Session, }; use der::{ asn1::{ObjectIdentifier, OctetStringRef}, @@ -28,6 +27,8 @@ use spki::{ use std::{convert::TryFrom, ops::Add}; use thiserror::Error; +use crate::SessionLike; + #[derive(Error, Debug)] pub enum Error { #[error("Cryptoki error: {0}")] @@ -50,19 +51,19 @@ impl SignAlgorithm for p256::NistP256 { } } -pub struct Signer { - session: Session, +pub struct Signer { + session: S, _public_key: ObjectHandle, private_key: ObjectHandle, verifying_key: VerifyingKey, } -impl Signer +impl Signer where FieldBytesSize: ModulusSize, AffinePoint: FromEncodedPoint + ToEncodedPoint, { - pub fn new(session: Session, label: &[u8]) -> Result { + pub fn new(session: S, label: &[u8]) -> Result { // First we'll lookup a private key with that label. let template = vec![ Attribute::Token(true), @@ -126,12 +127,12 @@ where }) } - pub fn into_session(self) -> Session { + pub fn into_session(self) -> S { self.session } } -impl AssociatedAlgorithmIdentifier for Signer +impl AssociatedAlgorithmIdentifier for Signer where C: AssociatedOid, { @@ -141,7 +142,7 @@ where PublicKey::::ALGORITHM_IDENTIFIER; } -impl signature::Keypair for Signer { +impl signature::Keypair for Signer { type VerifyingKey = VerifyingKey; fn verifying_key(&self) -> Self::VerifyingKey { @@ -149,7 +150,7 @@ impl signature::Keypair for Signer { } } -impl signature::Signer> for Signer +impl signature::Signer> for Signer where <::FieldBytesSize as Add>::Output: ArrayLength, { @@ -171,7 +172,7 @@ where } } -impl SignatureAlgorithmIdentifier for Signer +impl SignatureAlgorithmIdentifier for Signer where AffinePoint: FromEncodedPoint + ToEncodedPoint, FieldBytesSize: ModulusSize, diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index 28aebb25..cda9612a 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -1,5 +1,54 @@ // Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 +use cryptoki::{ + error::Result, + mechanism::Mechanism, + object::{Attribute, AttributeType, ObjectHandle}, + session::Session, +}; + pub mod ecdsa; pub mod rsa; + +pub trait SessionLike { + fn find_objects(&self, template: &[Attribute]) -> Result>; + fn get_attributes( + &self, + object: ObjectHandle, + attributes: &[AttributeType], + ) -> Result>; + fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result>; +} + +impl SessionLike for Session { + fn find_objects(&self, template: &[Attribute]) -> Result> { + Session::find_objects(self, template) + } + fn get_attributes( + &self, + object: ObjectHandle, + attributes: &[AttributeType], + ) -> Result> { + Session::get_attributes(self, object, attributes) + } + fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { + Session::sign(self, mechanism, key, data) + } +} + +impl<'s> SessionLike for &'s Session { + fn find_objects(&self, template: &[Attribute]) -> Result> { + Session::find_objects(self, template) + } + fn get_attributes( + &self, + object: ObjectHandle, + attributes: &[AttributeType], + ) -> Result> { + Session::get_attributes(self, object, attributes) + } + fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { + Session::sign(self, mechanism, key, data) + } +} diff --git a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs index 754ecbec..15ed1ef9 100644 --- a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs +++ b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs @@ -1,10 +1,7 @@ // Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -use cryptoki::{ - object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, - session::Session, -}; +use cryptoki::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}; use der::AnyRef; use rsa::{ pkcs1, @@ -15,16 +12,17 @@ use spki::{AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, SignatureAlgor use std::convert::TryFrom; use super::{DigestSigning, Error}; +use crate::SessionLike; -pub struct Signer { - session: Session, +pub struct Signer { + session: S, _public_key: ObjectHandle, private_key: ObjectHandle, verifying_key: VerifyingKey, } -impl Signer { - pub fn new(session: Session, label: &[u8]) -> Result { +impl Signer { + pub fn new(session: S, label: &[u8]) -> Result { // First we'll lookup a private key with that label. let template = vec![ Attribute::Token(true), @@ -83,17 +81,17 @@ impl Signer { }) } - pub fn into_session(self) -> Session { + pub fn into_session(self) -> S { self.session } } -impl AssociatedAlgorithmIdentifier for Signer { +impl AssociatedAlgorithmIdentifier for Signer { type Params = AnyRef<'static>; const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; } -impl signature::Keypair for Signer { +impl signature::Keypair for Signer { type VerifyingKey = VerifyingKey; fn verifying_key(&self) -> Self::VerifyingKey { @@ -101,7 +99,7 @@ impl signature::Keypair for Signer { } } -impl signature::Signer for Signer { +impl signature::Signer for Signer { fn try_sign(&self, msg: &[u8]) -> Result { let bytes = self .session @@ -116,7 +114,7 @@ impl signature::Signer for Signer { } } -impl SignatureAlgorithmIdentifier for Signer { +impl SignatureAlgorithmIdentifier for Signer { type Params = AnyRef<'static>; const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = diff --git a/cryptoki-rustcrypto/src/rsa/pss.rs b/cryptoki-rustcrypto/src/rsa/pss.rs index 20acdbf8..1a5886fd 100644 --- a/cryptoki-rustcrypto/src/rsa/pss.rs +++ b/cryptoki-rustcrypto/src/rsa/pss.rs @@ -1,10 +1,7 @@ // Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -use cryptoki::{ - object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, - session::Session, -}; +use cryptoki::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}; use der::{asn1::ObjectIdentifier, oid::AssociatedOid, Any, AnyRef}; use rsa::{ pkcs1::{self, RsaPssParams}, @@ -20,17 +17,18 @@ use spki::{ use std::convert::TryFrom; use super::{DigestSigning, Error}; +use crate::SessionLike; -pub struct Signer { - session: Session, +pub struct Signer { + session: S, _public_key: ObjectHandle, private_key: ObjectHandle, verifying_key: VerifyingKey, salt_len: usize, } -impl Signer { - pub fn new(session: Session, label: &[u8]) -> Result { +impl Signer { + pub fn new(session: S, label: &[u8]) -> Result { // First we'll lookup a private key with that label. let template = vec![ Attribute::Token(true), @@ -91,17 +89,17 @@ impl Signer { }) } - pub fn into_session(self) -> Session { + pub fn into_session(self) -> S { self.session } } -impl AssociatedAlgorithmIdentifier for Signer { +impl AssociatedAlgorithmIdentifier for Signer { type Params = AnyRef<'static>; const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; } -impl signature::Keypair for Signer { +impl signature::Keypair for Signer { type VerifyingKey = VerifyingKey; fn verifying_key(&self) -> Self::VerifyingKey { @@ -109,7 +107,7 @@ impl signature::Keypair for Signer { } } -impl signature::Signer for Signer { +impl signature::Signer for Signer { fn try_sign(&self, msg: &[u8]) -> Result { let bytes = self .session @@ -124,7 +122,7 @@ impl signature::Signer for Signer { } } -impl DynSignatureAlgorithmIdentifier for Signer { +impl DynSignatureAlgorithmIdentifier for Signer { fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result { get_pss_signature_algo_id::(self.salt_len as u8) } diff --git a/cryptoki-rustcrypto/tests/ecdsa.rs b/cryptoki-rustcrypto/tests/ecdsa.rs index eb083907..21b42df6 100644 --- a/cryptoki-rustcrypto/tests/ecdsa.rs +++ b/cryptoki-rustcrypto/tests/ecdsa.rs @@ -67,15 +67,13 @@ fn sign_verify() -> TestResult { let data = [0xFF, 0x55, 0xDD]; let signer = - ecdsa::Signer::::new(session, label).expect("Lookup keys from HSM"); + ecdsa::Signer::::new(&session, label).expect("Lookup keys from HSM"); let signature = signer.sign(&data); let verifying_key = signer.verifying_key(); verifying_key.verify(&data, &signature)?; - let session = signer.into_session(); - // delete keys session.destroy_object(public)?; session.destroy_object(private)?; diff --git a/cryptoki-rustcrypto/tests/rsa.rs b/cryptoki-rustcrypto/tests/rsa.rs index 8bb146a8..35c5d5e6 100644 --- a/cryptoki-rustcrypto/tests/rsa.rs +++ b/cryptoki-rustcrypto/tests/rsa.rs @@ -50,15 +50,13 @@ fn pkcs1v15_sign_verify() -> TestResult { let data = [0xFF, 0x55, 0xDD]; let signer = - pkcs1v15::Signer::::new(session, label).expect("Lookup keys from HSM"); + pkcs1v15::Signer::::new(&session, label).expect("Lookup keys from HSM"); let signature = signer.sign(&data); let verifying_key = signer.verifying_key(); verifying_key.verify(&data, &signature)?; - let session = signer.into_session(); - // delete keys session.destroy_object(public)?; session.destroy_object(private)?; @@ -104,15 +102,14 @@ fn pss_sign_verify() -> TestResult { // data to sign let data = [0xFF, 0x55, 0xDD]; - let signer = pss::Signer::::new(session, label).expect("Lookup keys from HSM"); + let signer = + pss::Signer::::new(&session, label).expect("Lookup keys from HSM"); let signature = signer.sign(&data); let verifying_key = signer.verifying_key(); verifying_key.verify(&data, &signature)?; - let session = signer.into_session(); - // delete keys session.destroy_object(public)?; session.destroy_object(private)?; diff --git a/cryptoki-rustcrypto/tests/x509-ca.rs b/cryptoki-rustcrypto/tests/x509-ca.rs index bd77a86e..db95a483 100644 --- a/cryptoki-rustcrypto/tests/x509-ca.rs +++ b/cryptoki-rustcrypto/tests/x509-ca.rs @@ -55,7 +55,8 @@ fn pss_create_ca() -> TestResult { let (public, private) = session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; - let signer = pss::Signer::::new(session, label).expect("Lookup keys from HSM"); + let signer = + pss::Signer::::new(&session, label).expect("Lookup keys from HSM"); let serial_number = SerialNumber::from(42u32); let validity = Validity::from_now(Duration::new(5, 0)).unwrap(); @@ -73,8 +74,6 @@ fn pss_create_ca() -> TestResult { let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", pem); - let session = signer.into_session(); - // delete keys session.destroy_object(public)?; session.destroy_object(private)?; From 2e072d6634b265764156bee8effe8dfad3a26783 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 25 Nov 2023 13:57:34 -0800 Subject: [PATCH 05/19] Add helpers to read public keys Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/ecdsa.rs | 79 +++++++++++++++---------- cryptoki-rustcrypto/src/rsa/mod.rs | 60 +++++++++++++++++-- cryptoki-rustcrypto/src/rsa/pkcs1v15.rs | 27 ++------- cryptoki-rustcrypto/src/rsa/pss.rs | 27 ++------- 4 files changed, 116 insertions(+), 77 deletions(-) diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index df8b7013..7f73f049 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -29,6 +29,47 @@ use thiserror::Error; use crate::SessionLike; +pub fn read_key( + session: &S, + template: impl Into>, +) -> Result, Error> +where + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + 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 keys = session.find_objects(&template)?; + if let Some(public_key) = keys.first() { + let attribute_pub = session.get_attributes(*public_key, &[AttributeType::EcPoint])?; + + let mut ec_point = None; + for attribute in attribute_pub { + match attribute { + Attribute::EcPoint(p) if ec_point.is_none() => { + ec_point = Some(p); + break; + } + _ => {} + } + } + + let ec_point = ec_point.ok_or(Error::MissingAttribute(AttributeType::EcPoint))?; + + // documented as "DER-encoding of ANSI X9.62 ECPoint value Q" + // https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203418 + // https://www.rfc-editor.org/rfc/rfc5480#section-2.2 + let ec_point = OctetStringRef::from_der(&ec_point).unwrap(); + + Ok(PublicKey::::from_sec1_bytes(ec_point.as_bytes())?) + } else { + Err(Error::MissingKey) + } +} + #[derive(Error, Debug)] pub enum Error { #[error("Cryptoki error: {0}")] @@ -39,6 +80,9 @@ pub enum Error { #[error("Elliptic curve error: {0}")] Ecdsa(#[from] ecdsa::elliptic_curve::Error), + + #[error("Key not found")] + MissingKey, } pub trait SignAlgorithm: PrimeCurve + CurveArithmetic + AssociatedOid + DigestPrimitive { @@ -53,7 +97,6 @@ impl SignAlgorithm for p256::NistP256 { pub struct Signer { session: S, - _public_key: ObjectHandle, private_key: ObjectHandle, verifying_key: VerifyingKey, } @@ -76,18 +119,12 @@ where ]; let private_key = session.find_objects(&template)?.remove(0); - let attribute_pk = session.get_attributes(private_key, &[AttributeType::Id])?; + let attribute_priv = session.get_attributes(private_key, &[AttributeType::Id])?; // Second we'll lookup a public key with the same label/ec params/ec point - let mut template = vec![ - Attribute::Private(false), - Attribute::Label(label.to_vec()), - Attribute::Class(ObjectClass::PUBLIC_KEY), - Attribute::KeyType(KeyType::EC), - Attribute::EcParams(C::OID.to_der().unwrap()), - ]; + let mut template = vec![Attribute::Private(false), Attribute::Label(label.to_vec())]; let mut id = None; - for attribute in attribute_pk { + for attribute in attribute_priv { match attribute { Attribute::Id(i) if id.is_none() => { template.push(Attribute::Id(i.clone())); @@ -97,32 +134,14 @@ where } } - let public_key = session.find_objects(&template)?.remove(0); - let attribute_pk = session.get_attributes(public_key, &[AttributeType::EcPoint])?; - - let mut ec_point = None; - for attribute in attribute_pk { - match attribute { - Attribute::EcPoint(p) if ec_point.is_none() => { - ec_point = Some(p); - } - _ => {} - } - } - - let ec_point = ec_point.ok_or(Error::MissingAttribute(AttributeType::EcPoint))?; + id.ok_or(Error::MissingAttribute(AttributeType::Id))?; - // documented as "DER-encoding of ANSI X9.62 ECPoint value Q" - // https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/os/pkcs11-spec-v3.1-os.html#_Toc111203418 - // https://www.rfc-editor.org/rfc/rfc5480#section-2.2 - let ec_point = OctetStringRef::from_der(&ec_point).unwrap(); - let public = PublicKey::::from_sec1_bytes(ec_point.as_bytes())?; + let public = read_key(&session, template)?; let verifying_key = public.into(); Ok(Self { session, private_key, - _public_key: public_key, verifying_key, }) } diff --git a/cryptoki-rustcrypto/src/rsa/mod.rs b/cryptoki-rustcrypto/src/rsa/mod.rs index ed91014a..876af778 100644 --- a/cryptoki-rustcrypto/src/rsa/mod.rs +++ b/cryptoki-rustcrypto/src/rsa/mod.rs @@ -1,20 +1,67 @@ // Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -use cryptoki::mechanism::{ - rsa::{PkcsMgfType, PkcsPssParams}, - Mechanism, MechanismType, +use cryptoki::{ + mechanism::{ + rsa::{PkcsMgfType, PkcsPssParams}, + Mechanism, MechanismType, + }, + object::{Attribute, AttributeType, KeyType, ObjectClass}, }; -use cryptoki::object::AttributeType; use der::oid::AssociatedOid; +use rsa::{BigUint, RsaPublicKey}; use signature::digest::Digest; use std::convert::TryInto; use thiserror::Error; -pub mod pkcs1v15; +use crate::SessionLike; +pub mod pkcs1v15; pub mod pss; +pub fn read_key( + session: &S, + template: impl Into>, +) -> Result { + let mut template: Vec = template.into(); + template.push(Attribute::Class(ObjectClass::PUBLIC_KEY)); + template.push(Attribute::KeyType(KeyType::RSA)); + + let keys = session.find_objects(&template)?; + if let Some(key) = keys.first() { + let attribute_priv = session.get_attributes( + *key, + &[AttributeType::Modulus, AttributeType::PublicExponent], + )?; + + let mut modulus = None; + let mut public_exponent = None; + + for attribute in attribute_priv { + match attribute { + Attribute::Modulus(m) if modulus.is_none() => { + modulus = Some(m.clone()); + } + Attribute::PublicExponent(e) if public_exponent.is_none() => { + public_exponent = Some(e.clone()); + } + _ => {} + } + } + + let modulus = modulus + .ok_or(Error::MissingAttribute(AttributeType::Modulus)) + .map(|v| BigUint::from_bytes_be(v.as_slice()))?; + let public_exponent = public_exponent + .ok_or(Error::MissingAttribute(AttributeType::PublicExponent)) + .map(|v| BigUint::from_bytes_be(v.as_slice()))?; + + Ok(RsaPublicKey::new(modulus, public_exponent)?) + } else { + Err(Error::MissingKey) + } +} + #[derive(Debug, Error)] pub enum Error { #[error("Cryptoki error: {0}")] @@ -25,6 +72,9 @@ pub enum Error { #[error("RSA error: {0}")] Rsa(#[from] rsa::Error), + + #[error("Key not found")] + MissingKey, } pub trait DigestSigning: Digest + AssociatedOid { diff --git a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs index 15ed1ef9..753bb36d 100644 --- a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs +++ b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs @@ -6,17 +6,15 @@ use der::AnyRef; use rsa::{ pkcs1, pkcs1v15::{Signature, VerifyingKey}, - BigUint, RsaPublicKey, }; use spki::{AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}; use std::convert::TryFrom; -use super::{DigestSigning, Error}; +use super::{read_key, DigestSigning, Error}; use crate::SessionLike; pub struct Signer { session: S, - _public_key: ObjectHandle, private_key: ObjectHandle, verifying_key: VerifyingKey, } @@ -34,21 +32,16 @@ impl Signer { ]; let private_key = session.find_objects(&template)?.remove(0); - let attribute_pk = session.get_attributes( + let attribute_priv = session.get_attributes( private_key, &[AttributeType::Modulus, AttributeType::PublicExponent], )?; // Second we'll lookup a public key with the same label/modulus/public exponent - let mut template = vec![ - Attribute::Private(false), - Attribute::Label(label.to_vec()), - Attribute::Class(ObjectClass::PUBLIC_KEY), - Attribute::KeyType(KeyType::RSA), - ]; + let mut template = vec![Attribute::Private(false), Attribute::Label(label.to_vec())]; let mut modulus = None; let mut public_exponent = None; - for attribute in attribute_pk { + for attribute in attribute_priv { match attribute { Attribute::Modulus(m) if modulus.is_none() => { modulus = Some(m.clone()); @@ -62,21 +55,13 @@ impl Signer { } } - let modulus = modulus - .ok_or(Error::MissingAttribute(AttributeType::Modulus)) - .map(|v| BigUint::from_bytes_be(v.as_slice()))?; - let public_exponent = public_exponent - .ok_or(Error::MissingAttribute(AttributeType::PublicExponent)) - .map(|v| BigUint::from_bytes_be(v.as_slice()))?; - - let public_key = session.find_objects(&template)?.remove(0); + let public_key = read_key(&session, template)?; - let verifying_key = VerifyingKey::new(RsaPublicKey::new(modulus, public_exponent)?); + let verifying_key = VerifyingKey::new(public_key); Ok(Self { session, private_key, - _public_key: public_key, verifying_key, }) } diff --git a/cryptoki-rustcrypto/src/rsa/pss.rs b/cryptoki-rustcrypto/src/rsa/pss.rs index 1a5886fd..84fbae02 100644 --- a/cryptoki-rustcrypto/src/rsa/pss.rs +++ b/cryptoki-rustcrypto/src/rsa/pss.rs @@ -7,7 +7,6 @@ use rsa::{ pkcs1::{self, RsaPssParams}, pkcs8::{self}, pss::{Signature, VerifyingKey}, - BigUint, RsaPublicKey, }; use signature::digest::Digest; use spki::{ @@ -16,12 +15,11 @@ use spki::{ }; use std::convert::TryFrom; -use super::{DigestSigning, Error}; +use super::{read_key, DigestSigning, Error}; use crate::SessionLike; pub struct Signer { session: S, - _public_key: ObjectHandle, private_key: ObjectHandle, verifying_key: VerifyingKey, salt_len: usize, @@ -40,21 +38,16 @@ impl Signer { ]; let private_key = session.find_objects(&template)?.remove(0); - let attribute_pk = session.get_attributes( + let attribute_priv = session.get_attributes( private_key, &[AttributeType::Modulus, AttributeType::PublicExponent], )?; // Second we'll lookup a public key with the same label/modulus/public exponent - let mut template = vec![ - Attribute::Private(false), - Attribute::Label(label.to_vec()), - Attribute::Class(ObjectClass::PUBLIC_KEY), - Attribute::KeyType(KeyType::RSA), - ]; + let mut template = vec![Attribute::Private(false), Attribute::Label(label.to_vec())]; let mut modulus = None; let mut public_exponent = None; - for attribute in attribute_pk { + for attribute in attribute_priv { match attribute { Attribute::Modulus(m) if modulus.is_none() => { modulus = Some(m.clone()); @@ -68,22 +61,14 @@ impl Signer { } } - let modulus = modulus - .ok_or(Error::MissingAttribute(AttributeType::Modulus)) - .map(|v| BigUint::from_bytes_be(v.as_slice()))?; - let public_exponent = public_exponent - .ok_or(Error::MissingAttribute(AttributeType::PublicExponent)) - .map(|v| BigUint::from_bytes_be(v.as_slice()))?; - - let public_key = session.find_objects(&template)?.remove(0); + let public_key = read_key(&session, template)?; - let verifying_key = VerifyingKey::new(RsaPublicKey::new(modulus, public_exponent)?); + let verifying_key = VerifyingKey::new(public_key); let salt_len = ::output_size(); Ok(Self { session, private_key, - _public_key: public_key, verifying_key, salt_len, }) From f33323999f46cfddaeff1dba8e2a77bb5933772e Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 25 Nov 2023 14:03:16 -0800 Subject: [PATCH 06/19] ecdsa: bring support for k256, p224 and p384 Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 3 +++ cryptoki-rustcrypto/src/ecdsa.rs | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index ef75b9a8..680dc891 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -14,7 +14,10 @@ repository = "https://github.com/parallaxsecond/rust-cryptoki" cryptoki = { path = "../cryptoki", version = "0.6.1" } der = "0.7.8" ecdsa = "0.16.9" +p224 = { version = "0.13.2", features = ["pkcs8"] } p256 = { version = "0.13.2", features = ["pkcs8"] } +p384 = { version = "0.13.0", features = ["pkcs8"] } +k256 = { version = "0.13.2", features = ["pkcs8"] } rsa = "0.9" signature = { version = "2.2.0", features = ["digest"] } sha1 = { version = "0.10", features = ["oid"] } diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index 7f73f049..8a1e9c5d 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -89,12 +89,21 @@ pub trait SignAlgorithm: PrimeCurve + CurveArithmetic + AssociatedOid + DigestPr fn sign_mechanism() -> Mechanism<'static>; } -impl SignAlgorithm for p256::NistP256 { - fn sign_mechanism() -> Mechanism<'static> { - Mechanism::Ecdsa - } +macro_rules! impl_sign_algorithm { + ($ec:ty) => { + impl SignAlgorithm for $ec { + fn sign_mechanism() -> Mechanism<'static> { + Mechanism::Ecdsa + } + } + }; } +impl_sign_algorithm!(p224::NistP224); +impl_sign_algorithm!(p256::NistP256); +impl_sign_algorithm!(p384::NistP384); +impl_sign_algorithm!(k256::Secp256k1); + pub struct Signer { session: S, private_key: ObjectHandle, From 2c6186ec8bc0b043d636688ae8558b934736fc97 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sat, 25 Nov 2023 22:46:59 -0800 Subject: [PATCH 07/19] adds x509 certificate support Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/lib.rs | 8 +++ cryptoki-rustcrypto/src/x509.rs | 95 +++++++++++++++++++++++++ cryptoki-rustcrypto/tests/verisign.der | Bin 0 -> 1582 bytes cryptoki-rustcrypto/tests/x509.rs | 41 +++++++++++ 4 files changed, 144 insertions(+) create mode 100644 cryptoki-rustcrypto/src/x509.rs create mode 100644 cryptoki-rustcrypto/tests/verisign.der create mode 100644 cryptoki-rustcrypto/tests/x509.rs diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index cda9612a..68b1ccc3 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -10,8 +10,10 @@ use cryptoki::{ pub mod ecdsa; pub mod rsa; +pub mod x509; pub trait SessionLike { + fn create_object(&self, template: &[Attribute]) -> Result; fn find_objects(&self, template: &[Attribute]) -> Result>; fn get_attributes( &self, @@ -22,6 +24,9 @@ pub trait SessionLike { } impl SessionLike for Session { + fn create_object(&self, template: &[Attribute]) -> Result { + Session::create_object(self, template) + } fn find_objects(&self, template: &[Attribute]) -> Result> { Session::find_objects(self, template) } @@ -38,6 +43,9 @@ impl SessionLike for Session { } impl<'s> SessionLike for &'s Session { + fn create_object(&self, template: &[Attribute]) -> Result { + Session::create_object(self, template) + } fn find_objects(&self, template: &[Attribute]) -> Result> { Session::find_objects(self, template) } diff --git a/cryptoki-rustcrypto/src/x509.rs b/cryptoki-rustcrypto/src/x509.rs new file mode 100644 index 00000000..76461c8a --- /dev/null +++ b/cryptoki-rustcrypto/src/x509.rs @@ -0,0 +1,95 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use cryptoki::object::{Attribute, AttributeType, CertificateType, ObjectClass, ObjectHandle}; +use thiserror::Error; +use x509_cert::{ + certificate::{CertificateInner, Profile}, + der::{Decode, Encode}, +}; + +use crate::SessionLike; + +#[derive(Debug, Error)] +pub enum Error { + #[error("Cryptoki error: {0}")] + Cryptoki(#[from] cryptoki::error::Error), + + #[error("Missing attribute: {0}")] + MissingAttribute(AttributeType), + + #[error(transparent)] + Der(#[from] x509_cert::der::Error), + + #[error("No such certificate found")] + MissingCert, +} + +pub trait CertPkcs11 { + fn pkcs11_store>>( + &self, + session: &S, + base_template: T, + ) -> Result; + + fn pkcs11_load>>( + session: &S, + template: T, + ) -> Result + where + Self: Sized; +} + +impl

CertPkcs11 for CertificateInner

+where + P: Profile, +{ + fn pkcs11_store>>( + &self, + session: &S, + base_template: T, + ) -> Result { + let mut template = base_template.into(); + template.push(Attribute::Class(ObjectClass::CERTIFICATE)); + template.push(Attribute::CertificateType(CertificateType::X_509)); + template.push(Attribute::Token(true)); + template.push(Attribute::Value(self.to_der()?)); + if !self.tbs_certificate.subject.is_empty() { + template.push(Attribute::Subject(self.tbs_certificate.subject.to_der()?)); + } + + Ok(session.create_object(&template)?) + } + + fn pkcs11_load>>( + session: &S, + template: T, + ) -> Result { + let mut template = template.into(); + template.push(Attribute::Class(ObjectClass::CERTIFICATE)); + template.push(Attribute::CertificateType(CertificateType::X_509)); + + let certs = session.find_objects(&template)?; + if let Some(cert) = certs.first() { + let attributes = session.get_attributes(*cert, &[AttributeType::Value])?; + + let mut value = None; + for attribute in attributes { + match attribute { + Attribute::Value(v) if value.is_none() => { + value = Some(v); + } + _ => {} + } + } + + let value = value.ok_or(Error::MissingAttribute(AttributeType::Value))?; + + let cert = Self::from_der(&value)?; + + Ok(cert) + } else { + Err(Error::MissingCert) + } + } +} diff --git a/cryptoki-rustcrypto/tests/verisign.der b/cryptoki-rustcrypto/tests/verisign.der new file mode 100644 index 0000000000000000000000000000000000000000..d94106f82a6e99fe50725261735e5eb377421147 GIT binary patch literal 1582 zcmb_cYfuwc6wYoo8$m%Z7?9`6LjxhunHlBxDv9sS&U$<7&T*c zlv3*yDRv^-YEdgy>w|)%YHcaDOb4e@TdUYo@mWCdiETH;IAuEi>;AcW&-?rCIR{L5 z7?=c;EPNC}QMVOEP4CD$Z(i`p^1t-Bt1lE>aHlYHviXq=^dCn>?-(}e_3l94d_<$1brWhhC7B2pQn zjLC!bE&mtTSrB6ftH{(ar3Qj79tERfiRCO?W{8c5FdB{WRUCx|jzYPbE{$NyR0PKi z31k$^u%ngz2W^U;)iC-|a4H>_qaF zmCA3s#g_)vv+?-vVZ*%8;5`SoJehz0*dLY`KUMMQQh0+Z9cSZd&#-Zsuh=#y~5W_kwb_$$W|lQXgXR; zkL|QohEbU0k&KaYME{cF*_<$GrBRB5oKysq)e-na|#HxRp^cd0nL@@5wQT|Uxng3>BXCpq_O{Kj^wwDe&+>f>)5We0Cm_J44#K=ZT;;K@ zOSAv%)w^HxgVTe=n5XEGNX~!k>f>ey;Z5-TGvFD&)@p1SnQUDYBB*PaEw!ds&S`&o zUvc~M_qJ5jrY%oU)vO*ob>M#629Lh@ep%4up5P|9CG_#@?TuRJCPRd}j86?Sa|YD8 zOHb^r3;$Z4)^qQTfz6+7z@$P}KC(NyaQ^$l!Li@DSDh=7Ha 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 cert = Certificate::from_der(VERISIGN_CERT).expect("read certificate from der"); + + let base_template = vec![Attribute::Label(b"demo-cert".to_vec())]; + + cert.pkcs11_store(&session, base_template.clone()) + .expect("Store cert with the PKCS11 provider"); + + let new = Certificate::pkcs11_load(&session, base_template) + .expect("Lookup cert from PKCS11 provider"); + + assert_eq!(cert, new); + + Ok(()) +} From 930d4ff05aaf279c2299fc82cf62700c47895e99 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 26 Nov 2023 14:18:42 -0800 Subject: [PATCH 08/19] provide a cryptoki-backed CSPRNG Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/lib.rs | 8 +++++ cryptoki-rustcrypto/src/rng.rs | 55 ++++++++++++++++++++++++++++++ cryptoki-rustcrypto/tests/rng.rs | 57 ++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 cryptoki-rustcrypto/src/rng.rs create mode 100644 cryptoki-rustcrypto/tests/rng.rs diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index 68b1ccc3..1500192c 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -9,6 +9,7 @@ use cryptoki::{ }; pub mod ecdsa; +pub mod rng; pub mod rsa; pub mod x509; @@ -21,6 +22,7 @@ pub trait SessionLike { attributes: &[AttributeType], ) -> Result>; fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result>; + fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()>; } impl SessionLike for Session { @@ -40,6 +42,9 @@ impl SessionLike for Session { fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { Session::sign(self, mechanism, key, data) } + fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> { + Session::generate_random_slice(self, random_data) + } } impl<'s> SessionLike for &'s Session { @@ -59,4 +64,7 @@ impl<'s> SessionLike for &'s Session { fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { Session::sign(self, mechanism, key, data) } + fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> { + Session::generate_random_slice(self, random_data) + } } diff --git a/cryptoki-rustcrypto/src/rng.rs b/cryptoki-rustcrypto/src/rng.rs new file mode 100644 index 00000000..551f6415 --- /dev/null +++ b/cryptoki-rustcrypto/src/rng.rs @@ -0,0 +1,55 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use signature::rand_core::{CryptoRng, Error as RndError, RngCore}; +use thiserror::Error; + +use crate::SessionLike; + +#[derive(Debug, Error)] +pub enum Error {} + +/// [`Rng`] is a PKCS#11-backed CSPRNG. +/// +/// ## Panics +/// +/// The [`RngCore::fill_bytes`] implementation may panic if the provider was +/// unable to return enough bytes. +pub struct Rng(S); + +// TODO(baloo): check for CKF_RNG bit flag (CK_TOKEN_INFO struct -> flags) +impl Rng { + pub fn new(session: S) -> Result { + Ok(Self(session)) + } +} + +macro_rules! impl_next_uint { + ($self:ident, $u:ty) => {{ + let mut buf = <$u>::MIN.to_be_bytes(); + $self.fill_bytes(&mut buf[..]); + + <$u>::from_be_bytes(buf) + }}; +} + +impl RngCore for Rng { + fn next_u32(&mut self) -> u32 { + impl_next_uint!(self, u32) + } + + fn next_u64(&mut self) -> u64 { + impl_next_uint!(self, u64) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + self.try_fill_bytes(dest) + .expect("Cryptoki provider failed to generate random"); + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), RndError> { + self.0.generate_random_slice(dest).map_err(RndError::new) + } +} + +impl CryptoRng for Rng {} diff --git a/cryptoki-rustcrypto/tests/rng.rs b/cryptoki-rustcrypto/tests/rng.rs new file mode 100644 index 00000000..38184d6a --- /dev/null +++ b/cryptoki-rustcrypto/tests/rng.rs @@ -0,0 +1,57 @@ +// Copyright 2023 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +mod common; + +use crate::common::USER_PIN; +use common::init_pins; +use cryptoki::{session::UserType, types::AuthPin}; +use cryptoki_rustcrypto::rng::Rng; +use serial_test::serial; +use signature::rand_core::{CryptoRngCore, RngCore}; +use testresult::TestResult; + +// This test is meant to ensure we provide [`rand_core::CryptoRngCore`]. +// This is the trait consumers will use throughout the RustCrypto ecosystem +// to express interest in a CSPRNG. +#[test] +#[serial] +fn ensure_crypto_rng_core() -> TestResult { + fn just_making_sure(_r: &mut R) { + // Hi! just making sure you provide a CSPRNG. + } + 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 = Rng::new(session).unwrap(); + just_making_sure(&mut rng); + + Ok(()) +} + +#[test] +#[serial] +fn generate_random() -> 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 = Rng::new(session).unwrap(); + rng.next_u32(); + rng.next_u64(); + + let mut buf = vec![0; 123]; + rng.fill_bytes(&mut buf); + rng.try_fill_bytes(&mut buf).unwrap(); + + Ok(()) +} From a54820b02d6ee2c0b434f706a0445f8cc1955d65 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 28 Nov 2023 15:12:07 -0800 Subject: [PATCH 09/19] fixup pss Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 2 +- cryptoki-rustcrypto/src/rsa/pss.rs | 21 ++------------------- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index 680dc891..45b8c00a 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -18,7 +18,7 @@ p224 = { version = "0.13.2", features = ["pkcs8"] } p256 = { version = "0.13.2", features = ["pkcs8"] } p384 = { version = "0.13.0", features = ["pkcs8"] } k256 = { version = "0.13.2", features = ["pkcs8"] } -rsa = "0.9" +rsa = "0.9.6" signature = { version = "2.2.0", features = ["digest"] } sha1 = { version = "0.10", features = ["oid"] } sha2 = { version = "0.10", features = ["oid"] } diff --git a/cryptoki-rustcrypto/src/rsa/pss.rs b/cryptoki-rustcrypto/src/rsa/pss.rs index 84fbae02..b474a7de 100644 --- a/cryptoki-rustcrypto/src/rsa/pss.rs +++ b/cryptoki-rustcrypto/src/rsa/pss.rs @@ -6,7 +6,7 @@ use der::{asn1::ObjectIdentifier, oid::AssociatedOid, Any, AnyRef}; use rsa::{ pkcs1::{self, RsaPssParams}, pkcs8::{self}, - pss::{Signature, VerifyingKey}, + pss::{get_default_pss_signature_algo_id, Signature, VerifyingKey}, }; use signature::digest::Digest; use spki::{ @@ -22,7 +22,6 @@ pub struct Signer { session: S, private_key: ObjectHandle, verifying_key: VerifyingKey, - salt_len: usize, } impl Signer { @@ -64,13 +63,11 @@ impl Signer { let public_key = read_key(&session, template)?; let verifying_key = VerifyingKey::new(public_key); - let salt_len = ::output_size(); Ok(Self { session, private_key, verifying_key, - salt_len, }) } @@ -109,20 +106,6 @@ impl signature::Signer for Signer DynSignatureAlgorithmIdentifier for Signer { fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result { - get_pss_signature_algo_id::(self.salt_len as u8) + get_default_pss_signature_algo_id::() } } - -fn get_pss_signature_algo_id(salt_len: u8) -> pkcs8::spki::Result -where - D: Digest + AssociatedOid, -{ - const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"); - - let pss_params = RsaPssParams::new::(salt_len); - - Ok(AlgorithmIdentifierOwned { - oid: ID_RSASSA_PSS, - parameters: Some(Any::encode_from(&pss_params)?), - }) -} From b54ada2bb6f79ea9973b219882c849bf6bff52b1 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 28 Nov 2023 19:49:18 -0800 Subject: [PATCH 10/19] rework rsa signer algorithm Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/rsa/pkcs1v15.rs | 34 +++++++++++++------------ cryptoki-rustcrypto/src/rsa/pss.rs | 5 ++-- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs index 753bb36d..625ea1b8 100644 --- a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs +++ b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs @@ -2,12 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use cryptoki::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}; -use der::AnyRef; -use rsa::{ - pkcs1, - pkcs1v15::{Signature, VerifyingKey}, -}; -use spki::{AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}; +use rsa::pkcs1v15::{RsaSignatureAssociatedOid, Signature, VerifyingKey}; +use spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}; use std::convert::TryFrom; use super::{read_key, DigestSigning, Error}; @@ -71,9 +67,14 @@ impl Signer { } } -impl AssociatedAlgorithmIdentifier for Signer { - type Params = AnyRef<'static>; - const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID; +impl AssociatedAlgorithmIdentifier for Signer +where + D: DigestSigning, + S: SessionLike, +{ + type Params = as AssociatedAlgorithmIdentifier>::Params; + const ALGORITHM_IDENTIFIER: AlgorithmIdentifier = + as AssociatedAlgorithmIdentifier>::ALGORITHM_IDENTIFIER; } impl signature::Keypair for Signer { @@ -99,12 +100,13 @@ impl signature::Signer for Signer SignatureAlgorithmIdentifier for Signer { - type Params = AnyRef<'static>; +impl SignatureAlgorithmIdentifier for Signer +where + S: SessionLike, + D: DigestSigning + RsaSignatureAssociatedOid, +{ + type Params = as SignatureAlgorithmIdentifier>::Params; - const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = - AlgorithmIdentifierRef { - oid: D::OID, - parameters: Some(AnyRef::NULL), - }; + const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier = + as SignatureAlgorithmIdentifier>::SIGNATURE_ALGORITHM_IDENTIFIER; } diff --git a/cryptoki-rustcrypto/src/rsa/pss.rs b/cryptoki-rustcrypto/src/rsa/pss.rs index b474a7de..303248f8 100644 --- a/cryptoki-rustcrypto/src/rsa/pss.rs +++ b/cryptoki-rustcrypto/src/rsa/pss.rs @@ -2,13 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use cryptoki::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}; -use der::{asn1::ObjectIdentifier, oid::AssociatedOid, Any, AnyRef}; +use der::AnyRef; use rsa::{ - pkcs1::{self, RsaPssParams}, + pkcs1, pkcs8::{self}, pss::{get_default_pss_signature_algo_id, Signature, VerifyingKey}, }; -use signature::digest::Digest; use spki::{ AlgorithmIdentifierOwned, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier, From eadf645560721a74814573498fbabefb5602bdcc Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 28 Nov 2023 19:49:42 -0800 Subject: [PATCH 11/19] cleanup Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/ecdsa.rs | 2 -- cryptoki-rustcrypto/tests/ecdsa.rs | 4 ---- 2 files changed, 6 deletions(-) diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index 8a1e9c5d..b19bde16 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -183,8 +183,6 @@ where <::FieldBytesSize as Add>::Output: ArrayLength, { fn try_sign(&self, msg: &[u8]) -> Result, signature::Error> { - println!("try sign"); - let msg = C::Digest::digest(msg); let bytes = self diff --git a/cryptoki-rustcrypto/tests/ecdsa.rs b/cryptoki-rustcrypto/tests/ecdsa.rs index 21b42df6..73824c86 100644 --- a/cryptoki-rustcrypto/tests/ecdsa.rs +++ b/cryptoki-rustcrypto/tests/ecdsa.rs @@ -51,10 +51,6 @@ fn sign_verify() -> TestResult { let priv_key_template = vec![ Attribute::Token(true), Attribute::Private(true), - //Attribute::KeyType(KeyType::EC), - //Attribute::EcParams(secp256r1_oid), - //Attribute::Sensitive(true), - //Attribute::Extractable(false), Attribute::Sign(true), Attribute::Label(label.to_vec()), ]; From cfcb567a52b3a5f2c9456d0a3c5a8e2790512aa1 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 2 Jan 2024 10:42:57 -0800 Subject: [PATCH 12/19] fixup ecdsa signer implementation Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 2 +- cryptoki-rustcrypto/src/ecdsa.rs | 24 +++++++-- cryptoki-rustcrypto/tests/ecdsa.rs | 2 +- cryptoki-rustcrypto/tests/x509-ca.rs | 78 ++++++++++++++++++++++++++-- 4 files changed, 97 insertions(+), 9 deletions(-) diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index 45b8c00a..74fa9c99 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -19,7 +19,7 @@ p256 = { version = "0.13.2", features = ["pkcs8"] } p384 = { version = "0.13.0", features = ["pkcs8"] } k256 = { version = "0.13.2", features = ["pkcs8"] } rsa = "0.9.6" -signature = { version = "2.2.0", features = ["digest"] } +signature = { version = "2.2.0", features = ["derive", "digest"] } sha1 = { version = "0.10", features = ["oid"] } sha2 = { version = "0.10", features = ["oid"] } spki = "0.7.3" diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index b19bde16..1895e8d6 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -19,7 +19,7 @@ use ecdsa::{ hazmat::DigestPrimitive, PrimeCurve, Signature, VerifyingKey, }; -use signature::digest::Digest; +use signature::{digest::Digest, DigestSigner}; use spki::{ AlgorithmIdentifier, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier, @@ -104,6 +104,7 @@ impl_sign_algorithm!(p256::NistP256); impl_sign_algorithm!(p384::NistP384); impl_sign_algorithm!(k256::Secp256k1); +#[derive(signature::Signer)] pub struct Signer { session: S, private_key: ObjectHandle, @@ -178,12 +179,12 @@ impl signature::Keypair for Signer { } } -impl signature::Signer> for Signer +impl DigestSigner> for Signer where <::FieldBytesSize as Add>::Output: ArrayLength, { - fn try_sign(&self, msg: &[u8]) -> Result, signature::Error> { - let msg = C::Digest::digest(msg); + fn try_sign_digest(&self, digest: C::Digest) -> Result, signature::Error> { + let msg = digest.finalize(); let bytes = self .session @@ -209,3 +210,18 @@ where const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = Signature::::ALGORITHM_IDENTIFIER; } + +impl DigestSigner> + for Signer +where + ecdsa::der::MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, + Self: DigestSigner>, +{ + fn try_sign_digest( + &self, + digest: C::Digest, + ) -> Result, signature::Error> { + DigestSigner::>::try_sign_digest(self, digest).map(Into::into) + } +} diff --git a/cryptoki-rustcrypto/tests/ecdsa.rs b/cryptoki-rustcrypto/tests/ecdsa.rs index 73824c86..c4c66d42 100644 --- a/cryptoki-rustcrypto/tests/ecdsa.rs +++ b/cryptoki-rustcrypto/tests/ecdsa.rs @@ -65,7 +65,7 @@ fn sign_verify() -> TestResult { let signer = ecdsa::Signer::::new(&session, label).expect("Lookup keys from HSM"); - let signature = signer.sign(&data); + let signature: p256::ecdsa::Signature = signer.sign(&data); let verifying_key = signer.verifying_key(); verifying_key.verify(&data, &signature)?; diff --git a/cryptoki-rustcrypto/tests/x509-ca.rs b/cryptoki-rustcrypto/tests/x509-ca.rs index db95a483..8d14b8d7 100644 --- a/cryptoki-rustcrypto/tests/x509-ca.rs +++ b/cryptoki-rustcrypto/tests/x509-ca.rs @@ -5,9 +5,15 @@ mod common; use crate::common::USER_PIN; use common::init_pins; -use cryptoki::{mechanism::Mechanism, object::Attribute, session::UserType, types::AuthPin}; -use cryptoki_rustcrypto::rsa::pss; -use der::{pem::LineEnding, EncodePem}; +use cryptoki::{ + mechanism::Mechanism, + object::{Attribute, KeyType}, + session::UserType, + types::AuthPin, +}; +use cryptoki_rustcrypto::{ecdsa, rsa::pss}; +use der::{pem::LineEnding, Encode, EncodePem}; +use p256::pkcs8::AssociatedOid; use serial_test::serial; use signature::Keypair; use spki::SubjectPublicKeyInfoOwned; @@ -80,3 +86,69 @@ fn pss_create_ca() -> TestResult { Ok(()) } + +#[test] +#[serial] +fn ecdsa_create_ca() -> 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())))?; + + // get mechanism + let mechanism = Mechanism::EccKeyPairGen; + + let secp256r1_oid: Vec = p256::NistP256::OID.to_der().unwrap(); + + let label = b"demo-signer"; + + // pub key template + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::KeyType(KeyType::EC), + Attribute::Verify(true), + Attribute::EcParams(secp256r1_oid.clone()), + Attribute::Label(label.to_vec()), + ]; + + // priv key template + let priv_key_template = vec![ + Attribute::Token(true), + Attribute::Private(true), + Attribute::Sign(true), + Attribute::Label(label.to_vec()), + ]; + + // generate a key pair + let (public, private) = + session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; + + let signer = + ecdsa::Signer::::new(&session, label).expect("Lookup keys from HSM"); + + let serial_number = SerialNumber::from(42u32); + let validity = Validity::from_now(Duration::new(5, 0)).unwrap(); + let profile = Profile::Root; + let subject = + Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap(); + let pub_key = SubjectPublicKeyInfoOwned::from_key(signer.verifying_key()).unwrap(); + + let builder = + CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) + .expect("Create certificate"); + + let certificate = builder.build::().unwrap(); + + let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); + println!("{}", pem); + + // delete keys + session.destroy_object(public)?; + session.destroy_object(private)?; + + Ok(()) +} From 973602467501c5be620fd429e12f9d4090bf258f Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 23 Feb 2024 21:24:54 -0800 Subject: [PATCH 13/19] ecdsa: implement key import Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 1 + cryptoki-rustcrypto/src/ecdsa.rs | 65 ++++++++++++++++++++++++++---- cryptoki-rustcrypto/src/lib.rs | 8 ++++ cryptoki-rustcrypto/tests/ecdsa.rs | 45 +++++++++++++++++++-- 4 files changed, 109 insertions(+), 10 deletions(-) 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(()) +} From 6ffe140ccff626729cd9bb45c59cb3bfcf42adc9 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 23 Feb 2024 21:26:02 -0800 Subject: [PATCH 14/19] re-export cryptoki Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index ac2dd57a..aae154cc 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -8,6 +8,8 @@ use cryptoki::{ session::Session, }; +pub use cryptoki; + pub mod ecdsa; pub mod rng; pub mod rsa; From 081bb1f8ac9d81458997b2eff677f7a533bca47b Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 27 Feb 2024 20:36:19 -0800 Subject: [PATCH 15/19] fixup import Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/ecdsa.rs | 8 ++++---- cryptoki-rustcrypto/src/rsa/mod.rs | 24 +++++++++++++++++++++--- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index 43ecfd22..7885cc08 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -17,10 +17,10 @@ use ecdsa::{ point::PointCompression, sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, subtle::CtOption, - AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, Scalar, + AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, Scalar, SecretKey, }, hazmat::{DigestPrimitive, SignPrimitive}, - PrimeCurve, Signature, SignatureSize, SigningKey, VerifyingKey, + PrimeCurve, Signature, SignatureSize, VerifyingKey, }; use signature::{digest::Digest, DigestSigner}; use spki::{ @@ -73,7 +73,7 @@ where } } -impl CryptokiImport for SigningKey +impl CryptokiImport for SecretKey where C: PrimeCurve + CurveArithmetic, Scalar: Invert>> + SignPrimitive, @@ -98,7 +98,7 @@ where } } -impl CryptokiImport for VerifyingKey +impl CryptokiImport for PublicKey where C: PrimeCurve + CurveArithmetic + PointCompression, AffinePoint: FromEncodedPoint + ToEncodedPoint, diff --git a/cryptoki-rustcrypto/src/rsa/mod.rs b/cryptoki-rustcrypto/src/rsa/mod.rs index 876af778..ee6d0c6b 100644 --- a/cryptoki-rustcrypto/src/rsa/mod.rs +++ b/cryptoki-rustcrypto/src/rsa/mod.rs @@ -6,15 +6,15 @@ use cryptoki::{ rsa::{PkcsMgfType, PkcsPssParams}, Mechanism, MechanismType, }, - object::{Attribute, AttributeType, KeyType, ObjectClass}, + object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, }; use der::oid::AssociatedOid; -use rsa::{BigUint, RsaPublicKey}; +use rsa::{traits::PublicKeyParts, BigUint, RsaPublicKey}; use signature::digest::Digest; use std::convert::TryInto; use thiserror::Error; -use crate::SessionLike; +use crate::{CryptokiImport, SessionLike}; pub mod pkcs1v15; pub mod pss; @@ -126,3 +126,21 @@ impl_digest_signing!( SHA512, MGF1_SHA512 ); + +impl CryptokiImport for RsaPublicKey { + 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::RSA)); + template.push(Attribute::Modulus(self.n().to_bytes_be())); + template.push(Attribute::PublicExponent(self.e().to_bytes_be())); + + let handle = session.create_object(&template)?; + + Ok(handle) + } +} From f4fff08a404ca3f16d70e9dc92b801f727d94ef6 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Tue, 27 Feb 2024 20:37:16 -0800 Subject: [PATCH 16/19] add missing methods to SessionLike Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/src/lib.rs | 48 +++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/cryptoki-rustcrypto/src/lib.rs b/cryptoki-rustcrypto/src/lib.rs index aae154cc..de5a3d47 100644 --- a/cryptoki-rustcrypto/src/lib.rs +++ b/cryptoki-rustcrypto/src/lib.rs @@ -5,7 +5,8 @@ use cryptoki::{ error::Result, mechanism::Mechanism, object::{Attribute, AttributeType, ObjectHandle}, - session::Session, + session::{Session, UserType}, + types::AuthPin, }; pub use cryptoki; @@ -23,8 +24,17 @@ pub trait SessionLike { object: ObjectHandle, attributes: &[AttributeType], ) -> Result>; + fn update_attributes(&self, object: ObjectHandle, template: &[Attribute]) -> Result<()>; fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result>; fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()>; + fn wrap_key( + &self, + mechanism: &Mechanism, + wrapping_key: ObjectHandle, + key: ObjectHandle, + ) -> Result>; + fn login(&self, user_type: UserType, pin: Option<&AuthPin>) -> Result<()>; + fn logout(&self) -> Result<()>; } impl SessionLike for Session { @@ -41,12 +51,30 @@ impl SessionLike for Session { ) -> Result> { Session::get_attributes(self, object, attributes) } + fn update_attributes(&self, object: ObjectHandle, template: &[Attribute]) -> Result<()> { + Session::update_attributes(self, object, template) + } + fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { Session::sign(self, mechanism, key, data) } fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> { Session::generate_random_slice(self, random_data) } + fn wrap_key( + &self, + mechanism: &Mechanism, + wrapping_key: ObjectHandle, + key: ObjectHandle, + ) -> Result> { + Session::wrap_key(self, mechanism, wrapping_key, key) + } + fn login(&self, user_type: UserType, pin: Option<&AuthPin>) -> Result<()> { + Session::login(self, user_type, pin) + } + fn logout(&self) -> Result<()> { + Session::logout(self) + } } impl<'s> SessionLike for &'s Session { @@ -63,12 +91,30 @@ impl<'s> SessionLike for &'s Session { ) -> Result> { Session::get_attributes(self, object, attributes) } + fn update_attributes(&self, object: ObjectHandle, template: &[Attribute]) -> Result<()> { + Session::update_attributes(self, object, template) + } + fn sign(&self, mechanism: &Mechanism, key: ObjectHandle, data: &[u8]) -> Result> { Session::sign(self, mechanism, key, data) } fn generate_random_slice(&self, random_data: &mut [u8]) -> Result<()> { Session::generate_random_slice(self, random_data) } + fn wrap_key( + &self, + mechanism: &Mechanism, + wrapping_key: ObjectHandle, + key: ObjectHandle, + ) -> Result> { + Session::wrap_key(self, mechanism, wrapping_key, key) + } + fn login(&self, user_type: UserType, pin: Option<&AuthPin>) -> Result<()> { + Session::login(self, user_type, pin) + } + fn logout(&self) -> Result<()> { + Session::logout(self) + } } pub trait CryptokiImport { From bc1215b0c596e688a9fa425dcaae45f2c424e893 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Wed, 5 Jun 2024 10:48:40 -0700 Subject: [PATCH 17/19] bump rustcrypto dependencies to pre-releases Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 26 +++++++++++++------------- cryptoki-rustcrypto/src/ecdsa.rs | 14 +++++++------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index d00d2097..c9aeb2dd 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -12,22 +12,22 @@ repository = "https://github.com/parallaxsecond/rust-cryptoki" [dependencies] cryptoki = { path = "../cryptoki", version = "0.6.1" } -der = "0.7.8" -ecdsa = "0.16.9" -p224 = { version = "0.13.2", features = ["pkcs8"] } -p256 = { version = "0.13.2", features = ["pkcs8"] } -p384 = { version = "0.13.0", features = ["pkcs8"] } -k256 = { version = "0.13.2", features = ["pkcs8"] } -rsa = "0.9.6" -signature = { version = "2.2.0", features = ["derive", "digest"] } -sha1 = { version = "0.10", features = ["oid"] } -sha2 = { version = "0.10", features = ["oid"] } -spki = "0.7.3" -x509-cert = "0.2.4" +der = "=0.8.0-pre.0" +ecdsa = "=0.17.0-pre.5" +p224 = { version = "=0.14.0-pre", features = ["pkcs8"] } +p256 = { version = "=0.14.0-pre.0", features = ["pkcs8"] } +p384 = { version = "=0.14.0-pre", features = ["pkcs8"] } +k256 = { version = "=0.14.0-pre.0", features = ["pkcs8"] } +rsa = "=0.10.0-pre.1" +signature = { version = "=2.3.0-pre.3", features = ["derive", "digest"] } +sha1 = { version = "=0.11.0-pre.3", features = ["oid"] } +sha2 = { version = "=0.11.0-pre.3", features = ["oid"] } +spki = "=0.8.0-pre.0" +x509-cert = "=0.3.0-pre" 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"] } +x509-cert = { version = "=0.3.0-pre", features = ["builder"] } diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index 7885cc08..2214a76b 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -12,14 +12,14 @@ use der::{ }; use ecdsa::{ elliptic_curve::{ - generic_array::ArrayLength, + array::ArraySize, ops::Invert, point::PointCompression, sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, subtle::CtOption, AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, Scalar, SecretKey, }, - hazmat::{DigestPrimitive, SignPrimitive}, + hazmat::DigestPrimitive, PrimeCurve, Signature, SignatureSize, VerifyingKey, }; use signature::{digest::Digest, DigestSigner}; @@ -76,8 +76,8 @@ where impl CryptokiImport for SecretKey where C: PrimeCurve + CurveArithmetic, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, + Scalar: Invert>>, + SignatureSize: ArraySize, C: AssociatedOid, { @@ -232,7 +232,7 @@ impl signature::Keypair for Signer { impl DigestSigner> for Signer where - <::FieldBytesSize as Add>::Output: ArrayLength, + <::FieldBytesSize as Add>::Output: ArraySize, { fn try_sign_digest(&self, digest: C::Digest) -> Result, signature::Error> { let msg = digest.finalize(); @@ -265,8 +265,8 @@ where impl DigestSigner> for Signer where - ecdsa::der::MaxSize: ArrayLength, - as Add>::Output: Add + ArrayLength, + ecdsa::der::MaxSize: ArraySize, + as Add>::Output: Add + ArraySize, Self: DigestSigner>, { fn try_sign_digest( From 7f4cd925336599f2df2b158362cb01c08c008217 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 10 Nov 2024 14:39:43 -0800 Subject: [PATCH 18/19] fixup cryptoki version Signed-off-by: Arthur Gautier --- cryptoki-rustcrypto/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index c9aeb2dd..c2e30c2e 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" repository = "https://github.com/parallaxsecond/rust-cryptoki" [dependencies] -cryptoki = { path = "../cryptoki", version = "0.6.1" } +cryptoki = { path = "../cryptoki", version = "0.7.0" } der = "=0.8.0-pre.0" ecdsa = "=0.17.0-pre.5" p224 = { version = "=0.14.0-pre", features = ["pkcs8"] } From af534425fb79627290f1250f71e01c60589d1770 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Sun, 10 Nov 2024 14:54:57 -0800 Subject: [PATCH 19/19] fixup updates Signed-off-by: Arthur Gautier --- Cargo.lock | 640 +++++++++++++++++++++++- Cargo.toml | 4 + cryptoki-rustcrypto/Cargo.toml | 27 +- cryptoki-rustcrypto/src/ecdsa.rs | 2 +- cryptoki-rustcrypto/src/rsa/pkcs1v15.rs | 42 +- cryptoki-rustcrypto/src/x509.rs | 6 +- cryptoki-rustcrypto/tests/ecdsa.rs | 5 +- cryptoki-rustcrypto/tests/rsa.rs | 67 ++- cryptoki-rustcrypto/tests/x509-ca.rs | 26 +- 9 files changed, 774 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index de0bc8ca..78fefb55 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,12 +11,33 @@ dependencies = [ "memchr", ] +[[package]] +name = "async-signature" +version = "0.6.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9bdb5df8dde2bd1ec515a0981636508bb37d55984d0bae3678d4ac859125431" +dependencies = [ + "signature", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bindgen" version = "0.69.4" @@ -52,6 +73,21 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "block-buffer" +version = "0.11.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd016a0ddc7cb13661bf5576073ce07330a693f8608a1320b4e20561cc12cdc" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cc" version = "1.0.86" @@ -93,6 +129,57 @@ dependencies = [ "cc", ] +[[package]] +name = "cms" +version = "0.3.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956098b1603285c33972193d6f62c8389d3d8548693a4077baa08ff0a8da97c7" +dependencies = [ + "const-oid", + "der", + "spki", + "x509-cert", +] + +[[package]] +name = "const-oid" +version = "0.10.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9adcf94f05e094fca3005698822ec791cb4433ced416afda1c5ca3b8dfc05a2f" + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.6.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d748d1f5b807ee6d0df5a548d0130417295c3aaed1dcbbb3d6a2e7106e11fcca" +dependencies = [ + "hybrid-array", + "num-traits", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.2.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b8ce8218c97789f16356e7896b3714f26c2ee1079b79c0b7ae7064bb9089fa" +dependencies = [ + "getrandom", + "hybrid-array", + "rand_core", +] + [[package]] name = "cryptoki" version = "0.7.0" @@ -107,7 +194,30 @@ dependencies = [ "psa-crypto", "secrecy", "serial_test", - "testresult", + "testresult 0.4.1", +] + +[[package]] +name = "cryptoki-rustcrypto" +version = "0.1.0" +dependencies = [ + "cryptoki", + "der", + "ecdsa", + "k256", + "p256", + "p384", + "pkcs12", + "rand", + "rsa", + "serial_test", + "sha1", + "sha2", + "signature", + "spki", + "testresult 0.2.0", + "thiserror", + "x509-cert", ] [[package]] @@ -118,12 +228,83 @@ dependencies = [ "libloading 0.7.4", ] +[[package]] +name = "der" +version = "0.8.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82db698b33305f0134faf590b9d1259dc171b5481ac41d5c8146c3b3ee7d4319" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.8.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "211bea8bb45f5f61bc857104606913ef8ac8b5ec698143aa2aa96a7ffdc94991" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "digest" +version = "0.11.0-pre.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2e3d6615d99707295a9673e889bf363a04b2a466bd320c65a72536f7577379" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.17.0-pre.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e62f2041a28c40b8884b79fbd19bc7457d76c6397767831e9ff4029fc0473a9" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "either" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +[[package]] +name = "elliptic-curve" +version = "0.14.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc43715037532dc2d061e5c97e81b684c28993d52a4fa4eb7d2ce2826d78f2f2" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "group", + "hkdf", + "hybrid-array", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "errno" version = "0.3.8" @@ -134,18 +315,74 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "flagset" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3ea1ec5f8307826a5b71094dd91fc04d4ae75d5709b20ad351c7fb4815c86ec" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.13.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00176ff81091018d42ff82e8324f8e5adb0b7e0468d1358f653972562dbff031" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.13.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4b1fb14e4df79f9406b434b60acef9f45c26c50062cccf1346c6103b8c47d58" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.9" @@ -155,6 +392,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "hybrid-array" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a9a965bb102c1c891fb017c09a05c965186b1265a207640f323ddd009f9deb" +dependencies = [ + "typenum", + "zeroize", +] + [[package]] name = "instant" version = "0.1.12" @@ -173,11 +420,28 @@ dependencies = [ "either", ] +[[package]] +name = "k256" +version = "0.14.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6995f4341b819603e1b836b530ba1c33bbb677d0a3d68ed122a55081abfc82dd" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "lazycell" @@ -187,9 +451,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.162" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" [[package]] name = "libloading" @@ -211,6 +475,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -255,13 +525,51 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -270,6 +578,30 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "p256" +version = "0.14.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71f3fd64a9cad9c26ed7f734b152196d5e56376b9957c832bcca0de48a708080" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.14.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e19554fe6ee269c860a0f231cbba714e5cbef26a927c75d8e30ac9040a4b32e" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -301,6 +633,57 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "pem-rfc7468" +version = "1.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dfbfa5c6f0906884269722c5478e72fd4d6c0e24fe600332c6d62359567ce1" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pkcs1" +version = "0.8.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226eb25e2c46c166ce498ac0f606ac623142d640064879ff445938accddff1e2" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs12" +version = "0.2.0-pre" +source = "git+https://github.com/RustCrypto/formats.git#48eac00018b31215141f98550e342da7d40062d6" +dependencies = [ + "cms", + "const-oid", + "der", + "spki", + "x509-cert", +] + +[[package]] +name = "pkcs8" +version = "0.11.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eacd2c7141f32aef1cfd1ad0defb5287a3d94592d7ab57c1ae20e3f9f1f0db1f" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "prettyplease" version = "0.2.16" @@ -311,6 +694,15 @@ dependencies = [ "syn 2.0.50", ] +[[package]] +name = "primeorder" +version = "0.14.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794117b388378d55629f78f61e64e182baa200bf59c1a8205e0c46508ce5873" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.78" @@ -353,6 +745,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -391,6 +813,35 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rfc6979" +version = "0.5.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "871ee76a3eee98b0f805e5d1caf26929f4565073c580c053a55f886fc15dea49" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rsa" +version = "0.10.0-pre.3" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-hash" version = "1.1.0" @@ -425,6 +876,20 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.8.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1988446eff153796413a73669dfaa4caa3f5ce8b25fac89e3821a39c611772e" +dependencies = [ + "base16ct", + "der", + "hybrid-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secrecy" version = "0.8.0" @@ -477,18 +942,84 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "sha1" +version = "0.11.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9540978cef7a8498211c1b1c14e5ce920fe5bd524ea84f4a3d72d4602515ae93" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.11.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "540c0893cce56cdbcfebcec191ec8e0f470dd1889b6e7a0b503e310a94a168f5" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signature" +version = "2.3.0-pre.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054d71959c7051b9042c26af337f05cc930575ed2604d7d3ced3158383e59734" +dependencies = [ + "digest", + "rand_core", + "signature_derive", +] + +[[package]] +name = "signature_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0381d1913eeaf4c7bc4094016c9a8de6c1120663afe32a90ff268ad7f80486" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + [[package]] name = "smallvec" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.8.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ac66481418fd7afdc584adcf3be9aa572cf6c2858814494dc2a01755f050bc" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "1.0.109" @@ -511,12 +1042,65 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "testresult" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649113ab56eab59f78f02314a05b24bda0200d322c9eb1c60d0af8554e94c5ef" + [[package]] name = "testresult" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614b328ff036a4ef882c61570f72918f7e9c5bee1da33f8e7f91e01daee7e56c" +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "tls_codec" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a" +dependencies = [ + "tls_codec_derive", + "zeroize", +] + +[[package]] +name = "tls_codec_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -533,6 +1117,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "which" version = "4.4.2" @@ -708,11 +1298,47 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "x509-cert" +version = "0.3.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2db382aa43c1fb5c419a960f72c3847ab0f383f635fc2e25f0bd6c5fb94371d1" +dependencies = [ + "async-signature", + "const-oid", + "der", + "sha1", + "signature", + "spki", + "tls_codec", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.50", +] + [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" dependencies = [ "zeroize_derive", ] diff --git a/Cargo.toml b/Cargo.toml index 740a8e6c..9a3f5d3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,6 @@ [workspace] members = ["cryptoki", "cryptoki-sys", "cryptoki-rustcrypto"] + +[patch.crates-io] +pkcs12 = { git = "https://github.com/RustCrypto/formats.git" } +rsa = { path = "../RSA" } diff --git a/cryptoki-rustcrypto/Cargo.toml b/cryptoki-rustcrypto/Cargo.toml index c2e30c2e..8d47dc9c 100644 --- a/cryptoki-rustcrypto/Cargo.toml +++ b/cryptoki-rustcrypto/Cargo.toml @@ -12,22 +12,23 @@ repository = "https://github.com/parallaxsecond/rust-cryptoki" [dependencies] cryptoki = { path = "../cryptoki", version = "0.7.0" } -der = "=0.8.0-pre.0" -ecdsa = "=0.17.0-pre.5" -p224 = { version = "=0.14.0-pre", features = ["pkcs8"] } -p256 = { version = "=0.14.0-pre.0", features = ["pkcs8"] } -p384 = { version = "=0.14.0-pre", features = ["pkcs8"] } -k256 = { version = "=0.14.0-pre.0", features = ["pkcs8"] } -rsa = "=0.10.0-pre.1" -signature = { version = "=2.3.0-pre.3", features = ["derive", "digest"] } -sha1 = { version = "=0.11.0-pre.3", features = ["oid"] } -sha2 = { version = "=0.11.0-pre.3", features = ["oid"] } -spki = "=0.8.0-pre.0" -x509-cert = "=0.3.0-pre" +der = "=0.8.0-rc.1" +ecdsa = "=0.17.0-pre.9" +#p224 = { version = "=0.14.0-pre.2", features = ["pkcs8"] } +p256 = { version = "=0.14.0-pre.2", features = ["pkcs8"] } +p384 = { version = "=0.14.0-pre.2", features = ["pkcs8"] } +k256 = { version = "=0.14.0-pre.2", features = ["pkcs8"] } +pkcs12 = { version = "=0.2.0-pre" } +rsa = { version = "=0.10.0-pre.3", features = ["sha2"] } +signature = { version = "=2.3.0-pre.4", features = ["derive", "digest"] } +sha1 = { version = "=0.11.0-pre.4", features = ["oid"] } +sha2 = { version = "=0.11.0-pre.4", features = ["oid"] } +spki = "=0.8.0-rc.1" +x509-cert = "=0.3.0-pre.0" thiserror = "1.0" [dev-dependencies] rand = "0.8.5" serial_test = "0.5.1" testresult = "0.2.0" -x509-cert = { version = "=0.3.0-pre", features = ["builder"] } +x509-cert = { version = "=0.3.0-pre.0", features = ["builder"] } diff --git a/cryptoki-rustcrypto/src/ecdsa.rs b/cryptoki-rustcrypto/src/ecdsa.rs index 2214a76b..d9a0b0fc 100644 --- a/cryptoki-rustcrypto/src/ecdsa.rs +++ b/cryptoki-rustcrypto/src/ecdsa.rs @@ -152,7 +152,7 @@ macro_rules! impl_sign_algorithm { }; } -impl_sign_algorithm!(p224::NistP224); +//impl_sign_algorithm!(p224::NistP224); impl_sign_algorithm!(p256::NistP256); impl_sign_algorithm!(p384::NistP384); impl_sign_algorithm!(k256::Secp256k1); diff --git a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs index 625ea1b8..71f288c2 100644 --- a/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs +++ b/cryptoki-rustcrypto/src/rsa/pkcs1v15.rs @@ -1,9 +1,16 @@ // Copyright 2023 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -use cryptoki::object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}; +use cryptoki::{ + mechanism::Mechanism, + object::{Attribute, AttributeType, KeyType, ObjectClass, ObjectHandle}, +}; use rsa::pkcs1v15::{RsaSignatureAssociatedOid, Signature, VerifyingKey}; -use spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier}; +use spki::{ + der::{asn1::OctetString, oid::AssociatedOid, referenced::RefToOwned, AnyRef, Encode}, + AlgorithmIdentifier, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier, + SignatureAlgorithmIdentifier, +}; use std::convert::TryFrom; use super::{read_key, DigestSigning, Error}; @@ -110,3 +117,34 @@ where const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier = as SignatureAlgorithmIdentifier>::SIGNATURE_ALGORITHM_IDENTIFIER; } + +impl signature::hazmat::PrehashSigner for Signer +where + S: SessionLike, + D: DigestSigning + RsaSignatureAssociatedOid, +{ + fn sign_prehash(&self, prehash: &[u8]) -> Result { + let payload = pkcs12::DigestInfo { + algorithm: (AlgorithmIdentifierRef { + oid: ::OID, + parameters: Some(AnyRef::NULL), + }) + .ref_to_owned(), + digest: OctetString::new(prehash).unwrap(), + }; + + let msg = payload.to_der().unwrap(); + println!("msg: {msg:x?}"); + + let bytes = self + .session + .sign(&Mechanism::RsaPkcs, self.private_key, &msg) + .map_err(Error::Cryptoki) + .map_err(Box::new) + .map_err(signature::Error::from_source)?; + + let signature = Signature::try_from(bytes.as_slice())?; + + Ok(signature) + } +} diff --git a/cryptoki-rustcrypto/src/x509.rs b/cryptoki-rustcrypto/src/x509.rs index 76461c8a..e3cf4d65 100644 --- a/cryptoki-rustcrypto/src/x509.rs +++ b/cryptoki-rustcrypto/src/x509.rs @@ -54,8 +54,10 @@ where template.push(Attribute::CertificateType(CertificateType::X_509)); template.push(Attribute::Token(true)); template.push(Attribute::Value(self.to_der()?)); - if !self.tbs_certificate.subject.is_empty() { - template.push(Attribute::Subject(self.tbs_certificate.subject.to_der()?)); + if !self.tbs_certificate().subject().is_empty() { + template.push(Attribute::Subject( + self.tbs_certificate().subject().to_der()?, + )); } Ok(session.create_object(&template)?) diff --git a/cryptoki-rustcrypto/tests/ecdsa.rs b/cryptoki-rustcrypto/tests/ecdsa.rs index 5db5c7ff..35d35fdf 100644 --- a/cryptoki-rustcrypto/tests/ecdsa.rs +++ b/cryptoki-rustcrypto/tests/ecdsa.rs @@ -95,8 +95,9 @@ fn test_import() -> TestResult { 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)?; + let private_handle = p256::SecretKey::from(&private).put_key(&session, template.clone())?; + let public_handle = + p256::PublicKey::from(private.verifying_key()).put_key(&session, template)?; // data to sign let data = [0xFF, 0x55, 0xDD]; diff --git a/cryptoki-rustcrypto/tests/rsa.rs b/cryptoki-rustcrypto/tests/rsa.rs index 35c5d5e6..0ca285b9 100644 --- a/cryptoki-rustcrypto/tests/rsa.rs +++ b/cryptoki-rustcrypto/tests/rsa.rs @@ -7,8 +7,10 @@ use crate::common::USER_PIN; use common::init_pins; use cryptoki::{mechanism::Mechanism, object::Attribute, session::UserType, types::AuthPin}; use cryptoki_rustcrypto::rsa::{pkcs1v15, pss}; +use rand::{thread_rng, RngCore}; use serial_test::serial; -use signature::{Keypair, Signer, Verifier}; +use sha2::{Digest, Sha256}; +use signature::{hazmat::PrehashSigner, Keypair, Signer, Verifier}; use testresult::TestResult; #[test] @@ -49,8 +51,7 @@ fn pkcs1v15_sign_verify() -> TestResult { // data to sign let data = [0xFF, 0x55, 0xDD]; - let signer = - pkcs1v15::Signer::::new(&session, label).expect("Lookup keys from HSM"); + let signer = pkcs1v15::Signer::::new(&session, label).expect("Lookup keys from HSM"); let signature = signer.sign(&data); @@ -102,8 +103,7 @@ fn pss_sign_verify() -> TestResult { // data to sign let data = [0xFF, 0x55, 0xDD]; - let signer = - pss::Signer::::new(&session, label).expect("Lookup keys from HSM"); + let signer = pss::Signer::::new(&session, label).expect("Lookup keys from HSM"); let signature = signer.sign(&data); @@ -116,3 +116,60 @@ fn pss_sign_verify() -> TestResult { Ok(()) } + +#[test] +#[serial] +fn pkcs1v15_sign_verify_prehashed() -> 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())))?; + + // get mechanism + let mechanism = Mechanism::RsaPkcsKeyPairGen; + + let public_exponent: Vec = vec![0x01, 0x00, 0x01]; + let modulus_bits = 1024; + + let label = b"demo-signer"; + + // pub key template + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Label(label.to_vec()), + Attribute::PublicExponent(public_exponent), + Attribute::ModulusBits(modulus_bits.into()), + ]; + + // priv key template + let priv_key_template = vec![Attribute::Token(true), Attribute::Label(label.to_vec())]; + + // generate a key pair + let (public, private) = + session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; + + // data to sign + let mut data = [0u8; 7123]; + thread_rng().fill_bytes(&mut data[..]); + + let prehashed = Sha256::digest(&data[..]); + + let signer = pkcs1v15::Signer::::new(&session, label).expect("Lookup keys from HSM"); + + let signature1 = signer.sign(&data); + let signature2 = signer.sign_prehash(&prehashed).expect("Sign prehash"); + + let verifying_key = signer.verifying_key(); + verifying_key.verify(&data, &signature1)?; + verifying_key.verify(&data, &signature2)?; + + // delete keys + session.destroy_object(public)?; + session.destroy_object(private)?; + + Ok(()) +} diff --git a/cryptoki-rustcrypto/tests/x509-ca.rs b/cryptoki-rustcrypto/tests/x509-ca.rs index 8d14b8d7..c6ab5b7b 100644 --- a/cryptoki-rustcrypto/tests/x509-ca.rs +++ b/cryptoki-rustcrypto/tests/x509-ca.rs @@ -20,7 +20,7 @@ use spki::SubjectPublicKeyInfoOwned; use std::{str::FromStr, time::Duration}; use testresult::TestResult; use x509_cert::{ - builder::{Builder, CertificateBuilder, Profile}, + builder::{profile::cabf, Builder, CertificateBuilder}, name::Name, serial_number::SerialNumber, time::Validity, @@ -66,16 +66,15 @@ fn pss_create_ca() -> TestResult { let serial_number = SerialNumber::from(42u32); let validity = Validity::from_now(Duration::new(5, 0)).unwrap(); - let profile = Profile::Root; let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap(); - let pub_key = SubjectPublicKeyInfoOwned::from_key(signer.verifying_key()).unwrap(); + let profile = cabf::Root::new(false, subject).expect("Create root profile"); + let pub_key = SubjectPublicKeyInfoOwned::from_key(&signer.verifying_key()).unwrap(); - let builder = - CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) - .expect("Create certificate"); + let builder = CertificateBuilder::new(profile, serial_number, validity, pub_key) + .expect("Create certificate"); - let certificate = builder.build().unwrap(); + let certificate = builder.build(&signer).unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", pem); @@ -132,16 +131,17 @@ fn ecdsa_create_ca() -> TestResult { let serial_number = SerialNumber::from(42u32); let validity = Validity::from_now(Duration::new(5, 0)).unwrap(); - let profile = Profile::Root; let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap(); - let pub_key = SubjectPublicKeyInfoOwned::from_key(signer.verifying_key()).unwrap(); + let profile = cabf::Root::new(false, subject).expect("create root profile"); + let pub_key = SubjectPublicKeyInfoOwned::from_key(&signer.verifying_key()).unwrap(); - let builder = - CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer) - .expect("Create certificate"); + let builder = CertificateBuilder::new(profile, serial_number, validity, pub_key) + .expect("Create certificate"); - let certificate = builder.build::().unwrap(); + let certificate = builder + .build::<_, p256::ecdsa::DerSignature>(&signer) + .unwrap(); let pem = certificate.to_pem(LineEnding::LF).expect("generate pem"); println!("{}", pem);