diff options
| author | Alex Gaynor <alex.gaynor@gmail.com> | 2021-04-11 16:44:27 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-11 15:44:27 -0500 |
| commit | ead82753899c4ad1d4096d718d65d4df64836ddd (patch) | |
| tree | cae5b61a476be2e00a0394b1315968459b3cee64 | |
| parent | 851877e3e8dd7e6b6035c2e02d80690c4c8b9cf6 (diff) | |
| download | cryptography-ead82753899c4ad1d4096d718d65d4df64836ddd.tar.gz | |
Port a tiny tiny bit of the ASN.1 parsing to Rust (#5357)
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/decode_asn1.py | 23 | ||||
| -rw-r--r-- | src/rust/Cargo.lock | 47 | ||||
| -rw-r--r-- | src/rust/Cargo.toml | 1 | ||||
| -rw-r--r-- | src/rust/src/asn1.rs | 75 | ||||
| -rw-r--r-- | src/rust/src/lib.rs | 6 |
5 files changed, 135 insertions, 17 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py index e62c25406..6e4dc0e93 100644 --- a/src/cryptography/hazmat/backends/openssl/decode_asn1.py +++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -8,8 +8,7 @@ import ipaddress import typing from cryptography import x509 -from cryptography.hazmat._der import DERReader, INTEGER, NULL, SEQUENCE -from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM +from cryptography.hazmat.bindings._rust import asn1 from cryptography.x509.name import _ASN1_TYPE_TO_ENUM from cryptography.x509.oid import ( CRLEntryExtensionOID, @@ -211,25 +210,17 @@ class _X509ExtensionParser(object): # The extension contents are a SEQUENCE OF INTEGERs. data = self._backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(self._backend, data) - features = DERReader(data_bytes).read_single_element(SEQUENCE) - parsed = [] - while not features.is_empty(): - parsed.append(features.read_element(INTEGER).as_integer()) - # Map the features to their enum value. - value = x509.TLSFeature( - [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed] - ) + value = asn1.parse_tls_feature(data_bytes) + extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POISON: data = self._backend._lib.X509_EXTENSION_get_data(ext) - # The contents of the extension must be an ASN.1 NULL. - reader = DERReader(_asn1_string_to_bytes(self._backend, data)) - reader.read_single_element(NULL).check_empty() - extensions.append( - x509.Extension(oid, critical, x509.PrecertPoison()) - ) + data_bytes = _asn1_string_to_bytes(self._backend, data) + value = asn1.parse_precert_poison(data_bytes) + + extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue diff --git a/src/rust/Cargo.lock b/src/rust/Cargo.lock index 2bd1b9f46..8cd155ba8 100644 --- a/src/rust/Cargo.lock +++ b/src/rust/Cargo.lock @@ -1,5 +1,22 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + +[[package]] +name = "asn1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d2efbfc907088c522a054db6e60277d3f3bf0cf73cd3e2676806f4d95f3b20" +dependencies = [ + "chrono", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bitflags" version = "1.2.1" @@ -13,9 +30,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] name = "cryptography-rust" version = "0.1.0" dependencies = [ + "asn1", "pyo3", ] @@ -110,6 +138,25 @@ dependencies = [ ] [[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] name = "parking_lot" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml index bcb9add10..b0dbc6f11 100644 --- a/src/rust/Cargo.toml +++ b/src/rust/Cargo.toml @@ -7,6 +7,7 @@ publish = false [dependencies] pyo3 = { version = "0.13.1", features = ["extension-module"] } +asn1 = { version = "0.3", default-features = false } [lib] name = "cryptography_rust" diff --git a/src/rust/src/asn1.rs b/src/rust/src/asn1.rs new file mode 100644 index 000000000..a2db23e12 --- /dev/null +++ b/src/rust/src/asn1.rs @@ -0,0 +1,75 @@ +// This file is dual licensed under the terms of the Apache License, Version +// 2.0, and the BSD License. See the LICENSE file in the root of this repository +// for complete details. + +use pyo3::conversion::ToPyObject; + +enum PyAsn1Error { + Asn1(asn1::ParseError), + Py(pyo3::PyErr), +} + +impl From<asn1::ParseError> for PyAsn1Error { + fn from(e: asn1::ParseError) -> PyAsn1Error { + PyAsn1Error::Asn1(e) + } +} + +impl From<pyo3::PyErr> for PyAsn1Error { + fn from(e: pyo3::PyErr) -> PyAsn1Error { + PyAsn1Error::Py(e) + } +} + +impl From<PyAsn1Error> for pyo3::PyErr { + fn from(e: PyAsn1Error) -> pyo3::PyErr { + match e { + PyAsn1Error::Asn1(asn1_error) => pyo3::exceptions::PyValueError::new_err(format!( + "error parsing asn1 value: {:?}", + asn1_error + )), + PyAsn1Error::Py(py_error) => py_error, + } + } +} + +#[pyo3::prelude::pyfunction] +fn parse_tls_feature(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult<pyo3::PyObject> { + let tls_feature_type_to_enum = py + .import("cryptography.x509.extensions")? + .getattr("_TLS_FEATURE_TYPE_TO_ENUM")?; + + let features = asn1::parse::<_, PyAsn1Error, _>(data, |p| { + let features = pyo3::types::PyList::empty(py); + for el in p.read_element::<asn1::SequenceOf<u64>>()? { + let feature = el?; + let py_feature = tls_feature_type_to_enum.get_item(feature.to_object(py))?; + features.append(py_feature)?; + } + Ok(features) + })?; + + let x509_module = py.import("cryptography.x509")?; + x509_module + .call1("TLSFeature", (features,)) + .map(|o| o.to_object(py)) +} + +#[pyo3::prelude::pyfunction] +fn parse_precert_poison(py: pyo3::Python<'_>, data: &[u8]) -> pyo3::PyResult<pyo3::PyObject> { + asn1::parse::<_, PyAsn1Error, _>(data, |p| { + p.read_element::<()>()?; + Ok(()) + })?; + + let x509_module = py.import("cryptography.x509")?; + x509_module.call0("PrecertPoison").map(|o| o.to_object(py)) +} + +pub(crate) fn create_submodule(py: pyo3::Python) -> pyo3::PyResult<&pyo3::prelude::PyModule> { + let submod = pyo3::prelude::PyModule::new(py, "asn1")?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_tls_feature))?; + submod.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?; + + Ok(submod) +} diff --git a/src/rust/src/lib.rs b/src/rust/src/lib.rs index 3257b35e1..a3b3fb715 100644 --- a/src/rust/src/lib.rs +++ b/src/rust/src/lib.rs @@ -2,6 +2,8 @@ // 2.0, and the BSD License. See the LICENSE file in the root of this repository // for complete details. +mod asn1; + use std::convert::TryInto; /// Returns the value of the input with the most-significant-bit copied to all @@ -66,10 +68,12 @@ fn check_ansix923_padding(data: &[u8]) -> bool { } #[pyo3::prelude::pymodule] -fn _rust(_py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { +fn _rust(py: pyo3::Python<'_>, m: &pyo3::types::PyModule) -> pyo3::PyResult<()> { m.add_function(pyo3::wrap_pyfunction!(check_pkcs7_padding, m)?)?; m.add_function(pyo3::wrap_pyfunction!(check_ansix923_padding, m)?)?; + m.add_submodule(asn1::create_submodule(py)?)?; + Ok(()) } |
