Skip to content

Commit

Permalink
Centralize ECC properties in ecc_misc
Browse files Browse the repository at this point in the history
All of the generic ECC properiets handling, like OIDs, OSSL Names, sizes
can be managd in a single place as it does not depend on ossl specific
fucntions.

This allows to simplify and handle these conversions uniformly across
all ECC operations and key types.

Signed-off-by: Simo Sorce <[email protected]>
  • Loading branch information
simo5 committed Nov 20, 2024
1 parent 330c556 commit 68ef99d
Show file tree
Hide file tree
Showing 10 changed files with 268 additions and 423 deletions.
4 changes: 2 additions & 2 deletions src/ec_montgomery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ 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;
pub const MIN_EC_MONTGOMERY_SIZE_BITS: usize = BITS_X25519;
pub const MAX_EC_MONTGOMERY_SIZE_BITS: usize = BITS_X448;

#[derive(Debug)]
pub struct ECMontgomeryPubFactory {
Expand Down
122 changes: 0 additions & 122 deletions src/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,113 +19,6 @@ use once_cell::sync::Lazy;
pub const MIN_EC_SIZE_BITS: usize = 256;
pub const MAX_EC_SIZE_BITS: usize = 521;

// ASN.1 encoding of the OID
const OID_SECP256R1: asn1::ObjectIdentifier =
asn1::oid!(1, 2, 840, 10045, 3, 1, 7);
const OID_SECP384R1: asn1::ObjectIdentifier = asn1::oid!(1, 3, 132, 0, 34);
const OID_SECP521R1: asn1::ObjectIdentifier = asn1::oid!(1, 3, 132, 0, 35);

// ASN.1 encoding of the curve name
const STRING_SECP256R1: &[u8] = &[
0x13, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x32, 0x35, 0x36, 0x76, 0x31,
];
const STRING_SECP384R1: &[u8] = &[
0x13, 0x09, 0x73, 0x65, 0x63, 0x70, 0x33, 0x38, 0x34, 0x72, 0x31,
];
const STRING_SECP521R1: &[u8] = &[
0x13, 0x09, 0x73, 0x65, 0x63, 0x70, 0x35, 0x32, 0x31, 0x72, 0x31,
];

pub const NAME_SECP256R1: &str = "prime256v1";
pub const NAME_SECP384R1: &str = "secp384r1";
pub const NAME_SECP521R1: &str = "secp521r1";

const BITS_SECP256R1: usize = 256;
const BITS_SECP384R1: usize = 384;
const BITS_SECP521R1: usize = 521;

pub fn oid_to_curve_name(oid: asn1::ObjectIdentifier) -> Result<&'static str> {
match oid {
OID_SECP256R1 => Ok(NAME_SECP256R1),
OID_SECP384R1 => Ok(NAME_SECP384R1),
OID_SECP521R1 => Ok(NAME_SECP521R1),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

#[cfg(test)]
pub fn curve_name_to_ec_params(name: &'static str) -> Result<&'static [u8]> {
match name {
NAME_SECP256R1 => Ok(STRING_SECP256R1),
NAME_SECP384R1 => Ok(STRING_SECP384R1),
NAME_SECP521R1 => Ok(STRING_SECP521R1),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

#[cfg(test)]
pub fn name_to_bits(name: &'static str) -> Result<usize> {
match name {
NAME_SECP256R1 => Ok(BITS_SECP256R1),
NAME_SECP384R1 => Ok(BITS_SECP384R1),
NAME_SECP521R1 => Ok(BITS_SECP521R1),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

pub fn oid_to_bits(oid: asn1::ObjectIdentifier) -> Result<usize> {
match oid {
OID_SECP256R1 => Ok(BITS_SECP256R1),
OID_SECP384R1 => Ok(BITS_SECP384R1),
OID_SECP521R1 => Ok(BITS_SECP521R1),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

pub fn curve_name_to_bits(name: asn1::PrintableString) -> Result<usize> {
let asn1_name = match asn1::write_single(&name) {
Ok(r) => r,
Err(_) => return Err(CKR_GENERAL_ERROR)?,
};
match asn1_name.as_slice() {
STRING_SECP256R1 => Ok(BITS_SECP256R1),
STRING_SECP384R1 => Ok(BITS_SECP384R1),
STRING_SECP521R1 => Ok(BITS_SECP521R1),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

pub fn curve_name_to_oid(
name: asn1::PrintableString,
) -> Result<asn1::ObjectIdentifier> {
let asn1_name = match asn1::write_single(&name) {
Ok(r) => r,
Err(_) => return Err(CKR_GENERAL_ERROR)?,
};
Ok(match asn1_name.as_slice() {
STRING_SECP256R1 => OID_SECP256R1,
STRING_SECP384R1 => OID_SECP384R1,
STRING_SECP521R1 => OID_SECP521R1,
_ => return Err(CKR_GENERAL_ERROR)?,
})
}

#[cfg(feature = "fips")]
pub fn ec_key_curve_size(key: &Object) -> Result<usize> {
let x = match key.get_attr_as_bytes(CKA_EC_PARAMS) {
Ok(b) => b,
Err(_) => return Err(CKR_GENERAL_ERROR)?,
};
match asn1::parse_single::<ECParameters>(x) {
Ok(a) => match a {
ECParameters::OId(o) => oid_to_bits(o),
ECParameters::CurveName(c) => curve_name_to_bits(c),
_ => return Err(CKR_GENERAL_ERROR)?,
},
Err(_) => return Err(CKR_GENERAL_ERROR)?,
}
}

#[derive(Debug)]
pub struct ECCPubFactory {
attributes: Vec<ObjectAttr>,
Expand Down Expand Up @@ -234,21 +127,6 @@ impl ObjectFactory for ECCPrivFactory {
}
}

fn get_oid_from_obj(key: &Object) -> Result<asn1::ObjectIdentifier> {
let x = match key.get_attr_as_bytes(CKA_EC_PARAMS) {
Ok(b) => b,
Err(_) => return Err(CKR_GENERAL_ERROR)?,
};
match asn1::parse_single::<ECParameters>(x) {
Ok(a) => match a {
ECParameters::OId(o) => Ok(o),
ECParameters::CurveName(c) => curve_name_to_oid(c),
_ => return Err(CKR_GENERAL_ERROR)?,
},
Err(_) => return Err(CKR_GENERAL_ERROR)?,
}
}

impl CommonKeyFactory for ECCPrivFactory {}

impl PrivKeyFactory for ECCPrivFactory {
Expand Down
165 changes: 164 additions & 1 deletion src/ecc_misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
// See LICENSE.txt file for terms

use crate::bytes_attr_not_empty;
use crate::error::Result;
use crate::error::{device_error, general_error, Result};
use crate::interface::*;
use crate::kasn1::DerEncOctetString;
use crate::object::Object;

use asn1;

type Version = u64;

#[derive(asn1::Asn1Read, asn1::Asn1Write)]
Expand Down Expand Up @@ -44,3 +46,164 @@ pub fn ec_key_check_import(obj: &mut Object) -> Result<()> {
bytes_attr_not_empty!(obj; CKA_VALUE);
Ok(())
}

// Bit sized for curves
const BITS_SECP256R1: usize = 256;
const BITS_SECP384R1: usize = 384;
const BITS_SECP521R1: usize = 521;
pub const BITS_ED25519: usize = 256;
pub const BITS_ED448: usize = 448;
pub const BITS_X25519: usize = 256;
pub const BITS_X448: usize = 448;

// ASN.1 encoding of OIDs
pub const OID_SECP256R1: asn1::ObjectIdentifier =
asn1::oid!(1, 2, 840, 10045, 3, 1, 7);
pub const OID_SECP384R1: asn1::ObjectIdentifier = asn1::oid!(1, 3, 132, 0, 34);
pub const OID_SECP521R1: asn1::ObjectIdentifier = asn1::oid!(1, 3, 132, 0, 35);
pub const OID_ED25519: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 112);
pub const OID_ED448: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 113);
pub const OID_X25519: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 110);
pub const OID_X448: asn1::ObjectIdentifier = asn1::oid!(1, 3, 101, 111);

// ASN.1 encoding of curve names
const OCTSTR_SECP256R1: &[u8] = &[
0x13, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x32, 0x35, 0x36, 0x76, 0x31,
];
const OCTSTR_SECP384R1: &[u8] = &[
0x13, 0x09, 0x73, 0x65, 0x63, 0x70, 0x33, 0x38, 0x34, 0x72, 0x31,
];
const OCTSTR_SECP521R1: &[u8] = &[
0x13, 0x09, 0x73, 0x65, 0x63, 0x70, 0x35, 0x32, 0x31, 0x72, 0x31,
];
const OCTSTR_ED25519: &[u8] = &[
0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x32, 0x35, 0x35,
0x31, 0x39,
];
const OCTSTR_ED448: &[u8] = &[
0x13, 0x0a, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x34, 0x34, 0x38,
];
const OCTSTR_X25519: &[u8] = &[
0x13, 0x0a, 0x63, 0x75, 0x72, 0x76, 0x65, 0x32, 0x35, 0x35, 0x31, 0x39,
];
const OCTSTR_X448: &[u8] =
&[0x13, 0x08, 0x63, 0x75, 0x72, 0x76, 0x65, 0x34, 0x34, 0x38];

const NAME_SECP256R1: &[u8] = b"prime256v1\0";
const NAME_SECP384R1: &[u8] = b"secp384r1\0";
const NAME_SECP521R1: &[u8] = b"secp521r1\0";
const NAME_ED25519: &[u8] = b"ED25519\0";
const NAME_ED448: &[u8] = b"ED448\0";
const NAME_X25519: &[u8] = b"X25519\0";
const NAME_X448: &[u8] = b"X448\0";

pub static EC_NAME: &[u8; 3] = b"EC\0";

pub fn curve_name_to_bits(name: &[u8]) -> Result<usize> {
match name {
NAME_SECP256R1 => Ok(BITS_SECP256R1),
NAME_SECP384R1 => Ok(BITS_SECP384R1),
NAME_SECP521R1 => Ok(BITS_SECP521R1),
NAME_ED25519 => Ok(BITS_ED25519),
NAME_ED448 => Ok(BITS_ED448),
NAME_X25519 => Ok(BITS_X25519),
NAME_X448 => Ok(BITS_X448),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

fn oid_to_ossl_name(oid: asn1::ObjectIdentifier) -> Result<&'static [u8]> {
match oid {
OID_SECP256R1 => Ok(NAME_SECP256R1),
OID_SECP384R1 => Ok(NAME_SECP384R1),
OID_SECP521R1 => Ok(NAME_SECP521R1),
OID_ED25519 => Ok(NAME_ED25519),
OID_ED448 => Ok(NAME_ED448),
OID_X25519 => Ok(NAME_X25519),
OID_X448 => Ok(NAME_X448),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

fn curve_to_oid(name: asn1::PrintableString) -> Result<asn1::ObjectIdentifier> {
match asn1::write_single(&name).map_err(general_error)?.as_slice() {
OCTSTR_SECP256R1 => Ok(OID_SECP256R1),
OCTSTR_SECP384R1 => Ok(OID_SECP384R1),
OCTSTR_SECP521R1 => Ok(OID_SECP521R1),
OCTSTR_ED25519 => Ok(OID_ED25519),
OCTSTR_ED448 => Ok(OID_ED448),
OCTSTR_X25519 => Ok(OID_X25519),
OCTSTR_X448 => Ok(OID_X448),
_ => return Err(CKR_GENERAL_ERROR)?,
}
}

fn curve_to_ossl_name(name: asn1::PrintableString) -> Result<&'static [u8]> {
match asn1::write_single(&name).map_err(general_error)?.as_slice() {
OCTSTR_SECP256R1 => Ok(NAME_SECP256R1),
OCTSTR_SECP384R1 => Ok(NAME_SECP384R1),
OCTSTR_SECP521R1 => Ok(NAME_SECP521R1),
OCTSTR_ED25519 => Ok(NAME_ED25519),
OCTSTR_ED448 => Ok(NAME_ED448),
OCTSTR_X25519 => Ok(NAME_X25519),
OCTSTR_X448 => Ok(NAME_X448),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

pub fn get_ossl_name_from_obj(key: &Object) -> Result<&'static [u8]> {
let params = key
.get_attr_as_bytes(CKA_EC_PARAMS)
.map_err(general_error)?;
let ecp =
asn1::parse_single::<ECParameters>(params).map_err(general_error)?;
match ecp {
ECParameters::OId(oid) => oid_to_ossl_name(oid),
ECParameters::CurveName(curve) => curve_to_ossl_name(curve),
_ => Err(CKR_GENERAL_ERROR)?,
}
}

pub fn get_oid_from_obj(key: &Object) -> Result<asn1::ObjectIdentifier> {
let params = key
.get_attr_as_bytes(CKA_EC_PARAMS)
.map_err(general_error)?;
let ecp =
asn1::parse_single::<ECParameters>(params).map_err(general_error)?;
match ecp {
ECParameters::OId(oid) => Ok(oid),
ECParameters::CurveName(c) => curve_to_oid(c),
_ => return Err(CKR_GENERAL_ERROR)?,
}
}

pub fn get_ec_point_from_obj(key: &Object) -> Result<Vec<u8>> {
let point = key.get_attr_as_bytes(CKA_EC_POINT).map_err(general_error)?;
/* [u8] is an octet string for the asn1 library */
let octet = asn1::parse_single::<&[u8]>(point).map_err(device_error)?;
Ok(octet.to_vec())
}

#[cfg(test)]
pub fn map_curve_name(curve: &str) -> Option<&'static [u8]> {
static NAME_SECP224R1: &[u8; 11] = b"prime224v1\0";
match curve {
"P-224" => Some(NAME_SECP224R1),
"P-256" => Some(NAME_SECP256R1),
"P-384" => Some(NAME_SECP384R1),
"P-521" => Some(NAME_SECP521R1),
_ => None,
}
}

#[cfg(test)]
pub fn curve_name_to_ec_params(name: &[u8]) -> Result<&'static [u8]> {
match name {
NAME_SECP256R1 => Ok(OCTSTR_SECP256R1),
NAME_SECP384R1 => Ok(OCTSTR_SECP384R1),
NAME_SECP521R1 => Ok(OCTSTR_SECP521R1),
NAME_ED25519 => Ok(OCTSTR_ED25519),
NAME_ED448 => Ok(OCTSTR_ED448),
_ => Err(CKR_GENERAL_ERROR)?,
}
}
13 changes: 6 additions & 7 deletions src/fips/indicators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::attr_element;
use crate::attribute::Attribute;
use crate::ecc::ec_key_curve_size;
use crate::ecc_misc::*;
use crate::error::Result;
use crate::interface::*;
use crate::object::{OAFlags, Object, ObjectAttr, ObjectFactory};
Expand Down Expand Up @@ -900,14 +900,13 @@ fn check_key(
Ok(m) => m.len(),
Err(_) => return false,
},
CKK_EC => match ec_key_curve_size(obj) {
Ok(s) => btb!(s),
CKK_EC | CKK_EC_EDWARDS => match get_ossl_name_from_obj(obj) {
Ok(s) => match curve_name_to_bits(s) {
Ok(l) => l,
Err(_) => return false,
},
Err(_) => return false,
},
CKK_EC_EDWARDS => {
/* TODO */
return false;
}
_ => {
/* assume everything else is a symmetric key */
match obj.get_attr_as_ulong(CKA_VALUE_LEN) {
Expand Down
26 changes: 26 additions & 0 deletions src/ossl/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,31 @@ impl EvpPkey {
pub fn privkey_from_object(obj: &object::Object) -> Result<EvpPkey> {
Self::from_object(obj, CKO_PRIVATE_KEY)
}

#[cfg(not(feature = "fips"))]
pub fn get_bits(&self) -> Result<usize> {
let ret = unsafe { EVP_PKEY_get_bits(self.ptr) };
if ret == 0 {
return Err(CKR_KEY_INDIGESTIBLE)?;
}
Ok(usize::try_from(ret)?)
}
#[cfg(feature = "fips")]
pub fn get_bits(&self) -> Result<usize> {
/* EVP_PKEY_get_bits() not available in libfips.a */
let mut bits: c_int = 0;
let ret = unsafe {
EVP_PKEY_get_int_param(
self.ptr,
name_as_char(OSSL_PKEY_PARAM_BITS),
&mut bits,
)
};
if ret == 0 {
return Err(CKR_KEY_INDIGESTIBLE)?;
}
Ok(usize::try_from(bits)?)
}
}

impl Drop for EvpPkey {
Expand Down Expand Up @@ -450,6 +475,7 @@ impl<'a> OsslParam<'a> {
Ok(())
}

#[allow(dead_code)]
pub fn add_utf8_string(
&mut self,
key: *const c_char,
Expand Down
Loading

0 comments on commit 68ef99d

Please sign in to comment.