Skip to content

Commit abc63dd

Browse files
authored
feat: support parsing certs with MLDSA public keys (#411)
1 parent 4edf52b commit abc63dd

File tree

10 files changed

+271
-1
lines changed

10 files changed

+271
-1
lines changed

ffi/src/key.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ impl From<KeyKind> for picky::key::KeyKind {
4646
KeyKind::Rsa => picky::key::KeyKind::Rsa,
4747
KeyKind::Ec => picky::key::KeyKind::Ec,
4848
KeyKind::Ed => picky::key::KeyKind::Ed,
49+
KeyKind::Mldsa => picky::key::KeyKind::Mldsa,
4950
}
5051
}
5152
}
@@ -56,6 +57,7 @@ impl From<picky::key::KeyKind> for KeyKind {
5657
picky::key::KeyKind::Rsa => KeyKind::Rsa,
5758
picky::key::KeyKind::Ec => KeyKind::Ec,
5859
picky::key::KeyKind::Ed => KeyKind::Ed,
60+
picky::key::KeyKind::Mldsa => KeyKind::Mldsa,
5961
}
6062
}
6163
}
@@ -94,6 +96,8 @@ pub mod ffi {
9496
Ec,
9597
/// Edwards-curve
9698
Ed,
99+
/// MLDSA (Module-Lattice-Based Digital Signature Algorithm)
100+
Mldsa,
97101
}
98102

99103
#[diplomat::opaque]

picky-asn1-x509/src/algorithm_identifier.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,27 @@ impl AlgorithmIdentifier {
297297
parameters: AlgorithmIdentifierParameters::None,
298298
}
299299
}
300+
301+
pub fn new_mldsa_44() -> Self {
302+
Self {
303+
algorithm: oids::id_mldsa_44().into(),
304+
parameters: AlgorithmIdentifierParameters::None,
305+
}
306+
}
307+
308+
pub fn new_mldsa_65() -> Self {
309+
Self {
310+
algorithm: oids::id_mldsa_65().into(),
311+
parameters: AlgorithmIdentifierParameters::None,
312+
}
313+
}
314+
315+
pub fn new_mldsa_87() -> Self {
316+
Self {
317+
algorithm: oids::id_mldsa_87().into(),
318+
parameters: AlgorithmIdentifierParameters::None,
319+
}
320+
}
300321
}
301322

302323
impl ser::Serialize for AlgorithmIdentifier {
@@ -379,7 +400,10 @@ impl<'de> de::Deserialize<'de> for AlgorithmIdentifier {
379400
| oids::ED25519
380401
| oids::ED448
381402
| oids::X25519
382-
| oids::X448 => AlgorithmIdentifierParameters::None,
403+
| oids::X448
404+
| oids::ID_MLDSA_44
405+
| oids::ID_MLDSA_65
406+
| oids::ID_MLDSA_87 => AlgorithmIdentifierParameters::None,
383407
oids::DSA_WITH_SHA1 => {
384408
// A note from [RFC 3927](https://www.ietf.org/rfc/rfc3279.txt)
385409
// When the id-dsa-with-sha1 algorithm identifier appears as the
@@ -1324,4 +1348,31 @@ mod tests {
13241348
pretty_assertions::assert_eq!(decoded, expected);
13251349
check_serde!(decoded: RawAlgorithmIdentifier in encoded);
13261350
}
1351+
1352+
#[test]
1353+
fn mldsa_44() {
1354+
let expected = [
1355+
0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x11,
1356+
];
1357+
let mldsa = AlgorithmIdentifier::new_mldsa_44();
1358+
check_serde!(mldsa: AlgorithmIdentifier in expected);
1359+
}
1360+
1361+
#[test]
1362+
fn mldsa_65() {
1363+
let expected = [
1364+
0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x12,
1365+
];
1366+
let mldsa = AlgorithmIdentifier::new_mldsa_65();
1367+
check_serde!(mldsa: AlgorithmIdentifier in expected);
1368+
}
1369+
1370+
#[test]
1371+
fn mldsa_87() {
1372+
let expected = [
1373+
0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x03, 0x13,
1374+
];
1375+
let mldsa = AlgorithmIdentifier::new_mldsa_87();
1376+
check_serde!(mldsa: AlgorithmIdentifier in expected);
1377+
}
13271378
}

picky-asn1-x509/src/oids.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ define_oid! {
6464
ID_RSASSA_PKCS1_V1_5_WITH_SHA3_256 => id_rsassa_pkcs1_v1_5_with_sha3_256 => "2.16.840.1.101.3.4.3.14",
6565
ID_RSASSA_PKCS1_V1_5_WITH_SHA3_384 => id_rsassa_pkcs1_v1_5_with_sha3_384 => "2.16.840.1.101.3.4.3.15",
6666
ID_RSASSA_PKCS1_V1_5_WITH_SHA3_512 => id_rsassa_pkcs1_v1_5_with_sha3_512 => "2.16.840.1.101.3.4.3.16",
67+
ID_MLDSA_44 => id_mldsa_44 => "2.16.840.1.101.3.4.3.17",
68+
ID_MLDSA_65 => id_mldsa_65 => "2.16.840.1.101.3.4.3.18",
69+
ID_MLDSA_87 => id_mldsa_87 => "2.16.840.1.101.3.4.3.19",
70+
6771

6872
// Certicom Object Identifiers
6973
SECP384R1 => secp384r1 => "1.3.132.0.34",

picky-asn1-x509/src/subject_public_key_info.rs

Lines changed: 185 additions & 0 deletions
Large diffs are not rendered by default.

picky/src/jose/jwe.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,11 @@ fn encode_impl(mut jwe: Jwe, mode: EncoderMode) -> Result<String, JweError> {
713713

714714
(encrypted_key_base64, jwe_cek)
715715
}
716+
RfcPublicKey::Mldsa(_) => {
717+
return Err(JweError::UnsupportedAlgorithm {
718+
algorithm: "mldsa".to_string(),
719+
});
720+
}
716721
},
717722
};
718723

@@ -1155,6 +1160,11 @@ fn generate_ecdh_shared_secret(
11551160
algorithm: format!("RSA key can't be used with `{:?}` algorithm", alg),
11561161
});
11571162
}
1163+
RfcPublicKey::Mldsa(_) => {
1164+
return Err(JweError::UnsupportedAlgorithm {
1165+
algorithm: format!("MLDSA key can't be used with `{:?}` algorithm", alg),
1166+
});
1167+
}
11581168
};
11591169

