Skip to content

Commit 0b67201

Browse files
committed
Add support for ML-DSA
Signed-off-by: Jakub Jelen <[email protected]>
1 parent 328807f commit 0b67201

File tree

3 files changed

+373
-1
lines changed

3 files changed

+373
-1
lines changed

cryptoki/src/mechanism/mldsa.rs

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

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)