Skip to content

Commit c2e6dde

Browse files
committed
Add support for ML-DSA
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
1 parent 10d1e16 commit c2e6dde

File tree

3 files changed

+370
-1
lines changed

3 files changed

+370
-1
lines changed

cryptoki/src/mechanism/mldsa.rs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
//! ML-DSA mechanism types
2+
3+
use crate::mechanism::{Mechanism, MechanismType};
4+
5+
use cryptoki_sys::*;
6+
use std::{convert::TryInto, marker::PhantomData, ptr::null_mut};
7+
8+
/// The hedge type for ML-DSA signature
9+
#[derive(Debug, Clone, Copy, PartialEq)]
10+
pub enum HedgeType {
11+
/// CKH_HEDGE_PREFERRED: Default
12+
/// token may create either a hedged signature or a deterministic signature
13+
Preferred,
14+
/// CKH_HEDGE_REQUIRED
15+
/// token must produce a hedged signature or fail
16+
Required,
17+
/// CKH_DETERMINISTIC_REQUIRED
18+
/// token must produce a deterministic signature or fail
19+
DeterministicRequired,
20+
}
21+
22+
impl HedgeType {
23+
/// Convert the enum to Cryptoki value
24+
pub fn into_ck(&self) -> CK_HEDGE_TYPE {
25+
match self {
26+
HedgeType::Preferred => CKH_HEDGE_PREFERRED,
27+
HedgeType::Required => CKH_HEDGE_REQUIRED,
28+
HedgeType::DeterministicRequired => CKH_DETERMINISTIC_REQUIRED,
29+
}
30+
}
31+
}
32+
33+
/// The ML-DSA additional context for signatures
34+
///
35+
/// This structure wraps `CK_SIGN_ADDITIONAL_CONTEXT` structure.
36+
#[derive(Debug, Clone, Copy)]
37+
pub struct SignAdditionalContext<'a> {
38+
inner: Option<CK_SIGN_ADDITIONAL_CONTEXT>,
39+
/// Marker type to ensure we don't outlive the data
40+
_marker: PhantomData<&'a [u8]>,
41+
}
42+
43+
impl SignAdditionalContext<'_> {
44+
/// Construct ML-DSA signature parameters.
45+
///
46+
/// # Arguments
47+
///
48+
/// * `hedge` - The HedgeType.
49+
/// * `context` - The context.
50+
///
51+
/// # Returns
52+
///
53+
/// A new SignAdditionalContext struct.
54+
pub fn new(hedge: HedgeType, context: Option<&[u8]>) -> Self {
55+
if hedge == HedgeType::Preferred && context.is_none() {
56+
return Self {
57+
inner: None,
58+
_marker: PhantomData,
59+
};
60+
}
61+
62+
let (p_context, ul_context_len) = match context {
63+
Some(c) => (
64+
c.as_ptr() as *mut _,
65+
c.len().try_into().expect("usize can not fit in CK_ULONG"),
66+
),
67+
None => (null_mut() as *mut _, 0),
68+
};
69+
Self {
70+
inner: Some(CK_SIGN_ADDITIONAL_CONTEXT {
71+
hedgeVariant: hedge.into_ck(),
72+
pContext: p_context,
73+
ulContextLen: ul_context_len,
74+
}),
75+
_marker: PhantomData,
76+
}
77+
}
78+
79+
/// Retrieve the inner `CK_SIGN_ADDITIONAL_CONTEXT` struct, if present.
80+
///
81+
/// This method provides a reference to the `CK_SIGN_ADDITIONAL_CONTEXT`
82+
/// struct encapsulated within the `SignAdditionalContext`, if the signature
83+
/// scheme requires additional parameters.
84+
///
85+
/// # Returns
86+
///
87+
/// `Some(&CK_SIGN_ADDITIONAL_CONTEXT)` if the signature scheme has associated
88+
/// parameters, otherwise `None`.
89+
pub fn inner(&self) -> Option<&CK_SIGN_ADDITIONAL_CONTEXT> {
90+
self.inner.as_ref()
91+
}
92+
}
93+
94+
/// The ML-DSA additional context for signatures with hashing information
95+
///
96+
/// This structure wraps `CK_HASH_SIGN_ADDITIONAL_CONTEXT` structure.
97+
#[derive(Debug, Clone, Copy)]
98+
pub struct HashSignAdditionalContext<'a> {
99+
inner: CK_HASH_SIGN_ADDITIONAL_CONTEXT,
100+
/// Marker type to ensure we don't outlive the data
101+
_marker: PhantomData<&'a [u8]>,
102+
}
103+
104+
impl HashSignAdditionalContext<'_> {
105+
/// Construct HashML-DSA Signature parameters.
106+
///
107+
/// # Arguments
108+
///
109+
/// * `hedge` - The HedgeType.
110+
/// * `context` - The context
111+
/// * `hash` - The hash type
112+
///
113+
/// # Returns
114+
///
115+
/// A new SignAdditionalContext struct.
116+
pub fn new(hedge: HedgeType, context: Option<&[u8]>, hash: MechanismType) -> Self {
117+
let (p_context, ul_context_len) = match context {
118+
Some(c) => (
119+
c.as_ptr() as *mut _,
120+
c.len().try_into().expect("usize can not fit in CK_ULONG"),
121+
),
122+
None => (null_mut(), 0),
123+
};
124+
Self {
125+
inner: CK_HASH_SIGN_ADDITIONAL_CONTEXT {
126+
hedgeVariant: hedge.into_ck(),
127+
pContext: p_context,
128+
ulContextLen: ul_context_len,
129+
hash: hash.into(),
130+
},
131+
_marker: PhantomData,
132+
}
133+
}
134+
135+
/// Retrieve the inner `CK_HASH_SIGN_ADDITIONAL_CONTEXT` struct.
136+
///
137+
/// This method provides a reference to the `CK_HASH_SIGN_ADDITIONAL_CONTEXT`
138+
/// struct encapsulated within the `HashSignAdditionalContext`.
139+
///
140+
/// # Returns
141+
///
142+
/// `&CK_HASH_SIGN_ADDITIONAL_CONTEXT`.
143+
pub fn inner(&self) -> &CK_HASH_SIGN_ADDITIONAL_CONTEXT {
144+
&self.inner
145+
}
146+
}
147+
148+
impl<'a> From<HashSignAdditionalContext<'a>> for Mechanism<'a> {
149+
fn from(params: HashSignAdditionalContext<'a>) -> Self {
150+
Mechanism::HashMlDsa(params)
151+
}
152+
}

