Skip to content

Commit 4f4bc0b

Browse files
committed
Improve coverage
1 parent 176e34b commit 4f4bc0b

File tree

8 files changed

+91
-9
lines changed

8 files changed

+91
-9
lines changed

src/rust/cryptography-key-parsing/src/spki.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,15 @@ mod tests {
269269
// Expected to panic
270270
_ = serialize_public_key(&pkey);
271271
}
272+
273+
#[cfg(CRYPTOGRAPHY_IS_AWSLC)]
274+
#[test]
275+
#[should_panic(expected = "Unsupported ML-DSA variant")]
276+
fn test_serialize_public_key_unsupported_mldsa_variant() {
277+
// Load an ML-DSA-44 public key from a Wycheproof test vector DER.
278+
let der = include_bytes!("../../test_data/mldsa44_pub.der");
279+
let pub_pkey = openssl::pkey::PKey::public_key_from_der(der).unwrap();
280+
// Expected to panic with "Unsupported ML-DSA variant"
281+
_ = serialize_public_key(&pub_pkey);
282+
}
272283
}

src/rust/cryptography-openssl/src/mldsa.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,3 +160,20 @@ pub fn verify(
160160

161161
Ok(r == 1)
162162
}
163+
164+
#[cfg(test)]
165+
mod tests {
166+
use super::*;
167+
168+
#[test]
169+
fn test_sign_with_context_too_long_returns_error() {
170+
// ML-DSA context strings are limited to 255 bytes.
171+
// Passing a 256-byte context to ml_dsa_65_sign triggers
172+
// an FFI error return.
173+
let seed = generate_seed().unwrap();
174+
let pkey = new_raw_private_key(&seed).unwrap();
175+
let long_ctx = [0x41u8; 256];
176+
let result = sign(&pkey, b"test", &long_ctx);
177+
assert!(result.is_err());
178+
}
179+
}

src/rust/src/backend/keys.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,4 +372,38 @@ mod tests {
372372
assert!(private_key_from_pkey(py, &pkey, false).is_err());
373373
});
374374
}
375+
376+
#[test]
377+
#[cfg(CRYPTOGRAPHY_IS_AWSLC)]
378+
fn test_private_key_from_pkey_unsupported_mldsa_variant() {
379+
use super::private_key_from_pkey;
380+
381+
pyo3::Python::initialize();
382+
383+
pyo3::Python::attach(|py| {
384+
// Load an ML-DSA-44 private key from a Wycheproof PKCS8 DER.
385+
// ML-DSA-44 is a PQDSA key that we don't support; its public key
386+
// length differs from ML-DSA-65, hitting the "Unsupported ML-DSA
387+
// variant" error branch.
388+
let der = include_bytes!("../../test_data/mldsa44_priv.der");
389+
let pkey = openssl::pkey::PKey::private_key_from_der(der).unwrap();
390+
assert!(private_key_from_pkey(py, &pkey, false).is_err());
391+
});
392+
}
393+
394+
#[test]
395+
#[cfg(CRYPTOGRAPHY_IS_AWSLC)]
396+
fn test_public_key_from_pkey_unsupported_mldsa_variant() {
397+
use super::public_key_from_pkey;
398+
399+
pyo3::Python::initialize();
400+
401+
pyo3::Python::attach(|py| {
402+
// Load an ML-DSA-44 public key from a Wycheproof SPKI DER.
403+
let der = include_bytes!("../../test_data/mldsa44_pub.der");
404+
let pub_pkey = openssl::pkey::PKey::public_key_from_der(der).unwrap();
405+
let id = pub_pkey.id();
406+
assert!(public_key_from_pkey(py, &pub_pkey, id).is_err());
407+
});
408+
}
375409
}

src/rust/src/backend/mldsa65.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ fn from_public_bytes(data: &[u8]) -> pyo3::PyResult<MlDsa65PublicKey> {
5858
Ok(MlDsa65PublicKey { pkey })
5959
}
6060

