Skip to content

fixes #11920 raise a clean Python error on DSA signing failure due to nilpotent #11921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/development/test-vectors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,10 @@ Custom asymmetric vectors
encrypted at the PEM level with AES-128-CBC and password "a123456".
* ``asymmetric/DER_Serialization/testrsa.der`` - The above as a DER-encoded
RSAPrivateKey structure.
* ``asymmetric/DSA/custom/nilpotent.pem`` -- A key where the field is actually
a ring and the generator of the multiplicative subgroup is actually
nilpotent with low degree. Taken from BoringSSL (see
``TEST(DSATest, NilpotentGenerator)``).


Key exchange
Expand Down
1 change: 1 addition & 0 deletions docs/spelling_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ namespace
namespaces
macOS
naïve
nilpotent
Nonces
nonces
online
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ __all__ = [
CRYPTOGRAPHY_IS_LIBRESSL: bool
CRYPTOGRAPHY_IS_BORINGSSL: bool
CRYPTOGRAPHY_OPENSSL_300_OR_GREATER: bool
CRYPTOGRAPHY_OPENSSL_309_OR_GREATER: bool
CRYPTOGRAPHY_OPENSSL_320_OR_GREATER: bool

class Providers: ...
Expand Down
2 changes: 1 addition & 1 deletion src/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ name = "cryptography_rust"
crate-type = ["cdylib"]

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)', 'cfg(CRYPTOGRAPHY_OPENSSL_320_OR_GREATER)', 'cfg(CRYPTOGRAPHY_IS_LIBRESSL)', 'cfg(CRYPTOGRAPHY_IS_BORINGSSL)', 'cfg(CRYPTOGRAPHY_OSSLCONF, values("OPENSSL_NO_IDEA", "OPENSSL_NO_CAST", "OPENSSL_NO_BF", "OPENSSL_NO_CAMELLIA", "OPENSSL_NO_SEED", "OPENSSL_NO_SM4"))'] }
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER)', 'cfg(CRYPTOGRAPHY_OPENSSL_309_OR_GREATER)', 'cfg(CRYPTOGRAPHY_OPENSSL_320_OR_GREATER)', 'cfg(CRYPTOGRAPHY_IS_LIBRESSL)', 'cfg(CRYPTOGRAPHY_IS_BORINGSSL)', 'cfg(CRYPTOGRAPHY_OSSLCONF, values("OPENSSL_NO_IDEA", "OPENSSL_NO_CAST", "OPENSSL_NO_BF", "OPENSSL_NO_CAMELLIA", "OPENSSL_NO_SEED", "OPENSSL_NO_SM4"))'] }
3 changes: 3 additions & 0 deletions src/rust/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ fn main() {
if version >= 0x3_00_00_00_0 {
println!("cargo:rustc-cfg=CRYPTOGRAPHY_OPENSSL_300_OR_GREATER");
}
if version >= 0x3_00_09_00_0 {
println!("cargo:rustc-cfg=CRYPTOGRAPHY_OPENSSL_309_OR_GREATER");
}
if version >= 0x3_02_00_00_0 {
println!("cargo:rustc-cfg=CRYPTOGRAPHY_OPENSSL_320_OR_GREATER");
}
Expand Down
10 changes: 8 additions & 2 deletions src/rust/src/backend/dsa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
use crate::backend::utils;
use crate::buf::CffiBuf;
use crate::error::{CryptographyError, CryptographyResult};
use crate::exceptions;
use crate::{error, exceptions};
use pyo3::types::PyAnyMethods;
use pyo3::ToPyObject;

#[pyo3::pyclass(
frozen,
Expand Down Expand Up @@ -76,7 +77,12 @@ impl DsaPrivateKey {
let mut signer = openssl::pkey_ctx::PkeyCtx::new(&self.pkey)?;
signer.sign_init()?;
let mut sig = vec![];
signer.sign_to_vec(data.as_bytes(), &mut sig)?;
signer.sign_to_vec(data.as_bytes(), &mut sig).map_err(|e| {
pyo3::exceptions::PyValueError::new_err((
"DSA signing failed. This generally indicates an invalid key.",
error::list_from_openssl_error(py, &e).to_object(py),
))
})?;
Ok(pyo3::types::PyBytes::new_bound(py, &sig))
}

Expand Down
4 changes: 4 additions & 0 deletions src/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ mod _rust {
"CRYPTOGRAPHY_OPENSSL_300_OR_GREATER",
cfg!(CRYPTOGRAPHY_OPENSSL_300_OR_GREATER),
)?;
openssl_mod.add(
"CRYPTOGRAPHY_OPENSSL_309_OR_GREATER",
cfg!(CRYPTOGRAPHY_OPENSSL_309_OR_GREATER),
)?;
openssl_mod.add(
"CRYPTOGRAPHY_OPENSSL_320_OR_GREATER",
cfg!(CRYPTOGRAPHY_OPENSSL_320_OR_GREATER),
Expand Down
25 changes: 25 additions & 0 deletions tests/hazmat/primitives/test_dsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from cryptography import utils
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import dsa
from cryptography.hazmat.primitives.asymmetric.utils import (
Expand Down Expand Up @@ -550,6 +551,30 @@ def test_prehashed_digest_mismatch(self, backend):
with pytest.raises(ValueError):
private_key.sign(digest, prehashed_alg)

@pytest.mark.supported(
only_if=lambda _: (
rust_openssl.CRYPTOGRAPHY_IS_LIBRESSL
or rust_openssl.CRYPTOGRAPHY_IS_BORINGSSL
or rust_openssl.CRYPTOGRAPHY_OPENSSL_309_OR_GREATER
),
skip_message="Requires OpenSSL 3.0.9+, LibreSSL, or BoringSSL",
)
def test_nilpotent(self):
try:
key = load_vectors_from_file(
os.path.join("asymmetric", "DSA", "custom", "nilpotent.pem"),
lambda pemfile: serialization.load_pem_private_key(
pemfile.read().encode(), password=None
),
)
except ValueError:
# LibreSSL simply rejects this key on load.
return
assert isinstance(key, dsa.DSAPrivateKey)

with pytest.raises(ValueError):
key.sign(b"anything", hashes.SHA256())


class TestDSANumbers:
def test_dsa_parameter_numbers(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN DSA PRIVATE KEY-----
MGECAQACFQHH+MnFXh4NNlZiV/zUVb5a5ib3kwIVAOP8ZOKvDwabKzEr/moq3y1z
E3vJAhUAl/2Ylx9fWbzHdh1URsc/c6IM/TECAQECFCsjU4AZRcuks45g1NMOUeCB
Epvg
-----END DSA PRIVATE KEY-----