Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for EC_MONTGOMERY keys #111

Merged
merged 1 commit into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ zeroize = "1.6.0"
aes = []
ecc = []
eddsa = []
ec_montgomery = []
hash = []
hkdf = []
hmac = ["hash"]
Expand All @@ -69,7 +70,7 @@ basic = [ "aes", "hmac", "pbkdf2", "sqlitedb" ]

#select everything by default
# Use --no-default-features --features basic, xxx for custom selections
default = [ "basic", "ecc", "eddsa", "hash", "hkdf", "rsa", "sp800_108", "sshkdf", "tlskdf"]
default = [ "basic", "ecc", "ec_montgomery", "eddsa", "hash", "hkdf", "rsa", "sp800_108", "sshkdf", "tlskdf"]

fips = [ "rusqlite/bundled", "basic", "ecc", "hash", "hkdf", "rsa", "sp800_108", "sshkdf", "tlskdf"]

Expand Down
244 changes: 244 additions & 0 deletions src/ec_montgomery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
// Copyright 2024 Jakub Jelen
// See LICENSE.txt file for terms

use std::fmt::Debug;

use crate::attribute::Attribute;
use crate::ecc_misc::*;
use crate::error::Result;
use crate::interface::*;
use crate::mechanism::*;
use crate::object::*;
use crate::ossl::ec_montgomery::*;
use crate::{attr_element, bytes_attr_not_empty};

use once_cell::sync::Lazy;

pub const MIN_EC_MONTGOMERY_SIZE_BITS: usize = BITS_CURVE25519;
pub const MAX_EC_MONTGOMERY_SIZE_BITS: usize = BITS_CURVE448;

#[derive(Debug)]
pub struct ECMontgomeryPubFactory {
attributes: Vec<ObjectAttr>,
}

