summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2021-04-11 16:44:27 -0400
committerGitHub <noreply@github.com>2021-04-11 15:44:27 -0500
commitead82753899c4ad1d4096d718d65d4df64836ddd (patch)
treecae5b61a476be2e00a0394b1315968459b3cee64
parent851877e3e8dd7e6b6035c2e02d80690c4c8b9cf6 (diff)
downloadcryptography-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.py23
-rw-r--r--src/rust/Cargo.lock47
-rw-r--r--src/rust/Cargo.toml1
-rw-r--r--src/rust/src/asn1.rs75
-rw-r--r--src/rust/src/lib.rs6
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(())
}