Skip to content

Commit 355b6c4

Browse files
committed
[update] MLDSA support for Authorization Manifest
1 parent 14069cc commit 355b6c4

File tree

14 files changed

+739
-156
lines changed

14 files changed

+739
-156
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/src/mailbox.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1238,7 +1238,7 @@ pub struct SetAuthManifestReq {
12381238
pub manifest: [u8; SetAuthManifestReq::MAX_MAN_SIZE],
12391239
}
12401240
impl SetAuthManifestReq {
1241-
pub const MAX_MAN_SIZE: usize = 17 * 1024;
1241+
pub const MAX_MAN_SIZE: usize = 34 * 1024;
12421242

12431243
pub fn as_bytes_partial(&self) -> CaliptraResult<&[u8]> {
12441244
if self.manifest_size as usize > Self::MAX_MAN_SIZE {

auth-manifest/app/src/auth-man.toml

+8
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,32 @@ ecc_pub_key = "vnd-pub-key-3.pem"
55
ecc_priv_key = "vnd-priv-key-3.pem"
66
lms_pub_key = "vnd-lms-pub-key-3.pem"
77
lms_priv_key = "vnd-lms-priv-key-3.pem"
8+
mldsa_pub_key = "vnd-mldsa-pub-key-3.bin"
9+
mldsa_priv_key = "vnd-mldsa-priv-key-3.bin"
810

911
[vendor_man_key_config]
1012
ecc_pub_key = "vnd-pub-key-3.pem"
1113
ecc_priv_key = "vnd-priv-key-3.pem"
1214
lms_pub_key = "vnd-lms-pub-key-3.pem"
1315
lms_priv_key = "vnd-lms-priv-key-3.pem"
16+
mldsa_pub_key = "vnd-mldsa-pub-key-3.bin"
17+
mldsa_priv_key = "vnd-mldsa-priv-key-3.bin"
1418

1519
[owner_fw_key_config]
1620
ecc_pub_key = "own-pub-key.pem"
1721
ecc_priv_key = "own-priv-key.pem"
1822
lms_pub_key = "own-lms-pub-key.pem"
1923
lms_priv_key = "own-lms-priv-key.pem"
24+
mldsa_pub_key = "own-mldsa-pub-key.bin"
25+
mldsa_priv_key = "own-mldsa-priv-key.bin"
2026

2127
[owner_man_key_config]
2228
ecc_pub_key = "own-pub-key.pem"
2329
ecc_priv_key = "own-priv-key.pem"
2430
lms_pub_key = "own-lms-pub-key.pem"
2531
lms_priv_key = "own-lms-priv-key.pem"
32+
mldsa_pub_key = "own-mldsa-pub-key.bin"
33+
mldsa_priv_key = "own-mldsa-priv-key.bin"
2634

2735
[[image_metadata_list]]
2836
digest = "C120EED0004B4CF6C344B00F5F501E7B7167C7010B6EA1D36AEE20CC90F1AE373DF1EC91C9AD9E0A5A969326A54E2517"

auth-manifest/app/src/config.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@ Abstract:
1414

1515
use anyhow::Context;
1616
use caliptra_auth_man_gen::AuthManifestGeneratorKeyConfig;
17-
use caliptra_auth_man_types::{Addr64, AuthManifestImageMetadata, AuthManifestPrivKeys};
18-
use caliptra_auth_man_types::{AuthManifestPubKeys, ImageMetadataFlags};
17+
use caliptra_auth_man_types::ImageMetadataFlags;
18+
use caliptra_auth_man_types::{
19+
Addr64, AuthManifestImageMetadata, AuthManifestPrivKeysConfig, AuthManifestPubKeysConfig,
20+
};
1921
#[cfg(feature = "openssl")]
2022
use caliptra_image_crypto::OsslCrypto as Crypto;
2123
#[cfg(feature = "rustcrypto")]
@@ -35,6 +37,10 @@ pub(crate) struct AuthManifestKeyConfigFromFile {
3537
pub lms_pub_key: String,
3638

3739
pub lms_priv_key: Option<String>,
40+
41+
pub mldsa_pub_key: String,
42+
43+
pub mldsa_priv_key: Option<String>,
3844
}
3945

4046
#[derive(Serialize, Deserialize)]
@@ -81,7 +87,7 @@ fn key_config_from_file(
8187
config: &AuthManifestKeyConfigFromFile,
8288
) -> anyhow::Result<AuthManifestGeneratorKeyConfig> {
8389
// Get the Private Keys.
84-
let mut priv_keys = AuthManifestPrivKeys::default();
90+
let mut priv_keys = AuthManifestPrivKeysConfig::default();
8591
if let Some(pem_file) = &config.ecc_priv_key {
8692
let priv_key_path = path.join(pem_file);
8793
priv_keys.ecc_priv_key = Crypto::ecc_priv_key_from_pem(&priv_key_path)?;
@@ -93,9 +99,10 @@ fn key_config_from_file(
9399
}
94100

95101
Ok(AuthManifestGeneratorKeyConfig {
96-
pub_keys: AuthManifestPubKeys {
102+
pub_keys: AuthManifestPubKeysConfig {
97103
ecc_pub_key: Crypto::ecc_pub_key_from_pem(&path.join(&config.ecc_pub_key))?,
98104
lms_pub_key: lms_pub_key_from_pem(&path.join(&config.lms_pub_key))?,
105+
mldsa_pub_key: Crypto::mldsa_pub_key_from_file(&path.join(&config.mldsa_pub_key))?,
99106
},
100107

101108
priv_keys: Some(priv_keys),

auth-manifest/app/src/main.rs

+11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use caliptra_auth_man_types::AuthManifestFlags;
1919
use caliptra_image_crypto::OsslCrypto as Crypto;
2020
#[cfg(feature = "rustcrypto")]
2121
use caliptra_image_crypto::RustCrypto as Crypto;
22+
use caliptra_image_types::FwVerificationPqcKeyType;
2223
use clap::ArgMatches;
2324
use clap::{arg, value_parser, Command};
2425
use std::io::Write;
@@ -82,6 +83,15 @@ pub(crate) fn run_auth_man_cmd(args: &ArgMatches) -> anyhow::Result<()> {
8283
.with_context(|| "flags arg not specified")?,
8384
);
8485

86+
let pqc_key_type: &u32 = args
87+
.get_one::<u32>("pqc-key-type")
88+
.with_context(|| "Type of PQC key validation: 1: MLDSA; 3: LMS")?;
89+
let pqc_key_type = match *pqc_key_type {
90+
1 => FwVerificationPqcKeyType::MLDSA,
91+
3 => FwVerificationPqcKeyType::LMS,
92+
_ => return Err(anyhow::anyhow!("Invalid PQC key type")),
93+
};
94+
8595
let config_path: &PathBuf = args
8696
.get_one::<PathBuf>("config")
8797
.with_context(|| "config arg not specified")?;
@@ -109,6 +119,7 @@ pub(crate) fn run_auth_man_cmd(args: &ArgMatches) -> anyhow::Result<()> {
109119
let gen_config = AuthManifestGeneratorConfig {
110120
version: *version,
111121
flags,
122+
pqc_key_type,
112123
vendor_man_key_info: config::vendor_config_from_file(
113124
key_dir,
114125
&config.vendor_man_key_config,

auth-manifest/gen/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ caliptra-image-gen.workspace = true
1616
caliptra-auth-man-types = { workspace = true, features = ["std"] }
1717
caliptra-lms-types.workspace = true
1818
memoffset.workspace = true
19-
zerocopy.workspace = true
19+
zerocopy.workspace = true
20+
fips204.workspace = true

auth-manifest/gen/src/generator.rs

+164-24
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@ Abstract:
1313
--*/
1414

1515
use caliptra_image_gen::ImageGeneratorCrypto;
16+
use caliptra_image_types::{
17+
ImageDigest512, ImageMldsaPrivKey, ImageMldsaSignature, MLDSA87_MSG_BYTE_SIZE,
18+
MLDSA87_PRIV_KEY_BYTE_SIZE,
19+
};
20+
use fips204::ml_dsa_87::{PrivateKey, SIG_LEN};
21+
use fips204::traits::{SerDes, Signer};
1622
use zerocopy::IntoBytes;
1723

1824
use crate::*;
@@ -56,7 +62,21 @@ impl<Crypto: ImageGeneratorCrypto> AuthManifestGenerator<Crypto> {
5662
auth_manifest.preamble.flags = config.flags.bits();
5763

5864
// Sign the vendor manifest public keys.
59-
auth_manifest.preamble.vendor_pub_keys = config.vendor_man_key_info.pub_keys;
65+
auth_manifest.preamble.vendor_pub_keys.ecc_pub_key =
66+
config.vendor_man_key_info.pub_keys.ecc_pub_key;
67+
let pqc_pub_key = match config.pqc_key_type {
68+
FwVerificationPqcKeyType::LMS => {
69+
config.vendor_man_key_info.pub_keys.lms_pub_key.as_bytes()
70+
}
71+
FwVerificationPqcKeyType::MLDSA => config
72+
.vendor_man_key_info
73+
.pub_keys
74+
.mldsa_pub_key
75+
.0
76+
.as_bytes(),
77+
};
78+
auth_manifest.preamble.vendor_pub_keys.pqc_pub_key.0[..pqc_pub_key.len()]
79+
.copy_from_slice(pqc_pub_key);
6080

6181
let range = AuthManifestPreamble::vendor_signed_data_range();
6282

@@ -70,25 +90,53 @@ impl<Crypto: ImageGeneratorCrypto> AuthManifestGenerator<Crypto> {
7090
"Failed to get vendor signed data range length"
7191
))?;
7292

73-
let digest = self.crypto.sha384_digest(data)?;
93+
let digest_sha384 = self.crypto.sha384_digest(data)?;
94+
let digest_sha512 = if config.pqc_key_type == FwVerificationPqcKeyType::MLDSA {
95+
let digest = self.crypto.sha512_digest(data)?;
96+
Some(digest)
97+
} else {
98+
None
99+
};
74100

75101
if let Some(priv_keys) = config.vendor_fw_key_info.priv_keys {
76102
let sig = self.crypto.ecdsa384_sign(
77-
&digest,
103+
&digest_sha384,
78104
&priv_keys.ecc_priv_key,
79105
&config.vendor_fw_key_info.pub_keys.ecc_pub_key,
80106
)?;
81107
auth_manifest.preamble.vendor_pub_keys_signatures.ecc_sig = sig;
82108

83-
let lms_sig = self.crypto.lms_sign(&digest, &priv_keys.lms_priv_key)?;
84-
auth_manifest.preamble.vendor_pub_keys_signatures.lms_sig = lms_sig;
109+
if config.pqc_key_type == FwVerificationPqcKeyType::LMS {
110+
let lms_sig = self
111+
.crypto
112+
.lms_sign(&digest_sha384, &priv_keys.lms_priv_key)?;
113+
let sig = lms_sig.as_bytes();
114+
auth_manifest.preamble.vendor_pub_keys_signatures.pqc_sig.0[..sig.len()]
115+
.copy_from_slice(sig);
116+
} else {
117+
let mldsa_sig =
118+
self.mldsa_sign(&digest_sha512.unwrap(), &priv_keys.mldsa_priv_key)?;
119+
120+
let sig = mldsa_sig.as_bytes();
121+
auth_manifest.preamble.vendor_pub_keys_signatures.pqc_sig.0[..sig.len()]
122+
.copy_from_slice(sig);
123+
}
85124
}
86125

87126
// Sign the owner manifest public keys.
88127
if let (Some(owner_fw_config), Some(owner_man_config)) =
89128
(&config.owner_fw_key_info, &config.owner_man_key_info)
90129
{
91-
auth_manifest.preamble.owner_pub_keys = owner_man_config.pub_keys;
130+
auth_manifest.preamble.owner_pub_keys.ecc_pub_key =
131+
owner_man_config.pub_keys.ecc_pub_key;
132+
let pqc_pub_key = match config.pqc_key_type {
133+
FwVerificationPqcKeyType::LMS => owner_man_config.pub_keys.lms_pub_key.as_bytes(),
134+
FwVerificationPqcKeyType::MLDSA => {
135+
owner_man_config.pub_keys.mldsa_pub_key.0.as_bytes()
136+
}
137+
};
138+
auth_manifest.preamble.owner_pub_keys.pqc_pub_key.0[..pqc_pub_key.len()]
139+
.copy_from_slice(pqc_pub_key);
92140

93141
let digest = self
94142
.crypto
@@ -101,10 +149,24 @@ impl<Crypto: ImageGeneratorCrypto> AuthManifestGenerator<Crypto> {
101149
&owner_fw_config.pub_keys.ecc_pub_key,
102150
)?;
103151
auth_manifest.preamble.owner_pub_keys_signatures.ecc_sig = sig;
104-
let lms_sig = self
105-
.crypto
106-
.lms_sign(&digest, &owner_fw_priv_keys.lms_priv_key)?;
107-
auth_manifest.preamble.owner_pub_keys_signatures.lms_sig = lms_sig;
152+
153+
if config.pqc_key_type == FwVerificationPqcKeyType::LMS {
154+
let lms_sig = self
155+
.crypto
156+
.lms_sign(&digest, &owner_fw_priv_keys.lms_priv_key)?;
157+
let sig = lms_sig.as_bytes();
158+
auth_manifest.preamble.owner_pub_keys_signatures.pqc_sig.0[..sig.len()]
159+
.copy_from_slice(sig);
160+
} else {
161+
let digest = self
162+
.crypto
163+
.sha512_digest(auth_manifest.preamble.owner_pub_keys.as_bytes())?;
164+
165+
let mldsa_sig = self.mldsa_sign(&digest, &owner_fw_priv_keys.mldsa_priv_key)?;
166+
let sig = mldsa_sig.as_bytes();
167+
auth_manifest.preamble.owner_pub_keys_signatures.pqc_sig.0[..sig.len()]
168+
.copy_from_slice(sig);
169+
}
108170
}
109171
}
110172

@@ -129,13 +191,32 @@ impl<Crypto: ImageGeneratorCrypto> AuthManifestGenerator<Crypto> {
129191
.vendor_image_metdata_signatures
130192
.ecc_sig = sig;
131193

132-
let lms_sig = self
133-
.crypto
134-
.lms_sign(&digest, &vendor_man_priv_keys.lms_priv_key)?;
135-
auth_manifest
136-
.preamble
137-
.vendor_image_metdata_signatures
138-
.lms_sig = lms_sig;
194+
if config.pqc_key_type == FwVerificationPqcKeyType::LMS {
195+
let lms_sig = self
196+
.crypto
197+
.lms_sign(&digest, &vendor_man_priv_keys.lms_priv_key)?;
198+
let sig = lms_sig.as_bytes();
199+
auth_manifest
200+
.preamble
201+
.vendor_image_metdata_signatures
202+
.pqc_sig
203+
.0[..sig.len()]
204+
.copy_from_slice(sig);
205+
} else {
206+
let digest = self
207+
.crypto
208+
.sha512_digest(auth_manifest.image_metadata_col.as_bytes())?;
209+
210+
let mldsa_sig =
211+
self.mldsa_sign(&digest, &vendor_man_priv_keys.mldsa_priv_key)?;
212+
let sig = mldsa_sig.as_bytes();
213+
auth_manifest
214+
.preamble
215+
.vendor_image_metdata_signatures
216+
.pqc_sig
217+
.0[..sig.len()]
218+
.copy_from_slice(sig);
219+
}
139220
}
140221
}
141222

@@ -152,16 +233,75 @@ impl<Crypto: ImageGeneratorCrypto> AuthManifestGenerator<Crypto> {
152233
.owner_image_metdata_signatures
153234
.ecc_sig = sig;
154235

155-
let lms_sig = self
156-
.crypto
157-
.lms_sign(&digest, &owner_man_priv_keys.lms_priv_key)?;
158-
auth_manifest
159-
.preamble
160-
.owner_image_metdata_signatures
161-
.lms_sig = lms_sig;
236+
if config.pqc_key_type == FwVerificationPqcKeyType::LMS {
237+
let lms_sig = self
238+
.crypto
239+
.lms_sign(&digest, &owner_man_priv_keys.lms_priv_key)?;
240+
241+
let sig = lms_sig.as_bytes();
242+
auth_manifest
243+
.preamble
244+
.owner_image_metdata_signatures
245+
.pqc_sig
246+
.0[..sig.len()]
247+
.copy_from_slice(sig);
248+
} else {
249+
let digest = self
250+
.crypto
251+
.sha512_digest(auth_manifest.image_metadata_col.as_bytes())?;
252+
253+
let mldsa_sig =
254+
self.mldsa_sign(&digest, &owner_man_priv_keys.mldsa_priv_key)?;
255+
let sig = mldsa_sig.as_bytes();
256+
auth_manifest
257+
.preamble
258+
.owner_image_metdata_signatures
259+
.pqc_sig
260+
.0[..sig.len()]
261+
.copy_from_slice(sig);
262+
}
162263
}
163264
}
164265

165266
Ok(auth_manifest)
166267
}
268+
269+
// [TODO][CAP2] Make this a common function in the crypto library.
270+
fn mldsa_sign(
271+
&self,
272+
digest: &ImageDigest512,
273+
priv_key: &ImageMldsaPrivKey,
274+
) -> anyhow::Result<ImageMldsaSignature> {
275+
// Private key is received in hw format which is also the library format.
276+
// Unlike ECC, no reversal of the DWORD endianess needed.
277+
let priv_key_bytes: [u8; MLDSA87_PRIV_KEY_BYTE_SIZE] = priv_key
278+
.0
279+
.as_bytes()
280+
.try_into()
281+
.map_err(|_| anyhow::anyhow!("Invalid private key size"))?;
282+
let priv_key = { PrivateKey::try_from_bytes(priv_key_bytes).unwrap() };
283+
284+
// Digest is received in hw format. Since the library and hardware format are the same, no endianess conversion needed.
285+
let digest: [u8; MLDSA87_MSG_BYTE_SIZE] = digest
286+
.as_bytes()
287+
.try_into()
288+
.map_err(|_| anyhow::anyhow!("Invalid digest size"))?;
289+
290+
let signature = priv_key
291+
.try_sign_with_seed(&[0u8; 32], &digest, &[])
292+
.unwrap();
293+
let signature_extended = {
294+
let mut sig = [0u8; SIG_LEN + 1];
295+
sig[..SIG_LEN].copy_from_slice(&signature);
296+
sig
297+
};
298+
299+
// Return the signature in hw format (which is also the library format)
300+
// Unlike ECC, no reversal of the DWORD endianess needed.
301+
let mut sig: ImageMldsaSignature = ImageMldsaSignature::default();
302+
for (i, chunk) in signature_extended.chunks(4).enumerate() {
303+
sig.0[i] = u32::from_le_bytes(chunk.try_into().unwrap());
304+
}
305+
Ok(sig)
306+
}
167307
}

0 commit comments

Comments
 (0)