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

Ensure ECC key attributes are aligned with the PKCS#11 Spec #119

Merged
merged 9 commits into from
Nov 27, 2024
51 changes: 46 additions & 5 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,23 @@ impl Slot {
}
}

#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "encoding")]
pub enum EcPointEncoding {
Bytes,
Der,
}

impl Default for EcPointEncoding {
fn default() -> Self {
EcPointEncoding::Bytes
}
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
#[serde(default)]
pub ec_point_encoding: EcPointEncoding,
pub slots: Vec<Slot>,
}

Expand All @@ -70,7 +85,10 @@ fn config_error<E: de::Error + 'static>(error: E) -> Error {

impl Config {
pub fn new() -> Config {
Config { slots: Vec::new() }
Config {
ec_point_encoding: EcPointEncoding::default(),
slots: Vec::new(),
}
}

#[cfg(test)]
Expand Down Expand Up @@ -120,7 +138,10 @@ impl Config {
}

fn from_legacy_conf_string(name: &str) -> Result<Config> {
let mut conf = Config { slots: Vec::new() };
let mut conf = Config {
ec_point_encoding: EcPointEncoding::default(),
slots: Vec::new(),
};
/* backwards compatibility where we used to only specify
* a file, this does not support all older options, just
* the more common one of specifying a .sql file with no
Expand Down Expand Up @@ -171,23 +192,43 @@ impl Config {
let filename = Self::find_conf()?;

match Self::from_file(&filename) {
Ok(conf) => return Ok(conf),
Ok(conf) => Ok(conf),
Err(e) => {
/* attempt fallback, return original error on fail */
match Self::from_legacy_conf_string(&filename) {
Ok(mut conf) => {
conf.fix_slot_numbers();
return Ok(conf);
Ok(conf)
}
Err(_) => return Err(e),
}
}
}
}

pub fn load_env_vars_overrides(&mut self) {
match env::var("KRYOPTIC_EC_POINT_ENCODING") {
Ok(var) => {
self.ec_point_encoding = match var.as_str() {
"DER" => EcPointEncoding::Der,
"BYTES" => EcPointEncoding::Bytes,
_ =>
/* ignore */
{
self.ec_point_encoding
}
}
}
Err(_) => (),
}
}