61+
// NO-COVERAGE-START
6162
#[pyo3::pymethods]
63+
// NO-COVERAGE-END
6264
impl MlDsa65PrivateKey {
6365
fn sign<'p>(
6466
&self,
@@ -104,11 +106,7 @@ impl MlDsa65PrivateKey {
104106
let pkcs8_der = self.pkey.private_key_to_pkcs8()?;
105107
let pki =
106108
asn1::parse_single::<cryptography_key_parsing::pkcs8::PrivateKeyInfo<'_>>(&pkcs8_der)
107-
.map_err(|_| {
108-
pyo3::exceptions::PyValueError::new_err(
109-
"Cannot extract seed from this ML-DSA-65 private key",
110-
)
111-
})?;
109+
.unwrap();
112110
// The privateKey content is [0x80, 0x20, <32 bytes of seed>]
113111
// (context-specific tag 0, length 32)
114112
if pki.private_key.len() == 2 + cryptography_openssl::mldsa::MLDSA65_SEED_BYTES
@@ -117,11 +115,16 @@ impl MlDsa65PrivateKey {
117115
{
118116
Ok(pyo3::types::PyBytes::new(py, &pki.private_key[2..]))
119117
} else {
118+
// NO-COVERAGE-START
119+
// All supported ML-DSA variants use 32-byte seeds with the
120+
// [0x80, 0x20, <seed>] encoding. This branch is purely
121+
// defensive against future format changes.
120122
Err(CryptographyError::from(
121123
pyo3::exceptions::PyValueError::new_err(
122124
"Cannot extract seed from this ML-DSA-65 private key",
123125
),
124126
))
127+
// NO-COVERAGE-END
125128
}
126129
}
127130

@@ -165,7 +168,9 @@ impl MlDsa65PrivateKey {
165168
}
166169
}
167170

171+
// NO-COVERAGE-START
168172
#[pyo3::pymethods]
173+
// NO-COVERAGE-END
169174
impl MlDsa65PublicKey {
170175
fn verify(&self, signature: CffiBuf<'_>, data: CffiBuf<'_>) -> CryptographyResult<()> {
171176
let valid = cryptography_openssl::mldsa::verify(
54 Bytes
Binary file not shown.

src/rust/test_data/mldsa44_pub.der

1.3 KB
Binary file not shown.

tests/hazmat/primitives/test_mldsa65.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ def test_sign_verify(self, backend):
5555
sig = key.sign(b"test data")
5656
key.public_key().verify(sig, b"test data")
5757

58+
def test_sign_verify_empty_message(self, backend):
59+
key = MlDsa65PrivateKey.generate()
60+
sig = key.sign(b"")
61+
key.public_key().verify(sig, b"")
62+
5863
@pytest.mark.parametrize(
5964
"ctx",
6065
[
@@ -101,6 +106,18 @@ def test_kat_vectors(self, backend, subtests):
101106
else:
102107
pub.verify(expected_sig, msg)
103108

109+
def test_kat_verify_no_context(self, backend):
110+
vectors = load_vectors_from_file(
111+
os.path.join("asymmetric", "MLDSA", "kat_MLDSA_65_det_pure.rsp"),
112+
load_nist_vectors,
113+
)
114+
vector = vectors[0]
115+
xi = binascii.unhexlify(vector["xi"])
116+
key = MlDsa65PrivateKey.from_seed_bytes(xi)
117+
pub = key.public_key()
118+
sig = key.sign(b"test")
119+
pub.verify(sig, b"test")
120+
104121
def test_private_bytes_raw_round_trip(self, backend):
105122
key = MlDsa65PrivateKey.generate()
106123
seed = key.private_bytes_raw()

tests/wycheproof/test_mldsa.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,5 @@ def test_mldsa65_sign_seed(backend, wycheproof):
9898
pub.verify(sig, msg)
9999
else:
100100
with pytest.raises(ValueError):
101-
if has_ctx:
102-
key.sign_with_context(msg, ctx)
103-
else:
104-
key.sign(msg)
101+
assert has_ctx
102+
key.sign_with_context(msg, ctx)

0 commit comments

Comments
 (0)