diff --git a/cryptoki/src/mechanism/eddsa.rs b/cryptoki/src/mechanism/eddsa.rs new file mode 100644 index 00000000..0d982b1a --- /dev/null +++ b/cryptoki/src/mechanism/eddsa.rs @@ -0,0 +1,48 @@ +//! EdDSA mechanism types + +use cryptoki_sys::*; +use std::marker::PhantomData; + +/// EdDSA parameters. +/// +/// The EdDSA mechanism, denoted CKM_EDDSA, is a mechanism for +/// single-part and multipart signatures and verification for +/// EdDSA. This mechanism implements the five EdDSA signature +/// schemes defined in RFC 8032 and RFC 8410. +/// +/// For curves according to RFC 8032, this mechanism has an +/// optional parameter, a CK_EDDSA_PARAMS structure. +/// +/// The absence or presence of the parameter as well as its +/// content is used to identify which signature scheme is to be +/// used. +/// +/// | Signature Scheme | Mechanism Param | phFlag | Context Data | +/// |------------------|-----------------|--------|--------------| +/// | Ed25519 | Not Required | N/A | N/A | +/// | Ed25519ctx | Required | False | Optional | +/// | Ed25519ph | Required | True | Optional | +/// | Ed448 | Required | False | Optional | +/// | Ed448ph | Required | True | Optional | +/// +/// This structure wraps a `CK_EDDSA_PARAMS` structure. +#[derive(Copy, Debug, Clone, Default)] +#[repr(transparent)] +pub struct EddsaParams<'a> { + inner: CK_EDDSA_PARAMS, + _marker: PhantomData<&'a [u8]>, +} + +impl EddsaParams<'_> { + /// Construct EdDSA parameters. + /// + /// # Arguments + /// + /// * `params` - The CK_EDDSA_PARAMS structure. + pub fn new(params: CK_EDDSA_PARAMS) -> Self { + Self { + inner: params, + _marker: PhantomData, + } + } +} diff --git a/cryptoki/src/mechanism/mod.rs b/cryptoki/src/mechanism/mod.rs index 52a78528..77a0ab33 100644 --- a/cryptoki/src/mechanism/mod.rs +++ b/cryptoki/src/mechanism/mod.rs @@ -3,6 +3,7 @@ //! Data types for mechanisms pub mod aead; +pub mod eddsa; pub mod ekdf; pub mod elliptic_curve; pub mod hkdf; @@ -902,11 +903,16 @@ pub enum Mechanism<'a> { EcdsaSha512, /// EDDSA mechanism /// + /// This mechanism has an optional parameter, a CK_EDDSA_PARAMS + /// structure. The absence or presence of the parameter as well + /// as its content is used to identify which signature scheme + /// is to be used. + /// /// Note: EdDSA is not part of the PKCS#11 v2.40 standard and as - /// such may not be understood by the backend. It is included here - /// because some vendor implementations support it through the - /// v2.40 interface. - Eddsa, + /// such may not be understood by some backends. It is included + /// here because some vendor implementations support it through + /// the v2.40 interface. + Eddsa(Option>), // SHA-n /// SHA-1 mechanism @@ -1001,7 +1007,7 @@ impl Mechanism<'_> { Mechanism::EccKeyPairGen => MechanismType::ECC_KEY_PAIR_GEN, Mechanism::EccEdwardsKeyPairGen => MechanismType::ECC_EDWARDS_KEY_PAIR_GEN, Mechanism::EccMontgomeryKeyPairGen => MechanismType::ECC_MONTGOMERY_KEY_PAIR_GEN, - Mechanism::Eddsa => MechanismType::EDDSA, + Mechanism::Eddsa(_) => MechanismType::EDDSA, Mechanism::Ecdh1Derive(_) => MechanismType::ECDH1_DERIVE, Mechanism::Ecdsa => MechanismType::ECDSA, Mechanism::EcdsaSha1 => MechanismType::ECDSA_SHA1, @@ -1073,6 +1079,13 @@ impl From<&Mechanism<'_>> for CK_MECHANISM { | Mechanism::Sha512RsaPkcsPss(params) => make_mechanism(mechanism, params), Mechanism::RsaPkcsOaep(params) => make_mechanism(mechanism, params), Mechanism::Ecdh1Derive(params) => make_mechanism(mechanism, params), + Mechanism::Eddsa(params) => match params { + Some(params) => make_mechanism(mechanism, params), + None => CK_MECHANISM { + mechanism, + ..Default::default() + }, + }, Mechanism::HkdfDerive(params) | Mechanism::HkdfData(params) => { make_mechanism(mechanism, params) } @@ -1098,7 +1111,6 @@ impl From<&Mechanism<'_>> for CK_MECHANISM { | Mechanism::EccKeyPairGen | Mechanism::EccEdwardsKeyPairGen | Mechanism::EccMontgomeryKeyPairGen - | Mechanism::Eddsa | Mechanism::Ecdsa | Mechanism::EcdsaSha1 | Mechanism::EcdsaSha224 diff --git a/cryptoki/tests/basic.rs b/cryptoki/tests/basic.rs index 1e3b32f8..059f9515 100644 --- a/cryptoki/tests/basic.rs +++ b/cryptoki/tests/basic.rs @@ -7,6 +7,7 @@ use common::init_pins; use cryptoki::context::Function; use cryptoki::error::{Error, RvError}; use cryptoki::mechanism::aead::GcmParams; +use cryptoki::mechanism::eddsa::EddsaParams; use cryptoki::mechanism::rsa::{PkcsMgfType, PkcsOaepParams, PkcsOaepSource}; use cryptoki::mechanism::{Mechanism, MechanismType}; use cryptoki::object::{ @@ -99,9 +100,57 @@ fn sign_verify_ed25519() -> TestResult { let data = [0xFF, 0x55, 0xDD]; - let signature = session.sign(&Mechanism::Eddsa, private, &data)?; + let signature = session.sign(&Mechanism::Eddsa(None), private, &data)?; - session.verify(&Mechanism::Eddsa, public, &data, &signature)?; + session.verify(&Mechanism::Eddsa(None), public, &data, &signature)?; + + session.destroy_object(public)?; + session.destroy_object(private)?; + + Ok(()) +} + +#[test] +#[serial] +fn sign_verify_ed25519_with_eddsa_params() -> TestResult { + let (pkcs11, slot) = init_pins(); + + let session = pkcs11.open_rw_session(slot)?; + + session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?; + + let mechanism = Mechanism::EccEdwardsKeyPairGen; + + let pub_key_template = vec![ + Attribute::Token(true), + Attribute::Private(false), + Attribute::Verify(true), + // Ed25519 OID + // See: https://github.com/opendnssec/SoftHSMv2/blob/ac70dc398b236e4522101930e790008936489e2d/src/lib/test/SignVerifyTests.cpp#L173 + Attribute::EcParams(vec![ + 0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x32, 0x35, 0x35, 0x31, 0x39, + ]), + ]; + + let priv_key_template = vec![Attribute::Token(true)]; + + let (public, private) = + session.generate_key_pair(&mechanism, &pub_key_template, &priv_key_template)?; + + let data = [0xFF, 0x55, 0xDD]; + + let signature = session.sign( + &Mechanism::Eddsa(Some(EddsaParams::default())), + private, + &data, + )?; + + session.verify( + &Mechanism::Eddsa(Some(EddsaParams::default())), + public, + &data, + &signature, + )?; session.destroy_object(public)?; session.destroy_object(private)?;