Skip to content

Add more setters for EcKdf. #292

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
69 changes: 58 additions & 11 deletions cryptoki/src/mechanism/elliptic_curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,45 @@ pub struct EcKdf<'a> {
shared_data: Option<&'a [u8]>,
}

impl EcKdf<'_> {
macro_rules! ansi {
{ $func_name: ident, $algo: ident, $algo_name: literal } => {
#[doc = "The key derivation function based on "]
#[doc = $algo_name]
#[doc = " as defined in the ANSI X9.63 standard. The
derived key is produced by concatenating hashes of
the shared value followed by 00000001, 00000002,
etc. until we find enough bytes to fill the
`CKA_VALUE_LEN` of the derived key."]
pub fn $func_name(shared_data: &'a [u8]) -> Self {
Self {
kdf_type: $algo,
shared_data: Some(shared_data),
}
}
}
}

macro_rules! sp800 {
{ $func_name: ident, $algo: ident, $algo_name: literal } => {
#[doc = "The key derivation function based on "]
#[doc = $algo_name]
#[doc = " as defined in the [NIST SP800-56A standard, revision
2](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Ar2.pdf),
section 5.8.1.1. The derived key is produced by
concatenating hashes of 00000001, 00000002,
etc. followed by the shared value until we find
enough bytes to fill the `CKA_VALUE_LEN` of the
derived key."]
pub fn $func_name(shared_data: &'a [u8]) -> Self {
Self {
kdf_type: $algo,
shared_data: Some(shared_data),
}
}
}
}

impl<'a> EcKdf<'a> {
/// The null transformation. The derived key value is produced by
/// taking bytes from the left of the agreed value. The new key
/// size is limited to the size of the agreed value.
Expand All @@ -93,16 +131,25 @@ impl EcKdf<'_> {
}
}

/// The key derivation function based on sha256 as defined in the ANSI X9.63 standard. The
/// derived key is produced by concatenating hashes of the shared
/// value followed by 00000001, 00000002, etc. until we find
/// enough bytes to fill the `CKA_VALUE_LEN` of the derived key.
pub fn sha256() -> Self {
Self {
kdf_type: CKD_SHA256_KDF,
shared_data: None,
}
}
ansi!(sha1, CKD_SHA1_KDF, "SHA1");
ansi!(sha224, CKD_SHA224_KDF, "SHA224");
ansi!(sha256, CKD_SHA256_KDF, "SHA256");
ansi!(sha384, CKD_SHA384_KDF, "SHA384");
ansi!(sha512, CKD_SHA512_KDF, "SHA512");
ansi!(sha3_224, CKD_SHA3_224_KDF, "SHA3_224");
ansi!(sha3_256, CKD_SHA3_256_KDF, "SHA3_256");
ansi!(sha3_384, CKD_SHA3_384_KDF, "SHA3_384");
ansi!(sha3_512, CKD_SHA3_512_KDF, "SHA3_512");

sp800!(sha1_sp800, CKD_SHA1_KDF_SP800, "SHA1");
sp800!(sha224_sp800, CKD_SHA224_KDF_SP800, "SHA224");
sp800!(sha256_sp800, CKD_SHA256_KDF_SP800, "SHA256");
sp800!(sha384_sp800, CKD_SHA384_KDF_SP800, "SHA384");
sp800!(sha512_sp800, CKD_SHA512_KDF_SP800, "SHA512");
sp800!(sha3_224_sp800, CKD_SHA3_224_KDF_SP800, "SHA3_224");
sp800!(sha3_256_sp800, CKD_SHA3_256_KDF_SP800, "SHA3_256");
sp800!(sha3_384_sp800, CKD_SHA3_384_KDF_SP800, "SHA3_384");
sp800!(sha3_512_sp800, CKD_SHA3_512_KDF_SP800, "SHA3_512");

// The intention here is to be able to support other methods with
// shared data, without it being a breaking change, by just adding
Expand Down
90 changes: 89 additions & 1 deletion cryptoki/tests/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
mod common;