impl ECMontgomeryPubFactory {
pub fn new() -> ECMontgomeryPubFactory {
let mut data: ECMontgomeryPubFactory = ECMontgomeryPubFactory {
attributes: Vec::new(),
};
data.attributes.append(&mut data.init_common_object_attrs());
data.attributes
.append(&mut data.init_common_storage_attrs());
data.attributes.append(&mut data.init_common_key_attrs());
data.attributes
.append(&mut data.init_common_public_key_attrs());
data.attributes.push(attr_element!(
CKA_EC_PARAMS; OAFlags::AlwaysRequired | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
data.attributes.push(attr_element!(
CKA_EC_POINT; OAFlags::RequiredOnCreate
| OAFlags::SettableOnlyOnCreate | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
data
}
}

impl ObjectFactory for ECMontgomeryPubFactory {
fn create(&self, template: &[CK_ATTRIBUTE]) -> Result<Object> {
let obj = self.default_object_create(template)?;

bytes_attr_not_empty!(obj; CKA_EC_PARAMS);
bytes_attr_not_empty!(obj; CKA_EC_POINT);

Ok(obj)
}

fn get_attributes(&self) -> &Vec<ObjectAttr> {
&self.attributes
}
}

impl CommonKeyFactory for ECMontgomeryPubFactory {}

impl PubKeyFactory for ECMontgomeryPubFactory {}

#[derive(Debug)]
pub struct ECMontgomeryPrivFactory {
attributes: Vec<ObjectAttr>,
}

impl ECMontgomeryPrivFactory {
pub fn new() -> ECMontgomeryPrivFactory {
let mut data: ECMontgomeryPrivFactory = ECMontgomeryPrivFactory {
attributes: Vec::new(),
};
data.attributes.append(&mut data.init_common_object_attrs());
data.attributes
.append(&mut data.init_common_storage_attrs());
data.attributes.append(&mut data.init_common_key_attrs());
data.attributes
.append(&mut data.init_common_private_key_attrs());
data.attributes.push(attr_element!(
CKA_EC_PARAMS; OAFlags::RequiredOnCreate | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));
data.attributes.push(attr_element!(
CKA_VALUE; OAFlags::Sensitive | OAFlags::RequiredOnCreate
| OAFlags::SettableOnlyOnCreate | OAFlags::Unchangeable;
Attribute::from_bytes; val Vec::new()));

/* default to private */
let private = attr_element!(
CKA_PRIVATE; OAFlags::Defval | OAFlags::ChangeOnCopy;
Attribute::from_bool; val true);
match data
.attributes
.iter()
.position(|x| x.get_type() == CKA_PRIVATE)
{
Some(idx) => data.attributes[idx] = private,
None => data.attributes.push(private),
}

data
}
}

impl ObjectFactory for ECMontgomeryPrivFactory {
fn create(&self, template: &[CK_ATTRIBUTE]) -> Result<Object> {
let mut obj = self.default_object_create(template)?;

ec_key_check_import(&mut obj)?;

Ok(obj)
}

fn get_attributes(&self) -> &Vec<ObjectAttr> {
&self.attributes
}

fn export_for_wrapping(&self, key: &Object) -> Result<Vec<u8>> {
PrivKeyFactory::export_for_wrapping(self, key)
}

fn import_from_wrapped(
&self,
data: Vec<u8>,
template: &[CK_ATTRIBUTE],
) -> Result<Object> {
PrivKeyFactory::import_from_wrapped(self, data, template)
}
}

impl CommonKeyFactory for ECMontgomeryPrivFactory {}

impl PrivKeyFactory for ECMontgomeryPrivFactory {}

static PUBLIC_KEY_FACTORY: Lazy<Box<dyn ObjectFactory>> =
Lazy::new(|| Box::new(ECMontgomeryPubFactory::new()));

static PRIVATE_KEY_FACTORY: Lazy<Box<dyn ObjectFactory>> =
Lazy::new(|| Box::new(ECMontgomeryPrivFactory::new()));

#[derive(Debug)]
struct ECMontgomeryMechanism {
info: CK_MECHANISM_INFO,
}

impl ECMontgomeryMechanism {
fn register_mechanisms(mechs: &mut Mechanisms) {
/* TODO PKCS #11 defines also CKM_XEDDSA for signatures, but it is not implemented by
* OpenSSL */
mechs.add_mechanism(
CKM_EC_MONTGOMERY_KEY_PAIR_GEN,
Box::new(ECMontgomeryMechanism {
info: CK_MECHANISM_INFO {
ulMinKeySize: CK_ULONG::try_from(
MIN_EC_MONTGOMERY_SIZE_BITS,
)
.unwrap(),
ulMaxKeySize: CK_ULONG::try_from(
MAX_EC_MONTGOMERY_SIZE_BITS,
)
.unwrap(),
flags: CKF_GENERATE_KEY_PAIR,
},
}),
);
}
}

impl Mechanism for ECMontgomeryMechanism {
fn info(&self) -> &CK_MECHANISM_INFO {
&self.info
}

fn generate_keypair(
&self,
mech: &CK_MECHANISM,
pubkey_template: &[CK_ATTRIBUTE],
prikey_template: &[CK_ATTRIBUTE],
) -> Result<(Object, Object)> {
let mut pubkey =
PUBLIC_KEY_FACTORY.default_object_generate(pubkey_template)?;
if !pubkey.check_or_set_attr(Attribute::from_ulong(
CKA_CLASS,
CKO_PUBLIC_KEY,
))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
if !pubkey.check_or_set_attr(Attribute::from_ulong(
CKA_KEY_TYPE,
CKK_EC_EDWARDS,
))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}

let mut privkey =
PRIVATE_KEY_FACTORY.default_object_generate(prikey_template)?;
if !privkey.check_or_set_attr(Attribute::from_ulong(
CKA_CLASS,
CKO_PRIVATE_KEY,
))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}
if !privkey.check_or_set_attr(Attribute::from_ulong(
CKA_KEY_TYPE,
CKK_EC_EDWARDS,
))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}

let ec_params = match pubkey.get_attr_as_bytes(CKA_EC_PARAMS) {
Ok(a) => a.clone(),
Err(_) => {
return Err(CKR_ATTRIBUTE_VALUE_INVALID)?;
}
};
if !privkey.check_or_set_attr(Attribute::from_bytes(
CKA_EC_PARAMS,
ec_params,
))? {
return Err(CKR_TEMPLATE_INCONSISTENT)?;
}

ECMontgomeryOperation::generate_keypair(&mut pubkey, &mut privkey)?;
default_key_attributes(&mut privkey, mech.mechanism)?;
default_key_attributes(&mut pubkey, mech.mechanism)?;

Ok((pubkey, privkey))
}
}

pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) {
ECMontgomeryMechanism::register_mechanisms(mechs);

ot.add_factory(
ObjectType::new(CKO_PUBLIC_KEY, CKK_EC_MONTGOMERY),
&PUBLIC_KEY_FACTORY,
);
ot.add_factory(
ObjectType::new(CKO_PRIVATE_KEY, CKK_EC_MONTGOMERY),
&PRIVATE_KEY_FACTORY,
);
}
19 changes: 2 additions & 17 deletions src/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ use crate::interface::*;
use crate::kasn1::PrivateKeyInfo;
use crate::mechanism::*;
use crate::object::*;
use crate::ossl::ecc::{ECDHOperation, EccOperation};
use crate::{attr_element, bytes_attr_not_empty, cast_params};
use crate::ossl::ecc::EccOperation;
use crate::{attr_element, bytes_attr_not_empty};

