Skip to content

Commit

Permalink
Port a tiny tiny bit of the ASN.1 parsing to Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
alex committed Dec 22, 2020
1 parent bd0d0fd commit 6213bad
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 20 deletions.
29 changes: 10 additions & 19 deletions src/cryptography/hazmat/backends/openssl/decode_asn1.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
import ipaddress

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 import _rust
from cryptography.x509.name import _ASN1_TYPE_TO_ENUM
from cryptography.x509.oid import (
CRLEntryExtensionOID,
Expand Down Expand Up @@ -208,27 +207,19 @@ def parse(self, x509_obj):
# ourselves.
if oid == ExtensionOID.TLS_FEATURE:
# 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]
)
data = backend._lib.X509_EXTENSION_get_data(ext)
data_bytes = _asn1_string_to_bytes(backend, data)
value = _rust.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 = backend._lib.X509_EXTENSION_get_data(ext)
data_bytes = _asn1_string_to_bytes(backend, data)
value = _rust.parse_precert_poison(data_bytes)

extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
continue

Expand Down
44 changes: 44 additions & 0 deletions src/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ publish = false

[dependencies]
pyo3 = { version = "0.13.0", features = ["extension-module"] }
asn1 = { git = "https://github.com/alex/rust-asn1" }

[lib]
name = "cryptography_rust"
Expand Down
71 changes: 70 additions & 1 deletion src/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,76 @@
// 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::ValueError::py_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| {
p.read_element::<asn1::Sequence>()?.parse(|p| {
let features = pyo3::types::PyList::empty(py);
while !p.is_empty() {
let feature = p.read_element::<u64>()?;
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))
}

#[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_wrapped(pyo3::wrap_pyfunction!(parse_tls_feature))?;
m.add_wrapped(pyo3::wrap_pyfunction!(parse_precert_poison))?;

Ok(())
}

0 comments on commit 6213bad

Please sign in to comment.