use crate::common::{get_pkcs11, is_softhsm, SO_PIN, USER_PIN};
use crate::common::{get_firmware_version, get_pkcs11, is_kryoptic, is_softhsm, SO_PIN, USER_PIN};
use common::init_pins;
use cryptoki::context::Function;
use cryptoki::error::{Error, RvError};
Expand Down Expand Up @@ -687,6 +687,94 @@ fn derive_key() -> TestResult {
Ok(())
}

#[test]
#[serial]
fn derive_key_sp800() -> TestResult {
if is_softhsm() {
return Ok(());
}

use cryptoki::mechanism::elliptic_curve::*;

let (pkcs11, slot) = init_pins();

if is_kryoptic() {
let (major, minor) = get_firmware_version(&pkcs11, slot);
// Kryoptic added support for sha256_sp800 in version 1.3.
if !(major > 1 || minor >= 3) {
eprintln!(
"Skipping test: Kryoptic is too old (need 1.3, got {}.{})",
major, minor
);
return Ok(());
}
}

// open a session
let session = pkcs11.open_rw_session(slot)?;

// log in the session
session.login(UserType::User, Some(&AuthPin::new(USER_PIN.into())))?;

// sha256_sp800
let key = hex::decode("F00670C5F139E7E6C2511EA04FF507AFBBE237CE3C71A89CA59A1C5CF8856562")
.expect("valid hex");
let ephemeral_key =
hex::decode("533B3F09E53B3DEED661A13F7A7D9694AB71CE156C728E00DEE87A1EE3A14C4A")
.expect("valid hex");
let kdf_param = hex::decode("0A2B0601040197550105011203010807416E6F6E796D6F75732053656E646572202020205633A4C5AE4305BC0FE2ABB699A8EE54632790A0").expect("valid hex");
let derivation = hex::decode("AF8CE51D0139A6D60831A9BABAB20186").expect("valid hex");

let template = [
Attribute::Class(ObjectClass::PRIVATE_KEY),
Attribute::KeyType(KeyType::EC_MONTGOMERY),
Attribute::EcParams(vec![
0x13, 0x0a, 0x63, 0x75, 0x72, 0x76, 0x65, 0x32, 0x35, 0x35, 0x31, 0x39,
]),
Attribute::Value(key),
Attribute::Id(b"foo".to_vec()),
Attribute::Label(b"bar".to_vec()),
Attribute::Sensitive(true),
Attribute::Token(true),
Attribute::Derive(true),
];

let private = session.create_object(&template)?;

let kdf = EcKdf::sha256_sp800(&kdf_param);

let params = Ecdh1DeriveParams::new(kdf, &ephemeral_key);

let shared_secret = session.derive_key(
&Mechanism::Ecdh1Derive(params),
private,
&[
Attribute::Class(ObjectClass::SECRET_KEY),
Attribute::KeyType(KeyType::GENERIC_SECRET),
Attribute::ValueLen(Ulong::new(derivation.len().try_into().unwrap())),
Attribute::Sensitive(false),
Attribute::Extractable(true),
Attribute::Token(false),
],
)?;

let value_attribute = session
.get_attributes(shared_secret, &[AttributeType::Value])?
.remove(0);
let value = if let Attribute::Value(value) = value_attribute {
value
} else {
panic!("Expected value attribute.");
};

assert_eq!(value, derivation);

// delete keys
session.destroy_object(private)?;

Ok(())
}

#[test]
#[serial]
fn import_export() -> TestResult {
Expand Down
11 changes: 11 additions & 0 deletions cryptoki/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub fn is_softhsm() -> bool {
get_pkcs11_path().contains("softhsm")
}

pub fn is_kryoptic() -> bool {
get_pkcs11_path().contains("kryoptic")
}

pub fn get_pkcs11() -> Pkcs11 {
Pkcs11::new(get_pkcs11_path()).unwrap()
}
Expand All @@ -46,3 +50,10 @@ pub fn init_pins() -> (Pkcs11, Slot) {

(pkcs11, slot)
}

pub fn get_firmware_version(pkcs11: &Pkcs11, slot: Slot) -> (u8, u8) {
let info = pkcs11.get_slot_info(slot).unwrap();

let v = info.firmware_version();
(v.major(), v.minor())
}
Loading