11601170
// Apply concact KDF to raw shared secret

picky/src/jose/jwk.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,9 @@ impl Jwk {
406406

407407
Ok(Self::new(JwkKeyType::new_ed_key(algorithm, ed_key.data())))
408408
}
409+
SerdePublicKey::Mldsa(_) => Err(JwkError::UnsupportedAlgorithm {
410+
algorithm: "JWK unsupported with MLDSA keys",
411+
}),
409412
}
410413
}
411414

picky/src/key/ec.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,9 @@ impl<'a> TryFrom<&'a PublicKey> for EcdsaPublicKey<'a> {
293293
InnerPublicKey::Ed(_) => Err(KeyError::EC {
294294
context: "EC public key cannot be constructed from ED25519 public key".to_string(),
295295
}),
296+
InnerPublicKey::Mldsa(_) => Err(KeyError::EC {
297+
context: "EC public key cannot be constructed from MLDSA public key".to_string(),
298+
}),
296299
}
297300
}
298301
}

picky/src/key/ed.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ impl<'a> TryFrom<&'a PublicKey> for EdPublicKey<'a> {
184184
algorithm: NamedEdAlgorithm::from(oid),
185185
})
186186
}
187+
InnerPublicKey::Mldsa(_) => Err(KeyError::ED {
188+
context: "Ed public key cannot be constructed from Mldsa public key".to_string(),
189+
}),
187190
}
188191
}
189192
}

picky/src/key/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ pub enum KeyKind {
105105
Rsa,
106106
Ec,
107107
Ed,
108+
Mldsa,
108109
}
109110

110111
// === private key === //
@@ -885,6 +886,7 @@ impl TryFrom<&'_ PublicKey> for RsaPublicKey {
885886
InnerPublicKey::Ed(_) => Err(KeyError::UnsupportedAlgorithm {
886887
algorithm: "edwards curves",
887888
}),
889+
InnerPublicKey::Mldsa(_) => Err(KeyError::UnsupportedAlgorithm { algorithm: "mldsa" }),
888890
}
889891
}
890892
}
@@ -1084,6 +1086,7 @@ impl PublicKey {
10841086
picky_asn1_x509::PublicKey::Rsa(_) => KeyKind::Rsa,
10851087
picky_asn1_x509::PublicKey::Ec(_) => KeyKind::Ec,
10861088
picky_asn1_x509::PublicKey::Ed(_) => KeyKind::Ed,
1089+
picky_asn1_x509::PublicKey::Mldsa(_) => KeyKind::Mldsa,
10871090
}
10881091
}
10891092

picky/src/x509/key_id_gen_method.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ impl KeyIdGenMethod {
5353
let der = bitstring.0.payload_view();
5454
Ok(hash_algo.digest(der)[..20].to_vec())
5555
}
56+
InnerPublicKey::Mldsa(bitstring) => {
57+
let der = bitstring.0.payload_view();
58+
Ok(hash_algo.digest(der)[..20].to_vec())
59+
}
5660
},
5761
KeyIdGenMethod::SPKFullDER(hash_algo) => {
5862
let der = public_key

0 commit comments

Comments
 (0)