cryptoki/src/mechanism/mod.rs

Lines changed: 141 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub mod elliptic_curve;
99
pub mod hkdf;
1010
pub mod kbkdf;
1111
mod mechanism_info;
12+
pub mod mldsa;
1213
pub mod rsa;
1314
pub mod vendor_defined;
1415

@@ -349,6 +350,58 @@ impl MechanismType {
349350
/// ML-KEM encapsulation and decapsulation mechanism
350351
pub const ML_KEM: MechanismType = MechanismType { val: CKM_ML_KEM };
351352

353+
// ML-DSA
354+
/// ML-DSA key pair generation mechanism
355+
pub const ML_DSA_KEY_PAIR_GEN: MechanismType = MechanismType {
356+
val: CKM_ML_DSA_KEY_PAIR_GEN,
357+
};
358+
/// ML-DSA signature mechanism
359+
pub const ML_DSA: MechanismType = MechanismType { val: CKM_ML_DSA };
360+
/// HashML-DSA signature mechanism
361+
pub const HASH_ML_DSA: MechanismType = MechanismType {
362+
val: CKM_HASH_ML_DSA,
363+
};
364+
/// HashML-DSA signature mechanism with SHA224
365+
pub const HASH_ML_DSA_SHA224: MechanismType = MechanismType {
366+
val: CKM_HASH_ML_DSA_SHA224,
367+
};
368+
/// HashML-DSA signature mechanism with SHA256
369+
pub const HASH_ML_DSA_SHA256: MechanismType = MechanismType {
370+
val: CKM_HASH_ML_DSA_SHA256,
371+
};
372+
/// HashML-DSA signature mechanism with SHA384
373+
pub const HASH_ML_DSA_SHA384: MechanismType = MechanismType {
374+
val: CKM_HASH_ML_DSA_SHA384,
375+
};
376+
/// HashML-DSA signature mechanism with SHA512
377+
pub const HASH_ML_DSA_SHA512: MechanismType = MechanismType {
378+
val: CKM_HASH_ML_DSA_SHA512,
379+
};
380+
/// HashML-DSA signature mechanism with SHA3-224
381+
pub const HASH_ML_DSA_SHA3_224: MechanismType = MechanismType {
382+
val: CKM_HASH_ML_DSA_SHA3_224,
383+
};
384+
/// HashML-DSA signature mechanism with SHA3-256
385+
pub const HASH_ML_DSA_SHA3_256: MechanismType = MechanismType {
386+
val: CKM_HASH_ML_DSA_SHA3_256,
387+
};
388+
/// HashML-DSA signature mechanism with SHA3-384
389+
pub const HASH_ML_DSA_SHA3_384: MechanismType = MechanismType {
390+
val: CKM_HASH_ML_DSA_SHA3_384,
391+
};
392+
/// HashML-DSA signature mechanism with SHA3-512
393+
pub const HASH_ML_DSA_SHA3_512: MechanismType = MechanismType {
394+
val: CKM_HASH_ML_DSA_SHA3_512,
395+
};
396+
/// HashML-DSA signature mechanism with SHAKE128
397+
pub const HASH_ML_DSA_SHAKE128: MechanismType = MechanismType {
398+
val: CKM_HASH_ML_DSA_SHAKE128,
399+
};
400+
/// HashML-DSA signature mechanism with SHAKE256
401+
pub const HASH_ML_DSA_SHAKE256: MechanismType = MechanismType {
402+
val: CKM_HASH_ML_DSA_SHAKE256,
403+
};
404+
352405
/// Create vendor defined mechanism
353406
///
354407
/// # Arguments
@@ -745,6 +798,19 @@ impl MechanismType {
745798
}
746799
CKM_ML_KEM_KEY_PAIR_GEN => String::from(stringify!(CKM_ML_KEM_KEY_PAIR_GEN)),
747800
CKM_ML_KEM => String::from(stringify!(CKM_ML_KEM)),
801+
CKM_ML_DSA_KEY_PAIR_GEN => String::from(stringify!(CKM_ML_DSA_KEY_PAIR_GEN)),
802+
CKM_ML_DSA => String::from(stringify!(CKM_ML_DSA)),
803+
CKM_HASH_ML_DSA => String::from(stringify!(CKM_HASH_ML_DSA)),
804+
CKM_HASH_ML_DSA_SHA224 => String::from(stringify!(CKM_HASH_ML_DSA_SHA224)),
805+
CKM_HASH_ML_DSA_SHA256 => String::from(stringify!(CKM_HASH_ML_DSA_SHA256)),
806+
CKM_HASH_ML_DSA_SHA384 => String::from(stringify!(CKM_HASH_ML_DSA_SHA384)),
807+
CKM_HASH_ML_DSA_SHA512 => String::from(stringify!(CKM_HASH_ML_DSA_SHA512)),
808+
CKM_HASH_ML_DSA_SHA3_224 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_224)),
809+
CKM_HASH_ML_DSA_SHA3_256 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_256)),
810+
CKM_HASH_ML_DSA_SHA3_384 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_384)),
811+
CKM_HASH_ML_DSA_SHA3_512 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_512)),
812+
CKM_HASH_ML_DSA_SHAKE128 => String::from(stringify!(CKM_HASH_ML_DSA_SHAKE128)),
813+
CKM_HASH_ML_DSA_SHAKE256 => String::from(stringify!(CKM_HASH_ML_DSA_SHAKE256)),
748814
_ => format!("unknown {mech:08x}"),
749815
}
750816
}
@@ -834,6 +900,18 @@ impl TryFrom<CK_MECHANISM_TYPE> for MechanismType {
834900
CKM_SP800_108_DOUBLE_PIPELINE_KDF => Ok(MechanismType::SP800_108_DOUBLE_PIPELINE_KDF),
835901
CKM_ML_KEM_KEY_PAIR_GEN => Ok(MechanismType::ML_KEM_KEY_PAIR_GEN),
836902
CKM_ML_KEM => Ok(MechanismType::ML_KEM),
903+
CKM_ML_DSA_KEY_PAIR_GEN => Ok(MechanismType::ML_DSA_KEY_PAIR_GEN),
904+
CKM_ML_DSA => Ok(MechanismType::ML_DSA),
905+
CKM_HASH_ML_DSA => Ok(MechanismType::HASH_ML_DSA),
906+
CKM_HASH_ML_DSA_SHA224 => Ok(MechanismType::HASH_ML_DSA_SHA224),
907+
CKM_HASH_ML_DSA_SHA256 => Ok(MechanismType::HASH_ML_DSA_SHA256),
908+
CKM_HASH_ML_DSA_SHA384 => Ok(MechanismType::HASH_ML_DSA_SHA384),
909+
CKM_HASH_ML_DSA_SHA512 => Ok(MechanismType::HASH_ML_DSA_SHA512),
910+
CKM_HASH_ML_DSA_SHA3_224 => Ok(MechanismType::HASH_ML_DSA_SHA3_224),
911+
CKM_HASH_ML_DSA_SHA3_256 => Ok(MechanismType::HASH_ML_DSA_SHA3_256),
912+
CKM_HASH_ML_DSA_SHA3_384 => Ok(MechanismType::HASH_ML_DSA_SHA3_384),
913+
CKM_HASH_ML_DSA_SHA3_512 => Ok(MechanismType::HASH_ML_DSA_SHA3_512),
914+
CKM_HASH_ML_DSA_SHAKE128 => Ok(MechanismType::HASH_ML_DSA_SHAKE128),
837915
other => {
838916
error!("Mechanism type {} is not supported.", other);
839917
Err(Error::NotSupported)
@@ -1070,6 +1148,34 @@ pub enum Mechanism<'a> {
10701148
/// ML-KEM key encacpsulation/decapsulation mechanism
10711149
MlKem,
10721150

1151+
// ML-DSA
1152+
/// ML-DSA key pair generation mechanism
1153+
MlDsaKeyPairGen,
1154+
/// ML-DSA signature mechanism
1155+
MlDsa(mldsa::SignAdditionalContext<'a>),
1156+
/// HashML-DSA signature mechanism
1157+
HashMlDsa(mldsa::HashSignAdditionalContext<'a>),
1158+
/// HashML-DSA signature mechanism with SHA224
1159+
HashMlDsaSha224(mldsa::SignAdditionalContext<'a>),
1160+
/// HashML-DSA signature mechanism with SHA256
1161+
HashMlDsaSha256(mldsa::SignAdditionalContext<'a>),
1162+
/// HashML-DSA signature mechanism with SHA384
1163+
HashMlDsaSha384(mldsa::SignAdditionalContext<'a>),
1164+
/// HashML-DSA signature mechanism with SHA512
1165+
HashMlDsaSha512(mldsa::SignAdditionalContext<'a>),
1166+
/// HashML-DSA signature mechanism with SHA3-224
1167+
HashMlDsaSha3_224(mldsa::SignAdditionalContext<'a>),
1168+
/// HashML-DSA signature mechanism with SHA3-256
1169+
HashMlDsaSha3_256(mldsa::SignAdditionalContext<'a>),
1170+
/// HashML-DSA signature mechanism with SHA3-384
1171+
HashMlDsaSha3_384(mldsa::SignAdditionalContext<'a>),
1172+
/// HashML-DSA signature mechanism with SHA3-512
1173+
HashMlDsaSha3_512(mldsa::SignAdditionalContext<'a>),
1174+
/// HashML-DSA signature mechanism with SHAKE128
1175+
HashMlDsaShake128(mldsa::SignAdditionalContext<'a>),
1176+
/// HashML-DSA signature mechanism with SHAKE256
1177+
HashMlDsaShake256(mldsa::SignAdditionalContext<'a>),
1178+
10731179
/// Vendor defined mechanism
10741180
VendorDefined(VendorDefinedMechanism<'a>),
10751181
}
@@ -1158,6 +1264,20 @@ impl Mechanism<'_> {
11581264
Mechanism::MlKemKeyPairGen => MechanismType::ML_KEM_KEY_PAIR_GEN,
11591265
Mechanism::MlKem => MechanismType::ML_KEM,
11601266

1267+
Mechanism::MlDsaKeyPairGen => MechanismType::ML_DSA_KEY_PAIR_GEN,
1268+
Mechanism::MlDsa(_) => MechanismType::ML_DSA,
1269+
Mechanism::HashMlDsa(_) => MechanismType::HASH_ML_DSA,
1270+
Mechanism::HashMlDsaSha224(_) => MechanismType::HASH_ML_DSA_SHA224,
1271+
Mechanism::HashMlDsaSha256(_) => MechanismType::HASH_ML_DSA_SHA256,
1272+
Mechanism::HashMlDsaSha384(_) => MechanismType::HASH_ML_DSA_SHA384,
1273+
Mechanism::HashMlDsaSha512(_) => MechanismType::HASH_ML_DSA_SHA512,
1274+
Mechanism::HashMlDsaSha3_224(_) => MechanismType::HASH_ML_DSA_SHA3_224,
1275+
Mechanism::HashMlDsaSha3_256(_) => MechanismType::HASH_ML_DSA_SHA3_256,
1276+
Mechanism::HashMlDsaSha3_384(_) => MechanismType::HASH_ML_DSA_SHA3_384,
1277+
Mechanism::HashMlDsaSha3_512(_) => MechanismType::HASH_ML_DSA_SHA3_512,
1278+
Mechanism::HashMlDsaShake128(_) => MechanismType::HASH_ML_DSA_SHAKE128,
1279+
Mechanism::HashMlDsaShake256(_) => MechanismType::HASH_ML_DSA_SHAKE256,
1280+
11611281
Mechanism::VendorDefined(vm) => MechanismType {
11621282
val: vm.inner.mechanism,
11631283
},
@@ -1214,6 +1334,25 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
12141334
make_mechanism(mechanism, params.inner())
12151335
}
12161336
Mechanism::KbkdfFeedback(params) => make_mechanism(mechanism, params.inner()),
1337+
Mechanism::HashMlDsa(params) => make_mechanism(mechanism, params),
1338+
Mechanism::MlDsa(params)
1339+
| Mechanism::HashMlDsaSha224(params)
1340+
| Mechanism::HashMlDsaSha256(params)
1341+
| Mechanism::HashMlDsaSha384(params)
1342+
| Mechanism::HashMlDsaSha512(params)
1343+
| Mechanism::HashMlDsaSha3_224(params)
1344+
| Mechanism::HashMlDsaSha3_256(params)
1345+
| Mechanism::HashMlDsaSha3_384(params)
1346+
| Mechanism::HashMlDsaSha3_512(params)
1347+
| Mechanism::HashMlDsaShake128(params)
1348+
| Mechanism::HashMlDsaShake256(params) => match params.inner() {
1349+
None => CK_MECHANISM {
1350+
mechanism,
1351+
pParameter: null_mut(),
1352+
ulParameterLen: 0,
1353+
},
1354+
Some(params) => make_mechanism(mechanism, params),
1355+
},
12171356
// Mechanisms without parameters
12181357
Mechanism::AesKeyGen
12191358
| Mechanism::AesEcb
@@ -1260,7 +1399,8 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
12601399
| Mechanism::GenericSecretKeyGen
12611400
| Mechanism::HkdfKeyGen
12621401
| Mechanism::MlKemKeyPairGen
1263-
| Mechanism::MlKem => CK_MECHANISM {
1402+
| Mechanism::MlKem
1403+
| Mechanism::MlDsaKeyPairGen => CK_MECHANISM {
12641404
mechanism,
12651405
pParameter: null_mut(),
12661406
ulParameterLen: 0,

0 commit comments

Comments
 (0)