use asn1;
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -398,20 +398,6 @@ impl Mechanism for EccMechanism {
Ok(Box::new(EccOperation::verify_new(mech, key, &self.info)?))
}

fn derive_operation(&self, mech: &CK_MECHANISM) -> Result<Operation> {
if self.info.flags & CKF_DERIVE != CKF_DERIVE {
return Err(CKR_MECHANISM_INVALID)?;
}
let kdf = match mech.mechanism {
CKM_ECDH1_DERIVE | CKM_ECDH1_COFACTOR_DERIVE => {
let params = cast_params!(mech, CK_ECDH1_DERIVE_PARAMS);
ECDHOperation::derive_new(mech.mechanism, params)?
}
_ => return Err(CKR_MECHANISM_INVALID)?,
};
Ok(Operation::Derive(Box::new(kdf)))
}

fn generate_keypair(
&self,
mech: &CK_MECHANISM,
Expand Down Expand Up @@ -469,7 +455,6 @@ impl Mechanism for EccMechanism {

pub fn register(mechs: &mut Mechanisms, ot: &mut ObjectFactories) {
EccOperation::register_mechanisms(mechs);
ECDHOperation::register_mechanisms(mechs);

ot.add_factory(
ObjectType::new(CKO_PUBLIC_KEY, CKK_EC),
Expand Down
60 changes: 60 additions & 0 deletions src/ecdh.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2024 Simo Sorce, Jakub Jelen
// See LICENSE.txt file for terms

use std::fmt::Debug;

use crate::ecc::*;
use crate::error::Result;
use crate::interface::*;
use crate::mechanism::{Mechanism, Mechanisms, Operation};
use crate::object::ObjectFactories;
use crate::ossl::ecdh::ECDHOperation;

use crate::cast_params;

pub fn register(mechs: &mut Mechanisms, _: &mut ObjectFactories) {
ECDHMechanism::register_mechanisms(mechs);
}

#[derive(Debug)]
struct ECDHMechanism {
info: CK_MECHANISM_INFO,
}

impl ECDHMechanism {
fn new_mechanism() -> Box<dyn Mechanism> {
Box::new(ECDHMechanism {
info: CK_MECHANISM_INFO {
ulMinKeySize: CK_ULONG::try_from(MIN_EC_SIZE_BITS).unwrap(),
ulMaxKeySize: CK_ULONG::try_from(MAX_EC_SIZE_BITS).unwrap(),
flags: CKF_DERIVE,
},
})
}

pub fn register_mechanisms(mechs: &mut Mechanisms) {
for ckm in &[CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE] {
mechs.add_mechanism(*ckm, Self::new_mechanism());
}
}
}

impl Mechanism for ECDHMechanism {
fn info(&self) -> &CK_MECHANISM_INFO {
&self.info
}

fn derive_operation(&self, mech: &CK_MECHANISM) -> Result<Operation> {
if self.info.flags & CKF_DERIVE != CKF_DERIVE {
return Err(CKR_MECHANISM_INVALID)?;
}
let kdf = match mech.mechanism {
CKM_ECDH1_DERIVE | CKM_ECDH1_COFACTOR_DERIVE => {
let params = cast_params!(mech, CK_ECDH1_DERIVE_PARAMS);
ECDHOperation::derive_new(mech.mechanism, params)?
}
_ => return Err(CKR_MECHANISM_INVALID)?,
};
Ok(Operation::Derive(Box::new(kdf)))
}
}
12 changes: 12 additions & 0 deletions src/enabled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ mod ecc;
#[cfg(any(feature = "ecc", feature = "eddsa"))]
mod ecc_misc;

#[cfg(all(feature = "ec_montgomery", not(feature = "fips")))]
mod ec_montgomery;

#[cfg(any(feature = "ec_montgomery", feature = "ecc"))]
mod ecdh;

#[cfg(all(feature = "eddsa", not(feature = "fips")))]
mod eddsa;

Expand Down Expand Up @@ -52,6 +58,12 @@ pub fn register_all(mechs: &mut Mechanisms, ot: &mut ObjectFactories) {
#[cfg(feature = "ecc")]
ecc::register(mechs, ot);

#[cfg(any(feature = "ec_montgomery", feature = "ecc"))]
ecdh::register(mechs, ot);

#[cfg(all(feature = "ec_montgomery", not(feature = "fips")))]
ec_montgomery::register(mechs, ot);

#[cfg(all(feature = "eddsa", not(feature = "fips")))]
eddsa::register(mechs, ot);

Expand Down
Loading