diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0fe786454e4..53958898d142 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,6 +31,7 @@ jobs: - {VERSION: "3.11", NOXSESSION: "docs", OPENSSL: {TYPE: "openssl", VERSION: "3.1.1"}} - {VERSION: "pypy-3.8", NOXSESSION: "tests-nocoverage"} - {VERSION: "pypy-3.9", NOXSESSION: "tests-nocoverage"} + - {VERSION: "pypy-3.10", NOXSESSION: "tests-nocoverage"} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "1.1.1u"}} - {VERSION: "3.11", NOXSESSION: "tests", OPENSSL: {TYPE: "openssl", VERSION: "3.0.9"}} - {VERSION: "3.11", NOXSESSION: "tests-ssh", OPENSSL: {TYPE: "openssl", VERSION: "3.1.1"}} diff --git a/.github/workflows/wheel-builder.yml b/.github/workflows/wheel-builder.yml index 677319b3fa5a..b03df812b8d7 100644 --- a/.github/workflows/wheel-builder.yml +++ b/.github/workflows/wheel-builder.yml @@ -60,6 +60,7 @@ jobs: - { VERSION: "cp37-cp37m", ABI_VERSION: 'cp37' } - { VERSION: "pp38-pypy38_pp73" } - { VERSION: "pp39-pypy39_pp73" } + - { VERSION: "pp310-pypy310_pp73" } MANYLINUX: - { NAME: "manylinux2014_x86_64", CONTAINER: "cryptography-manylinux2014:x86_64", RUNNER: "ubuntu-latest" } - { NAME: "manylinux_2_28_x86_64", CONTAINER: "cryptography-manylinux_2_28:x86_64", RUNNER: "ubuntu-latest"} @@ -74,19 +75,27 @@ jobs: MANYLINUX: { NAME: "musllinux_1_1_x86_64", CONTAINER: "cryptography-musllinux_1_1:x86_64", RUNNER: "ubuntu-latest"} - PYTHON: { VERSION: "pp39-pypy39_pp73" } MANYLINUX: { NAME: "musllinux_1_1_x86_64", CONTAINER: "cryptography-musllinux_1_1:x86_64", RUNNER: "ubuntu-latest"} + - PYTHON: { VERSION: "pp310-pypy310_pp73" } + MANYLINUX: { NAME: "musllinux_1_1_x86_64", CONTAINER: "cryptography-musllinux_1_1:x86_64", RUNNER: "ubuntu-latest"} - PYTHON: { VERSION: "pp38-pypy38_pp73" } MANYLINUX: { NAME: "musllinux_1_1_aarch64", CONTAINER: "cryptography-musllinux_1_1:aarch64", RUNNER: [self-hosted, Linux, ARM64]} - PYTHON: { VERSION: "pp39-pypy39_pp73" } MANYLINUX: { NAME: "musllinux_1_1_aarch64", CONTAINER: "cryptography-musllinux_1_1:aarch64", RUNNER: [self-hosted, Linux, ARM64]} + - PYTHON: { VERSION: "pp310-pypy310_pp73" } + MANYLINUX: { NAME: "musllinux_1_1_aarch64", CONTAINER: "cryptography-musllinux_1_1:aarch64", RUNNER: [self-hosted, Linux, ARM64]} # We also don't build pypy wheels for anything except the latest manylinux - PYTHON: { VERSION: "pp38-pypy38_pp73" } MANYLINUX: { NAME: "manylinux2014_x86_64", CONTAINER: "cryptography-manylinux2014:x86_64", RUNNER: "ubuntu-latest"} - PYTHON: { VERSION: "pp39-pypy39_pp73" } MANYLINUX: { NAME: "manylinux2014_x86_64", CONTAINER: "cryptography-manylinux2014:x86_64", RUNNER: "ubuntu-latest"} + - PYTHON: { VERSION: "pp310-pypy310_pp73" } + MANYLINUX: { NAME: "manylinux2014_x86_64", CONTAINER: "cryptography-manylinux2014:x86_64", RUNNER: "ubuntu-latest"} - PYTHON: { VERSION: "pp38-pypy38_pp73" } MANYLINUX: { NAME: "manylinux2014_aarch64", CONTAINER: "cryptography-manylinux2014_aarch64", RUNNER: [self-hosted, Linux, ARM64]} - PYTHON: { VERSION: "pp39-pypy39_pp73" } MANYLINUX: { NAME: "manylinux2014_aarch64", CONTAINER: "cryptography-manylinux2014_aarch64", RUNNER: [self-hosted, Linux, ARM64]} + - PYTHON: { VERSION: "pp310-pypy310_pp73" } + MANYLINUX: { NAME: "manylinux2014_aarch64", CONTAINER: "cryptography-manylinux2014_aarch64", RUNNER: [self-hosted, Linux, ARM64]} name: "${{ matrix.PYTHON.VERSION }} for ${{ matrix.MANYLINUX.NAME }}" steps: - name: Ridiculous alpine workaround for actions support on arm64 @@ -175,6 +184,11 @@ jobs: DEPLOYMENT_TARGET: '10.12' _PYTHON_HOST_PLATFORM: 'macosx-10.9-x86_64' ARCHFLAGS: '-arch x86_64' + - VERSION: 'pypy-3.10' + BIN_PATH: 'pypy3' + DEPLOYMENT_TARGET: '10.12' + _PYTHON_HOST_PLATFORM: 'macosx-10.9-x86_64' + ARCHFLAGS: '-arch x86_64' name: "${{ matrix.PYTHON.VERSION }} ABI ${{ matrix.PYTHON.ABI_VERSION }} macOS ${{ matrix.PYTHON.ARCHFLAGS }}" steps: - uses: actions/download-artifact@v3.0.2 @@ -253,12 +267,15 @@ jobs: - {VERSION: "3.11", "ABI_VERSION": "cp37"} - {VERSION: "pypy-3.8"} - {VERSION: "pypy-3.9"} + - {VERSION: "pypy-3.10"} exclude: # We need to exclude the below configuration because there is no 32-bit pypy3 - WINDOWS: {ARCH: 'x86', WINDOWS: 'win32', RUST_TRIPLE: 'i686-pc-windows-msvc'} PYTHON: {VERSION: "pypy-3.8"} - WINDOWS: {ARCH: 'x86', WINDOWS: 'win32', RUST_TRIPLE: 'i686-pc-windows-msvc'} PYTHON: {VERSION: "pypy-3.9"} + - WINDOWS: {ARCH: 'x86', WINDOWS: 'win32', RUST_TRIPLE: 'i686-pc-windows-msvc'} + PYTHON: {VERSION: "pypy-3.10"} name: "${{ matrix.PYTHON.VERSION }} ${{ matrix.WINDOWS.WINDOWS }} ${{ matrix.PYTHON.ABI_VERSION }}" steps: - uses: actions/download-artifact@v3.0.2 diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 95e2ab25c0d9..0f0450b19b72 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,26 @@ Changelog ========= +.. _v41-0-2: + +41.0.2 - 2023-07-10 +~~~~~~~~~~~~~~~~~~~ + +* Fixed bugs in creating and parsing SSH certificates where critical options + with values were handled incorrectly. Certificates are now created correctly + and parsing accepts correct values as well as the previously generated + invalid forms with a warning. In the next release, support for parsing these + invalid forms will be removed. + +.. _v41-0-1: + +41.0.1 - 2023-06-01 +~~~~~~~~~~~~~~~~~~~ + +* Temporarily allow invalid ECDSA signature algorithm parameters in X.509 + certificates, which are generated by older versions of Java. +* Allow null bytes in pass phrases when serializing private keys. + .. _v41-0-0: 41.0.0 - 2023-05-30 diff --git a/docs/development/test-vectors.rst b/docs/development/test-vectors.rst index 56bc9361c555..cfab7edcca69 100644 --- a/docs/development/test-vectors.rst +++ b/docs/development/test-vectors.rst @@ -499,6 +499,8 @@ Custom X.509 Vectors * ``rsa_pss_sha256_no_null.pem`` - A certificate with an RSA PSS signature with no encoded ``NULL`` for the PSS hash algorithm parameters. This certificate was generated by LibreSSL. +* ``ecdsa_null_alg.pem`` - A certificate with an ECDSA signature with ``NULL`` + algorithm parameters. This encoding is invalid, but was generated by Java 11. Custom X.509 Request Vectors ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -864,6 +866,10 @@ Custom OpenSSH Certificate Test Vectors critical option. * ``p256-p256-non-lexical-crit-opts.pub`` - A certificate with critical options in non-lexical order. +* ``p256-ed25519-non-singular-crit-opt-val.pub`` - A certificate with + a critical option that contains more than one value. +* ``p256-ed25519-non-singular-ext-val.pub`` - A certificate with + an extension that contains more than one value. * ``dsa-p256.pub`` - A certificate with a DSA public key signed by a P256 CA. * ``p256-dsa.pub`` - A certificate with a P256 public key signed by a DSA diff --git a/pyproject.toml b/pyproject.toml index c9de27381328..001f60598661 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ build-backend = "setuptools.build_meta" [project] name = "cryptography" -version = "41.0.0" +version = "41.0.2" authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ] diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index b66e23c606ba..73b3b56ccd63 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -10,7 +10,7 @@ "__copyright__", ] -__version__ = "41.0.0" +__version__ = "41.0.2" __author__ = "The Python Cryptographic Authority and individual contributors" diff --git a/src/cryptography/hazmat/primitives/serialization/ssh.py b/src/cryptography/hazmat/primitives/serialization/ssh.py index 7725c83543e8..35e53c102875 100644 --- a/src/cryptography/hazmat/primitives/serialization/ssh.py +++ b/src/cryptography/hazmat/primitives/serialization/ssh.py @@ -1063,6 +1063,20 @@ def _parse_exts_opts(exts_opts: memoryview) -> typing.Dict[bytes, bytes]: if last_name is not None and bname < last_name: raise ValueError("Fields not lexically sorted") value, exts_opts = _get_sshstr(exts_opts) + if len(value) > 0: + try: + value, extra = _get_sshstr(value) + except ValueError: + warnings.warn( + "This certificate has an incorrect encoding for critical " + "options or extensions. This will be an exception in " + "cryptography 42", + utils.DeprecatedIn41, + stacklevel=4, + ) + else: + if len(extra) > 0: + raise ValueError("Unexpected extra data after value") result[bname] = bytes(value) last_name = bname return result @@ -1450,12 +1464,22 @@ def sign(self, private_key: SSHCertPrivateKeyTypes) -> SSHCertificate: fcrit = _FragList() for name, value in self._critical_options: fcrit.put_sshstr(name) - fcrit.put_sshstr(value) + if len(value) > 0: + foptval = _FragList() + foptval.put_sshstr(value) + fcrit.put_sshstr(foptval.tobytes()) + else: + fcrit.put_sshstr(value) f.put_sshstr(fcrit.tobytes()) fext = _FragList() for name, value in self._extensions: fext.put_sshstr(name) - fext.put_sshstr(value) + if len(value) > 0: + fextval = _FragList() + fextval.put_sshstr(value) + fext.put_sshstr(fextval.tobytes()) + else: + fext.put_sshstr(value) f.put_sshstr(fext.tobytes()) f.put_sshstr(b"") # RESERVED FIELD # encode CA public key diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 47d972ff46ff..5dcbe68034c8 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -162,9 +162,9 @@ checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "openssl" -version = "0.10.53" +version = "0.10.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12df40a956736488b7b44fe79fe12d4f245bb5b3f5a1f6095e499760015be392" +checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019" dependencies = [ "bitflags", "cfg-if", @@ -285,9 +285,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.59" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" dependencies = [ "unicode-ident", ] diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index 2ca1d79d6802..01fba147e759 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -16,7 +16,7 @@ cryptography-x509 = { path = "cryptography-x509" } cryptography-openssl = { path = "cryptography-openssl" } pem = "1.1" ouroboros = "0.15" -openssl = "0.10.53" +openssl = "0.10.54" openssl-sys = "0.9.88" foreign-types-shared = "0.1" diff --git a/src/rust/cryptography-openssl/Cargo.toml b/src/rust/cryptography-openssl/Cargo.toml index 587a85909565..c85f406ae616 100644 --- a/src/rust/cryptography-openssl/Cargo.toml +++ b/src/rust/cryptography-openssl/Cargo.toml @@ -8,7 +8,7 @@ publish = false rust-version = "1.56.0" [dependencies] -openssl = "0.10.53" +openssl = "0.10.54" ffi = { package = "openssl-sys", version = "0.9.85" } foreign-types = "0.3" foreign-types-shared = "0.1" diff --git a/src/rust/cryptography-x509/src/common.rs b/src/rust/cryptography-x509/src/common.rs index 466d4b5bd179..a882d985e9cb 100644 --- a/src/rust/cryptography-x509/src/common.rs +++ b/src/rust/cryptography-x509/src/common.rs @@ -45,14 +45,18 @@ pub enum AlgorithmParameters<'a> { #[defined_by(oid::ED448_OID)] Ed448, + // These ECDSA algorithms should have no parameters, + // but Java 11 (up to at least 11.0.19) encodes them + // with NULL parameters. The JDK team is looking to + // backport the fix as of June 2023. #[defined_by(oid::ECDSA_WITH_SHA224_OID)] - EcDsaWithSha224, + EcDsaWithSha224(Option), #[defined_by(oid::ECDSA_WITH_SHA256_OID)] - EcDsaWithSha256, + EcDsaWithSha256(Option), #[defined_by(oid::ECDSA_WITH_SHA384_OID)] - EcDsaWithSha384, + EcDsaWithSha384(Option), #[defined_by(oid::ECDSA_WITH_SHA512_OID)] - EcDsaWithSha512, + EcDsaWithSha512(Option), #[defined_by(oid::ECDSA_WITH_SHA3_224_OID)] EcDsaWithSha3_224, diff --git a/src/rust/src/x509/certificate.rs b/src/rust/src/x509/certificate.rs index 3446bbbbb604..9204d730ba03 100644 --- a/src/rust/src/x509/certificate.rs +++ b/src/rust/src/x509/certificate.rs @@ -8,7 +8,7 @@ use crate::asn1::{ use crate::error::{CryptographyError, CryptographyResult}; use crate::x509::{extensions, sct, sign}; use crate::{exceptions, x509}; -use cryptography_x509::common::Asn1ReadableOrWritable; +use cryptography_x509::common::{AlgorithmParameters, Asn1ReadableOrWritable}; use cryptography_x509::extensions::Extension; use cryptography_x509::extensions::{ AuthorityKeyIdentifier, BasicConstraints, DisplayText, DistributionPoint, @@ -391,6 +391,10 @@ fn load_der_x509_certificate( // determine if the serial is negative and raise a warning if it is. We want to drop support // for this sort of invalid encoding eventually. warn_if_negative_serial(py, raw.borrow_value().tbs_cert.serial.as_bytes())?; + // determine if the signature algorithm has incorrect parameters and raise a warning if it + // does. this is a bug in JDK11 and we want to drop support for it eventually. + warn_if_invalid_ecdsa_params(py, raw.borrow_value().signature_alg.params.clone())?; + warn_if_invalid_ecdsa_params(py, raw.borrow_value().tbs_cert.signature_alg.params.clone())?; Ok(Certificate { raw, @@ -413,6 +417,30 @@ fn warn_if_negative_serial(py: pyo3::Python<'_>, bytes: &'_ [u8]) -> pyo3::PyRes Ok(()) } +fn warn_if_invalid_ecdsa_params( + py: pyo3::Python<'_>, + params: AlgorithmParameters<'_>, +) -> pyo3::PyResult<()> { + match params { + AlgorithmParameters::EcDsaWithSha224(Some(..)) + | AlgorithmParameters::EcDsaWithSha256(Some(..)) + | AlgorithmParameters::EcDsaWithSha384(Some(..)) + | AlgorithmParameters::EcDsaWithSha512(Some(..)) => { + let cryptography_warning = py + .import(pyo3::intern!(py, "cryptography.utils"))? + .getattr(pyo3::intern!(py, "DeprecatedIn41"))?; + pyo3::PyErr::warn( + py, + cryptography_warning, + "The parsed certificate contains a NULL parameter value in its signature algorithm parameters. This is invalid and will be rejected in a future version of cryptography. If this certificate was created via Java, please upgrade to JDK16+ or the latest JDK11 once a fix is issued. If this certificate was created in some other fashion please report the issue to the cryptography issue tracker. See https://github.com/pyca/cryptography/issues/8996 for more details.", + 2, + )?; + } + _ => {} + } + Ok(()) +} + fn parse_display_text( py: pyo3::Python<'_>, text: DisplayText<'_>, diff --git a/src/rust/src/x509/sign.rs b/src/rust/src/x509/sign.rs index b3a799b8cb01..4b03a2d9ab8e 100644 --- a/src/rust/src/x509/sign.rs +++ b/src/rust/src/x509/sign.rs @@ -234,19 +234,19 @@ pub(crate) fn compute_signature_algorithm<'p>( (KeyType::Ec, HashType::Sha224) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::EcDsaWithSha224, + params: common::AlgorithmParameters::EcDsaWithSha224(None), }), (KeyType::Ec, HashType::Sha256) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::EcDsaWithSha256, + params: common::AlgorithmParameters::EcDsaWithSha256(None), }), (KeyType::Ec, HashType::Sha384) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::EcDsaWithSha384, + params: common::AlgorithmParameters::EcDsaWithSha384(None), }), (KeyType::Ec, HashType::Sha512) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), - params: common::AlgorithmParameters::EcDsaWithSha512, + params: common::AlgorithmParameters::EcDsaWithSha512(None), }), (KeyType::Ec, HashType::Sha3_224) => Ok(common::AlgorithmIdentifier { oid: asn1::DefinedByMarker::marker(), @@ -483,10 +483,10 @@ fn identify_key_type_for_algorithm_params( | common::AlgorithmParameters::RsaWithSha3_384(..) | common::AlgorithmParameters::RsaWithSha3_512(..) | common::AlgorithmParameters::RsaPss(..) => Ok(KeyType::Rsa), - common::AlgorithmParameters::EcDsaWithSha224 - | common::AlgorithmParameters::EcDsaWithSha256 - | common::AlgorithmParameters::EcDsaWithSha384 - | common::AlgorithmParameters::EcDsaWithSha512 + common::AlgorithmParameters::EcDsaWithSha224(..) + | common::AlgorithmParameters::EcDsaWithSha256(..) + | common::AlgorithmParameters::EcDsaWithSha384(..) + | common::AlgorithmParameters::EcDsaWithSha512(..) | common::AlgorithmParameters::EcDsaWithSha3_224 | common::AlgorithmParameters::EcDsaWithSha3_256 | common::AlgorithmParameters::EcDsaWithSha3_384 @@ -616,10 +616,10 @@ pub(crate) fn identify_signature_algorithm_parameters<'p>( .call0()?; Ok(pkcs) } - common::AlgorithmParameters::EcDsaWithSha224 - | common::AlgorithmParameters::EcDsaWithSha256 - | common::AlgorithmParameters::EcDsaWithSha384 - | common::AlgorithmParameters::EcDsaWithSha512 + common::AlgorithmParameters::EcDsaWithSha224(_) + | common::AlgorithmParameters::EcDsaWithSha256(_) + | common::AlgorithmParameters::EcDsaWithSha384(_) + | common::AlgorithmParameters::EcDsaWithSha512(_) | common::AlgorithmParameters::EcDsaWithSha3_224 | common::AlgorithmParameters::EcDsaWithSha3_256 | common::AlgorithmParameters::EcDsaWithSha3_384 @@ -682,10 +682,22 @@ mod tests { &common::AlgorithmParameters::RsaWithSha3_512(Some(())), KeyType::Rsa, ), - (&common::AlgorithmParameters::EcDsaWithSha224, KeyType::Ec), - (&common::AlgorithmParameters::EcDsaWithSha256, KeyType::Ec), - (&common::AlgorithmParameters::EcDsaWithSha384, KeyType::Ec), - (&common::AlgorithmParameters::EcDsaWithSha512, KeyType::Ec), + ( + &common::AlgorithmParameters::EcDsaWithSha224(None), + KeyType::Ec, + ), + ( + &common::AlgorithmParameters::EcDsaWithSha256(None), + KeyType::Ec, + ), + ( + &common::AlgorithmParameters::EcDsaWithSha384(None), + KeyType::Ec, + ), + ( + &common::AlgorithmParameters::EcDsaWithSha512(None), + KeyType::Ec, + ), (&common::AlgorithmParameters::EcDsaWithSha3_224, KeyType::Ec), (&common::AlgorithmParameters::EcDsaWithSha3_256, KeyType::Ec), (&common::AlgorithmParameters::EcDsaWithSha3_384, KeyType::Ec), diff --git a/tests/hazmat/primitives/test_ed25519.py b/tests/hazmat/primitives/test_ed25519.py index 4b47e0a1657f..2501f1cf1bb1 100644 --- a/tests/hazmat/primitives/test_ed25519.py +++ b/tests/hazmat/primitives/test_ed25519.py @@ -245,6 +245,13 @@ def test_invalid_public_bytes(self, backend): None, serialization.load_der_private_key, ), + ( + serialization.Encoding.DER, + serialization.PrivateFormat.PKCS8, + serialization.BestAvailableEncryption(b"\x00"), + b"\x00", + serialization.load_der_private_key, + ), ], ) def test_round_trip_private_serialization( diff --git a/tests/hazmat/primitives/test_ssh.py b/tests/hazmat/primitives/test_ssh.py index e5c58062d075..fcd0928a87de 100644 --- a/tests/hazmat/primitives/test_ssh.py +++ b/tests/hazmat/primitives/test_ssh.py @@ -1115,26 +1115,28 @@ def test_loads_ssh_cert(self, backend): # secp256r1 public key, ed25519 signing key cert = load_ssh_public_identity( b"ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbm" - b"lzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgtdU+dl9vD4xPi8afxERYo" - b"s0c0d9/3m7XGY6fGeSkqn0AAAAIbmlzdHAyNTYAAABBBAsuVFNNj/mMyFm2xB99" - b"G4xiaUJE1lZNjcp+S2tXYW5KorcHpusSlSqOkUPZ2l0644dgiNPDKR/R+BtYENC" - b"8aq8AAAAAAAAAAAAAAAEAAAAUdGVzdEBjcnlwdG9ncmFwaHkuaW8AAAAaAAAACm" - b"NyeXB0b3VzZXIAAAAIdGVzdHVzZXIAAAAAY7KyZAAAAAB2frXAAAAAAAAAAIIAA" - b"AAVcGVybWl0LVgxMS1mb3J3YXJkaW5nAAAAAAAAABdwZXJtaXQtYWdlbnQtZm9y" - b"d2FyZGluZwAAAAAAAAAWcGVybWl0LXBvcnQtZm9yd2FyZGluZwAAAAAAAAAKcGV" - b"ybWl0LXB0eQAAAAAAAAAOcGVybWl0LXVzZXItcmMAAAAAAAAAAAAAADMAAAALc3" - b"NoLWVkMjU1MTkAAAAg3P0eyGf2crKGwSlnChbLzTVOFKwQELE1Ve+EZ6rXF18AA" - b"ABTAAAAC3NzaC1lZDI1NTE5AAAAQKoij8BsPj/XLb45+wHmRWKNqXeZYXyDIj8J" - b"IE6dIymjEqq0TP6ntu5t59hTmWlDO85GnMXAVGBjFbeikBMfAQc= reaperhulk" - b"@despoina.local" + b"lzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgLfsFv9Gbc6LZSiJFWdYQl" + b"IMNI50GExXW0fBpgGVf+Y4AAAAIbmlzdHAyNTYAAABBBIzVyRgVLR4F38bIOLBN" + b"8CNm8Nf+eBHCVkKDKb9WDyLLD61CEmzjK/ORwFuSE4N60eIGbFidBf0D0xh7G6o" + b"TNxsAAAAAAAAAAAAAAAEAAAAUdGVzdEBjcnlwdG9ncmFwaHkuaW8AAAAaAAAACm" + b"NyeXB0b3VzZXIAAAAIdGVzdHVzZXIAAAAAY7KyZAAAAAB2frXAAAAAWAAAAA1mb" + b"3JjZS1jb21tYW5kAAAALAAAAChlY2hvIGFhYWFhYWFhYWFhYWFhYWFhYWFhYWFh" + b"YWFhYWFhYWFhYWFhAAAAD3ZlcmlmeS1yZXF1aXJlZAAAAAAAAACCAAAAFXBlcm1" + b"pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybWl0LWFnZW50LWZvcndhcmRpbm" + b"cAAAAAAAAAFnBlcm1pdC1wb3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wd" + b"HkAAAAAAAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAAAzAAAAC3NzaC1lZDI1" + b"NTE5AAAAICH6csEOmGbOfT2B/S/FJg3uyPsaPSZUZk2SVYlfs0KLAAAAUwAAAAt" + b"zc2gtZWQyNTUxOQAAAEDz2u7X5/TFbN7Ms7DP4yArhz1oWWYKkdAk7FGFkHfjtY" + b"/YfNQ8Oky3dCZRi7PnSzScEEjos7723dhF8/y99WwH reaperhulk@despoina." + b"local" ) assert isinstance(cert, SSHCertificate) cert.verify_cert_signature() signature_key = cert.signature_key() assert isinstance(signature_key, ed25519.Ed25519PublicKey) assert cert.nonce == ( - b"\xb5\xd5>v_o\x0f\x8cO\x8b\xc6\x9f\xc4DX\xa2\xcd\x1c\xd1\xdf" - b"\x7f\xden\xd7\x19\x8e\x9f\x19\xe4\xa4\xaa}" + b'-\xfb\x05\xbf\xd1\x9bs\xa2\xd9J"EY\xd6\x10\x94\x83\r#\x9d' + b"\x06\x13\x15\xd6\xd1\xf0i\x80e_\xf9\x8e" ) public_key = cert.public_key() assert isinstance(public_key, ec.EllipticCurvePublicKey) @@ -1145,7 +1147,10 @@ def test_loads_ssh_cert(self, backend): assert cert.valid_principals == [b"cryptouser", b"testuser"] assert cert.valid_before == 1988015552 assert cert.valid_after == 1672655460 - assert cert.critical_options == {} + assert cert.critical_options == { + b"force-command": b"echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + b"verify-required": b"", + } assert cert.extensions == { b"permit-X11-forwarding": b"", b"permit-agent-forwarding": b"", @@ -1154,6 +1159,31 @@ def test_loads_ssh_cert(self, backend): b"permit-user-rc": b"", } + def test_loads_deprecated_invalid_encoding_cert(self, backend): + with pytest.warns(utils.DeprecatedIn41): + cert = load_ssh_public_identity( + b"ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYT" + b"ItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgXE7sJ+xDVVNCO" + b"cEvpZS+SXIbc0nJdny/KqVbnwHslMIAAAAIbmlzdHAyNTYAAABBBI/qcLq8" + b"iiErpAhOWRqdMkpFSCNv7TVUcXCIfAl01JXbe2MvS4V7lFtiyrBjLSV7Iyw" + b"3TrulrWLibjPzZvLwmQcAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAA//" + b"////////8AAABUAAAADWZvcmNlLWNvbW1hbmQAAAAoZWNobyBhYWFhYWFhY" + b"WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYQAAAA92ZXJpZnktcmVxdWly" + b"ZWQAAAAAAAAAEgAAAApwZXJtaXQtcHR5AAAAAAAAAAAAAABoAAAAE2VjZHN" + b"hLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI/qcLq8iiErpAhOWR" + b"qdMkpFSCNv7TVUcXCIfAl01JXbe2MvS4V7lFtiyrBjLSV7Iyw3TrulrWLib" + b"jPzZvLwmQcAAABlAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAABKAAAAIQCi" + b"eCsIhGKrZdkE1+zY5EBucrLzxFpwnm/onIT/6rapvQAAACEAuVQ1yQjlPKr" + b"kfsGfjeG+2umZrOS5Ycx85BQhYf0RgsA=" + ) + assert isinstance(cert, SSHCertificate) + cert.verify_cert_signature() + assert cert.extensions == {b"permit-pty": b""} + assert cert.critical_options == { + b"force-command": b"echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + b"verify-required": b"", + } + @pytest.mark.parametrize( "filename", [ @@ -1267,6 +1297,8 @@ def test_invalid_cert_type(self): "p256-p256-non-lexical-extensions.pub", "p256-p256-duplicate-crit-opts.pub", "p256-p256-non-lexical-crit-opts.pub", + "p256-ed25519-non-singular-crit-opt-val.pub", + "p256-ed25519-non-singular-ext-val.pub", ], ) def test_invalid_encodings(self, filename): @@ -1693,6 +1725,11 @@ def test_sign_and_byte_compare_rsa(self, monkeypatch): .valid_after(1672531200) .valid_before(1672617600) .type(SSHCertificateType.USER) + .add_extension(b"permit-pty", b"") + .add_critical_option( + b"force-command", b"echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ) + .add_critical_option(b"verify-required", b"") ) cert = builder.sign(private_key) sig_key = cert.signature_key() @@ -1707,19 +1744,21 @@ def test_sign_and_byte_compare_rsa(self, monkeypatch): b"4kyHpbLEIVloBjzetoqXK6u8Hjz/APuagONypNDCySDR6M7jM85HDcLoFFrbBb8" b"pruHSTxQejMeEmJxYf8b7rNl58/IWPB1ymbNlvHL/4oSOlnrtHkjcxRWzpQ7U3g" b"T9BThGyhCiI7EMyEHMgP3r7kTzEUwT6IavWDAAAAAAAAAAAAAAABAAAAAAAAAAA" - b"AAAAAY7DNAAAAAABjsh6AAAAAAAAAAAAAAAAAAAABFwAAAAdzc2gtcnNhAAAAAw" - b"EAAQAAAQEAwXr8fndHTKpaqDA2FYo/+/e1IWhRuiIw5dar/MHGz+9Z6SPqEzC8W" - b"TtzgCq2CKbkozBlI6MRa6WqOWYUUXThO2xJ6beAYuRJ1y77EP1J6R+gi5bQUeeC" - b"6fWrxbWm95hIJ6245z2gDyKy79zbduq0btrZjtZWYnQ/3GwOM2pdDNuqfcKeU2N" - b"eJMh6WyxCFZaAY83raKlyurvB48/wD7moDjcqTQwskg0ejO4zPORw3C6BRa2wW/" - b"Ka7h0k8UHozHhJicWH/G+6zZefPyFjwdcpmzZbxy/+KEjpZ67R5I3MUVs6UO1N4" - b"E/QU4RsoQoiOxDMhBzID96+5E8xFME+iGr1gwAAARQAAAAMcnNhLXNoYTItNTEy" - b"AAABAKCRnfhn6MZs3jRgIDICUpUyWrDCbpStEbdzhmoxF8w2m8klR7owRH/rxOf" - b"nWhKMGnXnoERS+az3Zh9ckiQPujkuEToORKpzu6CEWlzHSzyK1o2X548KkW76HJ" - b"gqzwMas94HY7UOJUgKSFUI0S3jAgqXAKSa1DxvJBu5/n57aUqPq+BmAtoI8uNBo" - b"x4F1pNEop38+oD7rUt8bZ8K0VcrubJZz806K8UNiK0mOahaEIkvZXBfzPGvSNRj" - b"0OjDl1dLUZaP8C1o5lVRomEm7pLcgE9i+ZDq5iz+mvQrSBStlpQ5hPGuUOrZ/oY" - b"ZLZ1G30R5tWj212MHoNZjxFxM8+f2OT4=" + b"AAAAAY7DNAAAAAABjsh6AAAAAWAAAAA1mb3JjZS1jb21tYW5kAAAALAAAAChlY2" + b"hvIGFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhAAAAD3Zlcmlme" + b"S1yZXF1aXJlZAAAAAAAAAASAAAACnBlcm1pdC1wdHkAAAAAAAAAAAAAARcAAAAH" + b"c3NoLXJzYQAAAAMBAAEAAAEBAMF6/H53R0yqWqgwNhWKP/v3tSFoUboiMOXWq/z" + b"Bxs/vWekj6hMwvFk7c4Aqtgim5KMwZSOjEWulqjlmFFF04TtsSem3gGLkSdcu+x" + b"D9SekfoIuW0FHngun1q8W1pveYSCetuOc9oA8isu/c23bqtG7a2Y7WVmJ0P9xsD" + b"jNqXQzbqn3CnlNjXiTIelssQhWWgGPN62ipcrq7wePP8A+5qA43Kk0MLJINHozu" + b"MzzkcNwugUWtsFvymu4dJPFB6Mx4SYnFh/xvus2Xnz8hY8HXKZs2W8cv/ihI6We" + b"u0eSNzFFbOlDtTeBP0FOEbKEKIjsQzIQcyA/evuRPMRTBPohq9YMAAAEUAAAADH" + b"JzYS1zaGEyLTUxMgAAAQCYbbNzhflDqZAxyBpdLIX0nLAdnTeFNBudMqgo3KGND" + b"WlU9N17hqBEmcvIOrtNi+JKuKZW89zZrbORHvdjv6NjGSKzJD/XA25YrX1KgMEO" + b"wt5pzMZX+100drwrjQo+vZqeIN3FJNmT3wssge73v+JsxQrdIAz7YM2OZrFr5HM" + b"qZEZ5tMvAf/s5YEMDttEU4zMtmjubQyDM5KyYnZdoDT4sKi2rB8gfaigc4IdI/K" + b"8oXL/3Y7rHuOtejl3lUK4v6DxeRl4aqGYWmhUJc++Rh0cbDgC2S6Cq7gAfG2tND" + b"zbwL217Q93R08bJn1hDWuiTiaHGauSy2gPUI+cnkvlEocHM" ) @pytest.mark.supported( @@ -1745,6 +1784,11 @@ def test_sign_and_byte_compare_ed25519(self, monkeypatch, backend): .valid_after(1672531200) .valid_before(1672617600) .type(SSHCertificateType.USER) + .add_extension(b"permit-pty", b"") + .add_critical_option( + b"force-command", b"echo aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + ) + .add_critical_option(b"verify-required", b"") ) cert = builder.sign(private_key) sig_key = cert.signature_key() @@ -1754,8 +1798,11 @@ def test_sign_and_byte_compare_ed25519(self, monkeypatch, backend): b"ssh-ed25519-cert-v01@openssh.com AAAAIHNzaC1lZDI1NTE5LWNlcnQtdj" b"AxQG9wZW5zc2guY29tAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" b"AAAAAAAINdamAGCsQq31Uv+08lkBzoO4XLz2qYjJa8CGmj3B1EaAAAAAAAAAAAA" - b"AAABAAAAAAAAAAAAAAAAY7DNAAAAAABjsh6AAAAAAAAAAAAAAAAAAAAAMwAAAAt" - b"zc2gtZWQyNTUxOQAAACDXWpgBgrEKt9VL/tPJZAc6DuFy89qmIyWvAhpo9wdRGg" - b"AAAFMAAAALc3NoLWVkMjU1MTkAAABAAlF6Lxabxs+8fkOr7KjKYei9konIG13cQ" - b"gJ2tWf3yFcg3OuV5s/AkRmKdwHlQfTUrhRdOmDnGxeLEB0mvkVFCw==" + b"AAABAAAAAAAAAAAAAAAAY7DNAAAAAABjsh6AAAAAWAAAAA1mb3JjZS1jb21tYW5" + b"kAAAALAAAAChlY2hvIGFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYW" + b"FhAAAAD3ZlcmlmeS1yZXF1aXJlZAAAAAAAAAASAAAACnBlcm1pdC1wdHkAAAAAA" + b"AAAAAAAADMAAAALc3NoLWVkMjU1MTkAAAAg11qYAYKxCrfVS/7TyWQHOg7hcvPa" + b"piMlrwIaaPcHURoAAABTAAAAC3NzaC1lZDI1NTE5AAAAQL2aUjeD60C2FrbgHcN" + b"t8yRa8IRbxvOyA9TZYDGG1dRE3DiR0fuudU20v6vqfTd1gx0S5QyEdECXLl9ZI3" + b"AwZgc=" ) diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 662cb9af2b8e..0bac1c271cfb 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -5199,6 +5199,21 @@ def test_load_ecdsa_cert(self, backend): cert.signature_algorithm_parameters, ) + def test_load_ecdsa_cert_null_alg_params(self, backend): + """ + This test verifies that we successfully load certificates with encoded + null parameters in the signature AlgorithmIdentifier. This is invalid, + but Java 11 (up to at least 11.0.19) generates certificates with this + encoding so we need to tolerate it at the moment. + """ + with pytest.warns(utils.DeprecatedIn41): + cert = _load_cert( + os.path.join("x509", "custom", "ecdsa_null_alg.pem"), + x509.load_pem_x509_certificate, + ) + assert isinstance(cert.signature_hash_algorithm, hashes.SHA256) + assert isinstance(cert.public_key(), ec.EllipticCurvePublicKey) + def test_load_bitstring_dn(self, backend): cert = _load_cert( os.path.join("x509", "scottishpower-bitstring-dn.pem"), diff --git a/vectors/cryptography_vectors/__about__.py b/vectors/cryptography_vectors/__about__.py index 6030fab339b0..297da704e265 100644 --- a/vectors/cryptography_vectors/__about__.py +++ b/vectors/cryptography_vectors/__about__.py @@ -6,4 +6,4 @@ "__version__", ] -__version__ = "41.0.0" +__version__ = "41.0.2" diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/certs/p256-ed25519-non-singular-crit-opt-val.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/certs/p256-ed25519-non-singular-crit-opt-val.pub new file mode 100644 index 000000000000..5510bd5f0f35 --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/certs/p256-ed25519-non-singular-crit-opt-val.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIbmlzdHAyNTYAAABBBCZWRs4GYIHGJpyXuqvfFGWN49dnJRkZJLDkFrHf6mNHhIMI3vtrLfCZwxPSfnCYWK6YofssZ1FYA6TkVJq8Xi8AAAAAAAAAAAAAAAEAAAAAAAAAAAAAAABjsM0AAAAAAGOyHoAAAABtAAAADWZvcmNlLWNvbW1hbmQAAABBAAAAKGVjaG8gYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWEAAAARaW52YWxpZF9taXNjX2RhdGEAAAAPdmVyaWZ5LXJlcXVpcmVkAAAAAAAAABIAAAAKcGVybWl0LXB0eQAAAAAAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACDdZgztgAFFC7T5PifrUy/kMu0Pnwq1au3vStKHe7FFMAAAAFMAAAALc3NoLWVkMjU1MTkAAABAt/0pBSDBFy1crBPHOBoKFoxRjKd1tKVdOrD3QVgbBfpaHfxi4vrgYe6JfQ54+vu5P+8yrMyACekT8H6hhvxHDw== \ No newline at end of file diff --git a/vectors/cryptography_vectors/asymmetric/OpenSSH/certs/p256-ed25519-non-singular-ext-val.pub b/vectors/cryptography_vectors/asymmetric/OpenSSH/certs/p256-ed25519-non-singular-ext-val.pub new file mode 100644 index 000000000000..c44b49fceccd --- /dev/null +++ b/vectors/cryptography_vectors/asymmetric/OpenSSH/certs/p256-ed25519-non-singular-ext-val.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAKGVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIbmlzdHAyNTYAAABBBCZWRs4GYIHGJpyXuqvfFGWN49dnJRkZJLDkFrHf6mNHhIMI3vtrLfCZwxPSfnCYWK6YofssZ1FYA6TkVJq8Xi8AAAAAAAAAAAAAAAEAAAAAAAAAAAAAAABjsM0AAAAAAGOyHoAAAAAXAAAAD3ZlcmlmeS1yZXF1aXJlZAAAAAAAAAAvAAAAFGNvbnRhaW5zLWV4dHJhLXZhbHVlAAAAEwAAAAVoZWxsbwAAAAYgd29ybGQAAAAAAAAAMwAAAAtzc2gtZWQyNTUxOQAAACDdZgztgAFFC7T5PifrUy/kMu0Pnwq1au3vStKHe7FFMAAAAFMAAAALc3NoLWVkMjU1MTkAAABAY80oIEvooz/k3x9a+yVkjSNRfi4y/q87wVYiT7keTpP4n9JV/Vlc0u7O2QYOHfb4DUkcrvbsksKVsiqoQu5qDg== \ No newline at end of file diff --git a/vectors/cryptography_vectors/x509/custom/ecdsa_null_alg.pem b/vectors/cryptography_vectors/x509/custom/ecdsa_null_alg.pem new file mode 100644 index 000000000000..327ad553ae7f --- /dev/null +++ b/vectors/cryptography_vectors/x509/custom/ecdsa_null_alg.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBNDCB2aADAgECAgRnI7YfMAwGCCqGSM49BAMCBQAwDzENMAsGA1UEAxMEdGVz +dDAeFw0yMzA1MzExMjI5MDNaFw0yNDA1MjUxMjI5MDNaMA8xDTALBgNVBAMTBHRl +c3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAS2LuMFnF5OcuYcldiufvppacg2 +8fF/KeJ/4QLMOTbnkatgx5wNPOUvlkzfT31MscwYyzkv1oTqe58iQ+R75C27oyEw +HzAdBgNVHQ4EFgQUD6COpW8C9Ns86r2BDE0jP0teCTswDAYIKoZIzj0EAwIFAANI +ADBFAiBKOlNsFpW6Bz7CK7Z5zXrCetnMiSH3NrbKSZBXJV62KQIhAKmjGu3rxlJr +xXpK+Uz8AsoFJ0BlgqPpdMtTGSrDq1AN +-----END CERTIFICATE----- diff --git a/vectors/pyproject.toml b/vectors/pyproject.toml index 44d517f0560e..f468d33dbfa4 100644 --- a/vectors/pyproject.toml +++ b/vectors/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "cryptography_vectors" -version = "41.0.0" +version = "41.0.2" authors = [ {name = "The Python Cryptographic Authority and individual contributors", email = "cryptography-dev@python.org"} ]