#[cfg(feature = "nssdb")]
fn from_nss_init_args(args: &str) -> Result<Config> {
let mut conf = Config { slots: Vec::new() };
let mut conf = Config {
ec_point_encoding: EcPointEncoding::default(),
slots: Vec::new(),
};
let mut slot = Slot::new();

slot.dbtype = Some(storage::nssdb::DBINFO.dbtype().to_string());
Expand Down
74 changes: 66 additions & 8 deletions src/ec/ecdsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

use std::fmt::Debug;

use crate::attr_element;
use crate::attribute::Attribute;
use crate::ec::*;
use crate::error::Result;
use crate::kasn1::PrivateKeyInfo;
use crate::error::{general_error, Error, Result};
use crate::kasn1::{oid, PrivateKeyInfo};
use crate::mechanism::*;
use crate::object::*;
use crate::ossl::ecdsa::EccOperation;
use crate::{attr_element, bytes_attr_not_empty};

use asn1;
use once_cell::sync::Lazy;
Expand Down Expand Up @@ -42,10 +42,35 @@ impl ECCPubFactory {

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

/* According to PKCS#11 v3.1 6.3.3:
* CKA_EC_PARAMS, Byte array,
* DER-encoding of an ANSI X9.62 Parameters value */
let oid = get_oid_from_obj(&obj).map_err(|e| {
if e.attr_not_found() {
Error::ck_rv_from_error(CKR_TEMPLATE_INCOMPLETE, e)
} else if e.rv() != CKR_ATTRIBUTE_VALUE_INVALID {
Error::ck_rv_from_error(CKR_ATTRIBUTE_VALUE_INVALID, e)
} else {
general_error(e)
}
})?;
match oid {
oid::EC_SECP256R1 | oid::EC_SECP384R1 | oid::EC_SECP521R1 => (),
_ => return Err(CKR_ATTRIBUTE_VALUE_INVALID)?,
}

bytes_attr_not_empty!(obj; CKA_EC_PARAMS);
bytes_attr_not_empty!(obj; CKA_EC_POINT);
/* According to PKCS#11 v3.1 6.3.3:
* CKA_EC_POINT, Byte array,
* DER-encoding of ANSI X9.62 ECPoint value Q */
check_ec_point_from_obj(&oid, &mut obj).map_err(|e| {
if e.attr_not_found() {
Error::ck_rv_from_error(CKR_TEMPLATE_INCOMPLETE, e)
} else {
e
}
})?;

Ok(obj)
}
Expand Down Expand Up @@ -102,9 +127,42 @@ impl ECCPrivFactory {

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

/* According to PKCS#11 v3.1 6.3.4:
* CKA_EC_PARAMS, Byte array,
* DER-encoding of an ANSI X9.62 Parameters value */
let oid = get_oid_from_obj(&obj).map_err(|e| {
if e.attr_not_found() {
Error::ck_rv_from_error(CKR_TEMPLATE_INCOMPLETE, e)
} else if e.rv() != CKR_ATTRIBUTE_VALUE_INVALID {
Error::ck_rv_from_error(CKR_ATTRIBUTE_VALUE_INVALID, e)
} else {
general_error(e)
}
})?;
match oid {
oid::EC_SECP256R1 | oid::EC_SECP384R1 | oid::EC_SECP521R1 => (),
_ => return Err(CKR_ATTRIBUTE_VALUE_INVALID)?,
}

ec_key_check_import(&mut obj)?;
/* According to PKCS#11 v3.1 6.3.4:
* CKA_VALUE, BigInteger,
* ANSI X9.62 private value d */
match obj.get_attr_as_bytes(CKA_VALUE) {
Ok(v) => {
if v.len() != ec_key_size(&oid)? {
return Err(CKR_ATTRIBUTE_VALUE_INVALID)?;
}
}
Err(e) => {
if e.attr_not_found() {
return Err(CKR_TEMPLATE_INCOMPLETE)?;
} else {
return Err(e);
}
}
}

Ok(obj)
}
Expand Down
76 changes: 67 additions & 9 deletions src/ec/eddsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@

use std::fmt::Debug;

use crate::attr_element;
use crate::attribute::Attribute;
use crate::ec::{ec_key_check_import, BITS_ED25519, BITS_ED448};
use crate::error::Result;
use crate::interface::*;
use crate::ec::*;
use crate::error::{general_error, Error, Result};
use crate::kasn1::oid;
use crate::mechanism::*;
use crate::object::*;
use crate::ossl::eddsa::*;
use crate::{attr_element, bytes_attr_not_empty};

use once_cell::sync::Lazy;

Expand Down Expand Up @@ -46,10 +46,35 @@ impl EDDSAPubFactory {

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

bytes_attr_not_empty!(obj; CKA_EC_PARAMS);
bytes_attr_not_empty!(obj; CKA_EC_POINT);
/* According to PKCS#11 v3.1 6.3.5:
* CKA_EC_PARAMS, Byte array,
* DER-encoding of a Parameters value as defined above (6.3.3) */
let oid = get_oid_from_obj(&obj).map_err(|e| {
if e.attr_not_found() {
Error::ck_rv_from_error(CKR_TEMPLATE_INCOMPLETE, e)
} else if e.rv() != CKR_ATTRIBUTE_VALUE_INVALID {
Error::ck_rv_from_error(CKR_ATTRIBUTE_VALUE_INVALID, e)
} else {
general_error(e)
}
})?;
match oid {
oid::ED25519_OID | oid::ED448_OID => (),
_ => return Err(CKR_ATTRIBUTE_VALUE_INVALID)?,
}

/* According to PKCS#11 v3.1 6.3.5:
* CKA_EC_POINT, Byte array,
* Public key bytes in little endian order as defined in RFC 8032 */
check_ec_point_from_obj(&oid, &mut obj).map_err(|e| {
if e.attr_not_found() {
Error::ck_rv_from_error(CKR_TEMPLATE_INCOMPLETE, e)
} else {
e
}
})?;

Ok(obj)
}
Expand Down Expand Up @@ -106,9 +131,42 @@ impl EDDSAPrivFactory {

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

/* According to PKCS#11 v3.1 6.3.6:
* CKA_EC_PARAMS, Byte array,
* DER-encoding of a Parameters value as defined above (6.3.3?) */
let oid = get_oid_from_obj(&obj).map_err(|e| {
if e.attr_not_found() {
Error::ck_rv_from_error(CKR_TEMPLATE_INCOMPLETE, e)
} else if e.rv() != CKR_ATTRIBUTE_VALUE_INVALID {
Error::ck_rv_from_error(CKR_ATTRIBUTE_VALUE_INVALID, e)
} else {
general_error(e)
}
})?;
match oid {
oid::ED25519_OID | oid::ED448_OID => (),
_ => return Err(CKR_ATTRIBUTE_VALUE_INVALID)?,
}

ec_key_check_import(&mut obj)?;
/* According to PKCS#11 v3.1 6.3.6:
* CKA_VALUE, BigInteger,
* Private key bytes in little endian order as defined in RFC 8032 */
match obj.get_attr_as_bytes(CKA_VALUE) {
Ok(v) => {
if v.len() != ec_key_size(&oid)? {
return Err(CKR_ATTRIBUTE_VALUE_INVALID)?;
}
}
Err(e) => {
if e.attr_not_found() {
return Err(CKR_TEMPLATE_INCOMPLETE)?;
} else {
return Err(e);
}
}
}

Ok(obj)
}
Expand Down
Loading