Skip to content

Commit 5b5bd98

Browse files
author
Willy Zhang
committed
[hsmtool] Refactor MLDSA key logic to util/key/mldsa
Moves the MLDSA key encoding and decoding logic from the import/export commands into a dedicated utility module at `sw/host/hsmtool/src/util/key/mldsa.rs`. Signed-off-by: Willy Zhang <[email protected]>
1 parent 2ce5400 commit 5b5bd98

File tree

6 files changed

+459
-148
lines changed

6 files changed

+459
-148
lines changed

sw/host/hsmtool/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ rust_library(
156156
"src/util/escape.rs",
157157
"src/util/helper.rs",
158158
"src/util/key/ecdsa.rs",
159+
"src/util/key/mldsa.rs",
159160
"src/util/key/mod.rs",
160161
"src/util/key/rsa.rs",
161162
"src/util/mod.rs",

sw/host/hsmtool/src/commands/mldsa/export.rs

Lines changed: 8 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,12 @@ use std::path::PathBuf;
1313
use crate::commands::{BasicResult, Dispatch};
1414
use crate::error::HsmError;
1515
use crate::module::Module;
16-
use crate::util::attribute::{AttributeMap, AttributeType, KeyType, ObjectClass};
16+
use crate::util::attribute::{AttributeMap, KeyType, ObjectClass};
1717
use crate::util::helper;
18+
use crate::util::key::mldsa;
1819
use crate::util::key::KeyEncoding;
1920
use crate::util::wrap::{Wrap, WrapPrivateKey};
2021

21-
use der::{Encode, EncodePem};
22-
use ml_dsa::{
23-
EncodedSigningKey, EncodedVerifyingKey, MlDsa44, MlDsa65, MlDsa87, SigningKey, VerifyingKey,
24-
};
25-
use pkcs8::{LineEnding, PrivateKeyInfo};
26-
use spki::{AssociatedAlgorithmIdentifier, EncodePublicKey};
27-
2822
#[derive(clap::Args, Debug, Serialize, Deserialize)]
2923
pub struct Export {
3024
#[arg(long)]
@@ -48,89 +42,13 @@ pub struct Export {
4842
impl Export {
4943
fn export(&self, session: &Session, object: ObjectHandle) -> Result<()> {
5044
let map = AttributeMap::from_object(session, object)?;
51-
let val = map
52-
.get(&AttributeType::Value)
53-
.ok_or(anyhow!("Key does not contain a value"))?;
54-
let key_value: Vec<u8> = val.try_into()?;
55-
56-
let encoded_bytes = if self.private {
57-
if let Ok(arr) = EncodedSigningKey::<MlDsa44>::try_from(key_value.as_slice()) {
58-
let _ = SigningKey::<MlDsa44>::decode(&arr); // Validate
59-
let pk_info = PrivateKeyInfo::new(MlDsa44::ALGORITHM_IDENTIFIER, &key_value);
60-
match self.format {
61-
KeyEncoding::Der | KeyEncoding::Pkcs8Der => pk_info.to_der()?,
62-
KeyEncoding::Pem | KeyEncoding::Pkcs8Pem => {
63-
pk_info.to_pem(LineEnding::LF)?.as_bytes().to_vec()
64-
}
65-
_ => return Err(anyhow!("Unsupported format for MLDSA export")),
66-
}
67-
} else if let Ok(arr) = EncodedSigningKey::<MlDsa65>::try_from(key_value.as_slice()) {
68-
let _ = SigningKey::<MlDsa65>::decode(&arr); // Validate
69-
let pk_info = PrivateKeyInfo::new(MlDsa65::ALGORITHM_IDENTIFIER, &key_value);
70-
match self.format {
71-
KeyEncoding::Der | KeyEncoding::Pkcs8Der => pk_info.to_der()?,
72-
KeyEncoding::Pem | KeyEncoding::Pkcs8Pem => {
73-
pk_info.to_pem(LineEnding::LF)?.as_bytes().to_vec()
74-
}
75-
_ => return Err(anyhow!("Unsupported format for MLDSA export")),
76-
}
77-
} else if let Ok(arr) = EncodedSigningKey::<MlDsa87>::try_from(key_value.as_slice()) {
78-
let _ = SigningKey::<MlDsa87>::decode(&arr); // Validate
79-
let pk_info = PrivateKeyInfo::new(MlDsa87::ALGORITHM_IDENTIFIER, &key_value);
80-
match self.format {
81-
KeyEncoding::Der | KeyEncoding::Pkcs8Der => pk_info.to_der()?,
82-
KeyEncoding::Pem | KeyEncoding::Pkcs8Pem => {
83-
pk_info.to_pem(LineEnding::LF)?.as_bytes().to_vec()
84-
}
85-
_ => return Err(anyhow!("Unsupported format for MLDSA export")),
86-
}
87-
} else {
88-
return Err(anyhow!(
89-
"Could not decode MLDSA private key (length: {})",
90-
key_value.len()
91-
));
92-
}
93-
} else if let Ok(arr) = EncodedVerifyingKey::<MlDsa44>::try_from(key_value.as_slice()) {
94-
let key = VerifyingKey::<MlDsa44>::decode(&arr);
95-
match self.format {
96-
KeyEncoding::Der | KeyEncoding::Pkcs8Der => {
97-
key.to_public_key_der()?.as_bytes().to_vec()
98-
}
99-
KeyEncoding::Pem | KeyEncoding::Pkcs8Pem => {
100-
key.to_public_key_pem(LineEnding::LF)?.as_bytes().to_vec()
101-
}
102-
_ => return Err(anyhow!("Unsupported format for MLDSA export")),
103-
}
104-
} else if let Ok(arr) = EncodedVerifyingKey::<MlDsa65>::try_from(key_value.as_slice()) {
105-
let key = VerifyingKey::<MlDsa65>::decode(&arr);
106-
match self.format {
107-
KeyEncoding::Der | KeyEncoding::Pkcs8Der => {
108-
key.to_public_key_der()?.as_bytes().to_vec()
109-
}
110-
KeyEncoding::Pem | KeyEncoding::Pkcs8Pem => {
111-
key.to_public_key_pem(LineEnding::LF)?.as_bytes().to_vec()
112-
}
113-
_ => return Err(anyhow!("Unsupported format for MLDSA export")),
114-
}
115-
} else if let Ok(arr) = EncodedVerifyingKey::<MlDsa87>::try_from(key_value.as_slice()) {
116-
let key = VerifyingKey::<MlDsa87>::decode(&arr);
117-
match self.format {
118-
KeyEncoding::Der | KeyEncoding::Pkcs8Der => {
119-
key.to_public_key_der()?.as_bytes().to_vec()
120-
}
121-
KeyEncoding::Pem | KeyEncoding::Pkcs8Pem => {
122-
key.to_public_key_pem(LineEnding::LF)?.as_bytes().to_vec()
123-
}
124-
_ => return Err(anyhow!("Unsupported format for MLDSA export")),
125-
}
45+
if self.private {
46+
let key = mldsa::MldsaSigningKey::try_from(&map)?;
47+
mldsa::save_private_key(&self.filename, &key, self.format)?;
12648
} else {
127-
return Err(anyhow!(
128-
"Could not decode MLDSA public key (length: {})",
129-
key_value.len()
130-
));
131-
};
132-
133-
fs::write(&self.filename, &encoded_bytes)?;
49+
let key = mldsa::MldsaVerifyingKey::try_from(&map)?;
50+
mldsa::save_public_key(&self.filename, &key, self.format)?;
51+
}
13452
Ok(())
13553
}
13654

sw/host/hsmtool/src/commands/mldsa/export_csr.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// SPDX-License-Identifier: Apache-2.0
44

55
use anyhow::{Result, anyhow};
6-
use const_oid::ObjectIdentifier;
76
use cryptoki::mechanism::Mechanism;
87
use cryptoki::mechanism::vendor_defined::VendorDefinedMechanism;
98
use cryptoki::object::Attribute;
@@ -21,11 +20,9 @@ use x509_cert::spki::{AlgorithmIdentifierOwned, SubjectPublicKeyInfoOwned};
2120
use crate::commands::{BasicResult, Dispatch};
2221
use crate::error::HsmError;
2322
use crate::module::Module;
24-
use crate::util::attribute::{AttributeMap, AttributeType, KeyType, MechanismType, ObjectClass};
23+
use crate::util::attribute::{AttributeMap, KeyType, MechanismType, ObjectClass};
2524
use crate::util::helper;
26-
27-
// ML-DSA-87 OID: 2.16.840.1.101.3.4.3.19
28-
const OID_MLDSA_87: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.16.840.1.101.3.4.3.19");
25+
use crate::util::key::mldsa;
2926

3027
#[derive(clap::Args, Debug, Serialize, Deserialize)]
3128
pub struct ExportCsr {
@@ -67,18 +64,16 @@ impl ExportCsr {
6764

6865
// Get public key value
6966
let map = AttributeMap::from_object(session, public_key)?;
70-
let val = map
71-
.get(&AttributeType::Value)
72-
.ok_or(anyhow!("Public key does not contain a value"))?;
73-
let pub_key_bytes: Vec<u8> = val.try_into()?;
67+
let key = mldsa::MldsaVerifyingKey::try_from(&map)?;
68+
let pub_key_bytes = key.encode();
7469

7570
// Construct Subject Name
7671
let subject =
7772
Name::from_str(&self.subject).map_err(|e| anyhow!("Invalid subject: {}", e))?;
7873

7974
// Create CertReqInfo
8075
let algorithm = AlgorithmIdentifierOwned {
81-
oid: OID_MLDSA_87,
76+
oid: key.oid(),
8277
parameters: None,
8378
};
8479
let subject_public_key_info = SubjectPublicKeyInfoOwned {

sw/host/hsmtool/src/commands/mldsa/import.rs

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,9 @@ use crate::error::HsmError;
1616
use crate::module::Module;
1717
use crate::util::attribute::{AttrData, AttributeMap, AttributeType};
1818
use crate::util::helper;
19+
use crate::util::key::mldsa;
1920
use crate::util::wrap::{Wrap, WrapPrivateKey};
2021

21-
use ml_dsa::{MlDsa44, MlDsa65, MlDsa87, SigningKey, VerifyingKey};
22-
use pkcs8::DecodePrivateKey;
23-
use spki::DecodePublicKey;
24-
2522
#[derive(clap::Args, Debug, Serialize, Deserialize)]
2623
pub struct Import {
2724
#[arg(long)]
@@ -64,56 +61,30 @@ impl Import {
6461
}"#;
6562

6663
fn import(&self, session: &Session, id: AttrData, label: AttrData) -> Result<ObjectHandle> {
67-
let data = fs::read(&self.filename)?;
68-
let der_bytes = if let Ok((_label, bytes)) = pem_rfc7468::decode_vec(&data) {
69-
bytes
70-
} else {
71-
// Assume DER/Raw
72-
data
73-
};
74-
75-
let (key_value, mldsa_type) = if self.private {
76-
if let Ok(key) = SigningKey::<MlDsa44>::from_pkcs8_der(&der_bytes) {
77-
(key.encode().to_vec(), 1u64)
78-
} else if let Ok(key) = SigningKey::<MlDsa65>::from_pkcs8_der(&der_bytes) {
79-
(key.encode().to_vec(), 2u64)
80-
} else if let Ok(key) = SigningKey::<MlDsa87>::from_pkcs8_der(&der_bytes) {
81-
(key.encode().to_vec(), 3u64)
82-
} else {
83-
return Err(anyhow!("Could not decode MLDSA private key from PKCS#8 DER"));
84-
}
85-
} else if let Ok(key) = VerifyingKey::<MlDsa44>::from_public_key_der(&der_bytes) {
86-
(key.encode().to_vec(), 1u64)
87-
} else if let Ok(key) = VerifyingKey::<MlDsa65>::from_public_key_der(&der_bytes) {
88-
(key.encode().to_vec(), 2u64)
89-
} else if let Ok(key) = VerifyingKey::<MlDsa87>::from_public_key_der(&der_bytes) {
90-
(key.encode().to_vec(), 3u64)
91-
} else {
92-
return Err(anyhow!("Could not decode MLDSA public key from SPKI DER"));
93-
};
94-
9564
let mut template = if self.private {
96-
AttributeMap::from_str(Self::PRIVATE_TEMPLATE).expect("error in PRIVATE_TEMPLATE")
65+
let key = mldsa::load_private_key(&self.filename)?;
66+
let mut template = AttributeMap::try_from(&key)?;
67+
template.merge(
68+
AttributeMap::from_str(Self::PRIVATE_TEMPLATE).expect("error in PRIVATE_TEMPLATE"),
69+
);
70+
if let Some(tpl) = &self.private_template {
71+
template.merge(tpl.clone());
72+
}
73+
template
9774
} else {
98-
AttributeMap::from_str(Self::PUBLIC_TEMPLATE).expect("error in PUBLIC_TEMPLATE")
75+
let key = mldsa::load_public_key(&self.filename)?;
76+
let mut template = AttributeMap::try_from(&key)?;
77+
template.merge(
78+
AttributeMap::from_str(Self::PUBLIC_TEMPLATE).expect("error in PUBLIC_TEMPLATE"),
79+
);
80+
if let Some(tpl) = &self.public_template {
81+
template.merge(tpl.clone());
82+
}
83+
template
9984
};
10085

10186
template.insert(AttributeType::Id, id);
10287
template.insert(AttributeType::Label, label);
103-
template.insert(AttributeType::Value, AttrData::from(key_value));
104-
105-
if self.private {
106-
if let Some(tpl) = &self.private_template {
107-
template.merge(tpl.clone());
108-
}
109-
} else if let Some(tpl) = &self.public_template {
110-
template.merge(tpl.clone());
111-
}
112-
113-
template.insert(
114-
AttributeType::ParameterSet,
115-
AttrData::from(mldsa_type),
116-
);
11788

11889
log::info!("template = {}", serde_json::to_string_pretty(&template)?);
11990

0 commit comments

Comments
 (0)