Skip to content

Commit 56b1427

Browse files
committed
Add support for ML-DSA
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
1 parent 977b0ad commit 56b1427

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
@@ -8,6 +8,7 @@ pub mod ekdf;
88
pub mod elliptic_curve;
99
pub mod hkdf;
1010
mod mechanism_info;
11+
pub mod mldsa;
1112
pub mod rsa;
1213
pub mod vendor_defined;
1314

@@ -334,6 +335,58 @@ impl MechanismType {
334335
/// ML-KEM encapsulation and decapsulation mechanism
335336
pub const ML_KEM: MechanismType = MechanismType { val: CKM_ML_KEM };
336337

338+
// ML-DSA
339+
/// ML-DSA key pair generation mechanism
340+
pub const ML_DSA_KEY_PAIR_GEN: MechanismType = MechanismType {
341+
val: CKM_ML_DSA_KEY_PAIR_GEN,
342+
};
343+
/// ML-DSA signature mechanism
344+
pub const ML_DSA: MechanismType = MechanismType { val: CKM_ML_DSA };
345+
/// HashML-DSA signature mechanism
346+
pub const HASH_ML_DSA: MechanismType = MechanismType {
347+
val: CKM_HASH_ML_DSA,
348+
};
349+
/// HashML-DSA signature mechanism with SHA224
350+
pub const HASH_ML_DSA_SHA224: MechanismType = MechanismType {
351+
val: CKM_HASH_ML_DSA_SHA224,
352+
};
353+
/// HashML-DSA signature mechanism with SHA256
354+
pub const HASH_ML_DSA_SHA256: MechanismType = MechanismType {
355+
val: CKM_HASH_ML_DSA_SHA256,
356+
};
357+
/// HashML-DSA signature mechanism with SHA384
358+
pub const HASH_ML_DSA_SHA384: MechanismType = MechanismType {
359+
val: CKM_HASH_ML_DSA_SHA384,
360+
};
361+
/// HashML-DSA signature mechanism with SHA512
362+
pub const HASH_ML_DSA_SHA512: MechanismType = MechanismType {
363+
val: CKM_HASH_ML_DSA_SHA512,
364+
};
365+
/// HashML-DSA signature mechanism with SHA3-224
366+
pub const HASH_ML_DSA_SHA3_224: MechanismType = MechanismType {
367+
val: CKM_HASH_ML_DSA_SHA3_224,
368+
};
369+
/// HashML-DSA signature mechanism with SHA3-256
370+
pub const HASH_ML_DSA_SHA3_256: MechanismType = MechanismType {
371+
val: CKM_HASH_ML_DSA_SHA3_256,
372+
};
373+
/// HashML-DSA signature mechanism with SHA3-384
374+
pub const HASH_ML_DSA_SHA3_384: MechanismType = MechanismType {
375+
val: CKM_HASH_ML_DSA_SHA3_384,
376+
};
377+
/// HashML-DSA signature mechanism with SHA3-512
378+
pub const HASH_ML_DSA_SHA3_512: MechanismType = MechanismType {
379+
val: CKM_HASH_ML_DSA_SHA3_512,
380+
};
381+
/// HashML-DSA signature mechanism with SHAKE128
382+
pub const HASH_ML_DSA_SHAKE128: MechanismType = MechanismType {
383+
val: CKM_HASH_ML_DSA_SHAKE128,
384+
};
385+
/// HashML-DSA signature mechanism with SHAKE256
386+
pub const HASH_ML_DSA_SHAKE256: MechanismType = MechanismType {
387+
val: CKM_HASH_ML_DSA_SHAKE256,
388+
};
389+
337390
/// Create vendor defined mechanism
338391
///
339392
/// # Arguments
@@ -725,6 +778,19 @@ impl MechanismType {
725778
CKM_HKDF_DATA => String::from(stringify!(CKM_HKDF_DATA)),
726779
CKM_ML_KEM_KEY_PAIR_GEN => String::from(stringify!(CKM_ML_KEM_KEY_PAIR_GEN)),
727780
CKM_ML_KEM => String::from(stringify!(CKM_ML_KEM)),
781+
CKM_ML_DSA_KEY_PAIR_GEN => String::from(stringify!(CKM_ML_DSA_KEY_PAIR_GEN)),
782+
CKM_ML_DSA => String::from(stringify!(CKM_ML_DSA)),
783+
CKM_HASH_ML_DSA => String::from(stringify!(CKM_HASH_ML_DSA)),
784+
CKM_HASH_ML_DSA_SHA224 => String::from(stringify!(CKM_HASH_ML_DSA_SHA224)),
785+
CKM_HASH_ML_DSA_SHA256 => String::from(stringify!(CKM_HASH_ML_DSA_SHA256)),
786+
CKM_HASH_ML_DSA_SHA384 => String::from(stringify!(CKM_HASH_ML_DSA_SHA384)),
787+
CKM_HASH_ML_DSA_SHA512 => String::from(stringify!(CKM_HASH_ML_DSA_SHA512)),
788+
CKM_HASH_ML_DSA_SHA3_224 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_224)),
789+
CKM_HASH_ML_DSA_SHA3_256 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_256)),
790+
CKM_HASH_ML_DSA_SHA3_384 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_384)),
791+
CKM_HASH_ML_DSA_SHA3_512 => String::from(stringify!(CKM_HASH_ML_DSA_SHA3_512)),
792+
CKM_HASH_ML_DSA_SHAKE128 => String::from(stringify!(CKM_HASH_ML_DSA_SHAKE128)),
793+
CKM_HASH_ML_DSA_SHAKE256 => String::from(stringify!(CKM_HASH_ML_DSA_SHAKE256)),
728794
_ => format!("unknown {mech:08x}"),
729795
}
730796
}
@@ -811,6 +877,18 @@ impl TryFrom<CK_MECHANISM_TYPE> for MechanismType {
811877
CKM_HKDF_DATA => Ok(MechanismType::HKDF_DATA),
812878
CKM_ML_KEM_KEY_PAIR_GEN => Ok(MechanismType::ML_KEM_KEY_PAIR_GEN),
813879
CKM_ML_KEM => Ok(MechanismType::ML_KEM),
880+
CKM_ML_DSA_KEY_PAIR_GEN => Ok(MechanismType::ML_DSA_KEY_PAIR_GEN),
881+
CKM_ML_DSA => Ok(MechanismType::ML_DSA),
882+
CKM_HASH_ML_DSA => Ok(MechanismType::HASH_ML_DSA),
883+
CKM_HASH_ML_DSA_SHA224 => Ok(MechanismType::HASH_ML_DSA_SHA224),
884+
CKM_HASH_ML_DSA_SHA256 => Ok(MechanismType::HASH_ML_DSA_SHA256),
885+
CKM_HASH_ML_DSA_SHA384 => Ok(MechanismType::HASH_ML_DSA_SHA384),
886+
CKM_HASH_ML_DSA_SHA512 => Ok(MechanismType::HASH_ML_DSA_SHA512),
887+
CKM_HASH_ML_DSA_SHA3_224 => Ok(MechanismType::HASH_ML_DSA_SHA3_224),
888+
CKM_HASH_ML_DSA_SHA3_256 => Ok(MechanismType::HASH_ML_DSA_SHA3_256),
889+
CKM_HASH_ML_DSA_SHA3_384 => Ok(MechanismType::HASH_ML_DSA_SHA3_384),
890+
CKM_HASH_ML_DSA_SHA3_512 => Ok(MechanismType::HASH_ML_DSA_SHA3_512),
891+
CKM_HASH_ML_DSA_SHAKE128 => Ok(MechanismType::HASH_ML_DSA_SHAKE128),
814892
other => {
815893
error!("Mechanism type {} is not supported.", other);
816894
Err(Error::NotSupported)
@@ -1039,6 +1117,34 @@ pub enum Mechanism<'a> {
10391117
/// ML-KEM key encacpsulation/decapsulation mechanism
10401118
MlKem,
10411119

1120+
// ML-DSA
1121+
/// ML-DSA key pair generation mechanism
1122+
MlDsaKeyPairGen,
1123+
/// ML-DSA signature mechanism
1124+
MlDsa(mldsa::SignAdditionalContext<'a>),
1125+
/// HashML-DSA signature mechanism
1126+
HashMlDsa(mldsa::HashSignAdditionalContext<'a>),
1127+
/// HashML-DSA signature mechanism with SHA224
1128+
HashMlDsaSha224(mldsa::SignAdditionalContext<'a>),
1129+
/// HashML-DSA signature mechanism with SHA256
1130+
HashMlDsaSha256(mldsa::SignAdditionalContext<'a>),
1131+
/// HashML-DSA signature mechanism with SHA384
1132+
HashMlDsaSha384(mldsa::SignAdditionalContext<'a>),
1133+
/// HashML-DSA signature mechanism with SHA512
1134+
HashMlDsaSha512(mldsa::SignAdditionalContext<'a>),
1135+
/// HashML-DSA signature mechanism with SHA3-224
1136+
HashMlDsaSha3_224(mldsa::SignAdditionalContext<'a>),
1137+
/// HashML-DSA signature mechanism with SHA3-256
1138+
HashMlDsaSha3_256(mldsa::SignAdditionalContext<'a>),
1139+
/// HashML-DSA signature mechanism with SHA3-384
1140+
HashMlDsaSha3_384(mldsa::SignAdditionalContext<'a>),
1141+
/// HashML-DSA signature mechanism with SHA3-512
1142+
HashMlDsaSha3_512(mldsa::SignAdditionalContext<'a>),
1143+
/// HashML-DSA signature mechanism with SHAKE128
1144+
HashMlDsaShake128(mldsa::SignAdditionalContext<'a>),
1145+
/// HashML-DSA signature mechanism with SHAKE256
1146+
HashMlDsaShake256(mldsa::SignAdditionalContext<'a>),
1147+
10421148
/// Vendor defined mechanism
10431149
VendorDefined(VendorDefinedMechanism<'a>),
10441150
}
@@ -1123,6 +1229,20 @@ impl Mechanism<'_> {
11231229
Mechanism::MlKemKeyPairGen => MechanismType::ML_KEM_KEY_PAIR_GEN,
11241230
Mechanism::MlKem => MechanismType::ML_KEM,
11251231

1232+
Mechanism::MlDsaKeyPairGen => MechanismType::ML_DSA_KEY_PAIR_GEN,
1233+
Mechanism::MlDsa(_) => MechanismType::ML_DSA,
1234+
Mechanism::HashMlDsa(_) => MechanismType::HASH_ML_DSA,
1235+
Mechanism::HashMlDsaSha224(_) => MechanismType::HASH_ML_DSA_SHA224,
1236+
Mechanism::HashMlDsaSha256(_) => MechanismType::HASH_ML_DSA_SHA256,
1237+
Mechanism::HashMlDsaSha384(_) => MechanismType::HASH_ML_DSA_SHA384,
1238+
Mechanism::HashMlDsaSha512(_) => MechanismType::HASH_ML_DSA_SHA512,
1239+
Mechanism::HashMlDsaSha3_224(_) => MechanismType::HASH_ML_DSA_SHA3_224,
1240+
Mechanism::HashMlDsaSha3_256(_) => MechanismType::HASH_ML_DSA_SHA3_256,
1241+
Mechanism::HashMlDsaSha3_384(_) => MechanismType::HASH_ML_DSA_SHA3_384,
1242+
Mechanism::HashMlDsaSha3_512(_) => MechanismType::HASH_ML_DSA_SHA3_512,
1243+
Mechanism::HashMlDsaShake128(_) => MechanismType::HASH_ML_DSA_SHAKE128,
1244+
Mechanism::HashMlDsaShake256(_) => MechanismType::HASH_ML_DSA_SHAKE256,
1245+
11261246
Mechanism::VendorDefined(vm) => MechanismType {
11271247
val: vm.inner.mechanism,
11281248
},
@@ -1175,6 +1295,25 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
11751295
Mechanism::HkdfDerive(params) | Mechanism::HkdfData(params) => {
11761296
make_mechanism(mechanism, params)
11771297
}
1298+
Mechanism::HashMlDsa(params) => make_mechanism(mechanism, params),
1299+
Mechanism::MlDsa(params)
1300+
| Mechanism::HashMlDsaSha224(params)
1301+
| Mechanism::HashMlDsaSha256(params)
1302+
| Mechanism::HashMlDsaSha384(params)
1303+
| Mechanism::HashMlDsaSha512(params)
1304+
| Mechanism::HashMlDsaSha3_224(params)
1305+
| Mechanism::HashMlDsaSha3_256(params)
1306+
| Mechanism::HashMlDsaSha3_384(params)
1307+
| Mechanism::HashMlDsaSha3_512(params)
1308+
| Mechanism::HashMlDsaShake128(params)
1309+
| Mechanism::HashMlDsaShake256(params) => match params.inner() {
1310+
None => CK_MECHANISM {
1311+
mechanism,
1312+
pParameter: null_mut(),
1313+
ulParameterLen: 0,
1314+
},
1315+
Some(params) => make_mechanism(mechanism, params),
1316+
},
11781317
// Mechanisms without parameters
11791318
Mechanism::AesKeyGen
11801319
| Mechanism::AesEcb
@@ -1221,7 +1360,8 @@ impl From<&Mechanism<'_>> for CK_MECHANISM {
12211360
| Mechanism::GenericSecretKeyGen
12221361
| Mechanism::HkdfKeyGen
12231362
| Mechanism::MlKemKeyPairGen
1224-
| Mechanism::MlKem => CK_MECHANISM {
1363+
| Mechanism::MlKem
1364+
| Mechanism::MlDsaKeyPairGen => CK_MECHANISM {
12251365
mechanism,
12261366
pParameter: null_mut(),
12271367
ulParameterLen: 0,

0 commit comments

Comments
 (0)