Skip to content

Commit

Permalink
Add Python 3.13 support, update to latest PyO3
Browse files Browse the repository at this point in the history
Update to latest PyO3
  • Loading branch information
CBonnell authored Oct 14, 2024
2 parents c6281e6 + 949c187 commit c6f470d
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 211 deletions.
Binary file modified .github/workflows/CI.yml
Binary file not shown.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyasn1-fasder"
version = "0.1.2"
version = "0.1.3"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
Expand All @@ -9,7 +9,7 @@ name = "pyasn1_fasder"
crate-type = ["cdylib"]

[dependencies]
pyo3 = { version = "0.20.3", features = ["num-bigint"] }
pyo3 = { version = "0.22.4", features = ["abi3", "abi3-py39", "num-bigint"] }
der = { version = "0.7.8", features = ["oid"] }
num-bigint = "0.4.6"
itertools = "0.13.0"
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dynamic = ["version"]
dependencies = [
Expand Down
218 changes: 113 additions & 105 deletions src/asn1_type.rs

Large diffs are not rendered by default.

123 changes: 64 additions & 59 deletions src/decoder.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
use der::{Encode, Header, Reader};
use pyo3::PyAny;
use pyo3::PyErr;
use pyo3::PyResult;
use pyo3::prelude::{PyModule};
use pyo3::types::PyDict;
use crate::{HELPER_MODULE_ATTR, NativeHelperModule, Pyasn1FasderError, TYPE_MAP};
use crate::asn1_type::{AnyDecoder, BitStringDecoder, BooleanDecoder, CharacterStringDecoder, ChoiceDecoder, Decoder, IntegerDecoder, NullDecoder, ObjectIdentifierDecoder, OctetStringDecoder, PrintableStringDecoder, SequenceDecoder, SequenceOfDecoder, SetOfDecoder};
use crate::tag::Asn1Tag;

use crate::{NativeHelperModule, Pyasn1FasderError, HELPER_MODULE_ATTR, TYPE_MAP};
use der::{Encode, Header, Reader};
use pyo3::prelude::{PyAnyMethods, PyModule, PyTypeMethods};
use pyo3::types::PyDict;
use pyo3::types::PyDictMethods;
use pyo3::PyResult;
use pyo3::{Bound, PyAny};
use pyo3::PyErr;

const TYPE_ID_ATTR: &str = "typeId";


#[derive(Copy, Clone)]
#[derive(Clone)]
pub struct DecodeStep<'py> {
module: NativeHelperModule<'py>,
substrate: &'py [u8],
header: Header,
asn1_spec: &'py PyAny,
tag_set: &'py PyAny,
asn1_spec: Bound<'py, PyAny>,
tag_set: Bound<'py, PyAny>,
offset: usize
}

impl<'py> DecodeStep<'py> {
pub fn new(module: NativeHelperModule<'py>, substrate: &'py [u8], header: Header, asn1_spec: &'py PyAny, tag_set: &'py PyAny, offset: usize) -> Self {
pub fn new(module: NativeHelperModule<'py>, substrate: &'py [u8], header: Header, asn1_spec: Bound<'py, PyAny>, tag_set: Bound<'py, PyAny>, offset: usize) -> Self {
Self { module, substrate, header, asn1_spec, tag_set, offset }
}

pub fn module(&self) -> NativeHelperModule<'py> {
self.module
pub fn module(&self) -> &NativeHelperModule<'py> {
&self.module
}

pub fn substrate(&self) -> &'py [u8] {
Expand All @@ -47,12 +47,12 @@ impl<'py> DecodeStep<'py> {
Asn1Tag::new(self.substrate[0])
}

pub fn asn1_spec(&self) -> &'py PyAny {
self.asn1_spec
pub fn asn1_spec(&self) -> &Bound<'py, PyAny> {
&self.asn1_spec
}

pub fn tag_set(&self) -> &'py PyAny {
self.tag_set
pub fn tag_set(&self) -> &Bound<'py, PyAny> {
&self.tag_set
}

pub fn value_substrate_len(&self) -> usize {
Expand All @@ -68,7 +68,8 @@ impl<'py> DecodeStep<'py> {
}

pub fn create_error(&self, description: &str) -> PyErr {
let asn1_spec_name = self.asn1_spec.get_type().name().unwrap();
let asn1_spec_type = self.asn1_spec.get_type();
let asn1_spec_name = asn1_spec_type.name().unwrap();

Pyasn1FasderError::new_err(format!("Error decoding \"{}\" TLV near substrate offset {}: {}", asn1_spec_name, self.offset, description))
}
Expand Down Expand Up @@ -118,18 +119,20 @@ const DECODER_TYPE_ANY: usize = 98;
const DECODER_TYPE_CHOICE: usize = 99;


pub fn decode_asn1_spec_value<'py>(step: DecodeStep<'py>) -> PyResult<Bound<'py, PyAny>> {
let type_id = step.asn1_spec().getattr(TYPE_ID_ATTR)?;

pub fn decode_asn1_spec_value(step: DecodeStep) -> PyResult<&PyAny> {
let type_id = step.asn1_spec().getattr(TYPE_ID_ATTR).unwrap();
let decoder_mappings = &step.module.decoder_mappings;
let type_mapping = PyDictMethods::get_item(decoder_mappings, type_id.clone())?;

match step.module.decoder_mappings.get_item(type_id).unwrap() {
match type_mapping {
None => {
let type_id_u8 : u8 = type_id.extract()?;

Err(step.create_error(&format!("ASN.1 specification with type ID of {} is not supported", type_id_u8)))
},
Some(decoder_id) => {
let decoder_id_u8: usize = decoder_id.extract().unwrap();
let decoder_id_u8: usize = decoder_id.extract()?;

let decoder: &dyn Decoder = match decoder_id_u8 {
DECODER_TYPE_BOOLEAN => &BooleanDecoder::new(step),
Expand All @@ -156,6 +159,7 @@ pub fn decode_asn1_spec_value(step: DecodeStep) -> PyResult<&PyAny> {
DECODER_TYPE_BMPSTRING => &CharacterStringDecoder::new(step, "BMPSTRING"),
DECODER_TYPE_ANY => &AnyDecoder::new(step),
DECODER_TYPE_CHOICE => &ChoiceDecoder::new(step),

_ => return Err(Pyasn1FasderError::new_err("ASN.1 type is unsuppported"))
};

Expand All @@ -169,7 +173,7 @@ pub fn decode_asn1_spec_value(step: DecodeStep) -> PyResult<&PyAny> {
match decoded_result {
Err(e) => Err(e),
Ok(decoded) => {
match decoder.verify_decoded(decoded) {
match decoder.verify_decoded(&decoded) {
Err(e) => Err(e),
Ok(()) => Ok(decoded)
}
Expand All @@ -180,50 +184,51 @@ pub fn decode_asn1_spec_value(step: DecodeStep) -> PyResult<&PyAny> {
}


pub fn init_module<'py>(m: &'py PyModule) -> PyResult<()> {
pub fn init_module(m: &Bound<PyModule>) -> PyResult<()> {
let py = m.py();

let helper_mod = m.getattr(HELPER_MODULE_ATTR)?;
let type_map : &PyDict = helper_mod.getattr(TYPE_MAP).unwrap().downcast_exact().unwrap();
let type_map_any = helper_mod.getattr(TYPE_MAP)?;
let type_map : &Bound<PyDict> = type_map_any.downcast_exact()?;

let add_map_entry = |type_mod: &'py PyModule, cls_name: &str, decoder_type: usize| {
let add_map_entry = |type_mod: &Bound<PyModule>, cls_name: &str, decoder_type: usize| {
let type_id = type_mod.getattr(cls_name).unwrap().getattr(TYPE_ID_ATTR).unwrap();

type_map.set_item(type_id, decoder_type).unwrap()
};

let univ_mod = py.import("pyasn1.type.univ").unwrap();

add_map_entry(univ_mod, "Boolean", DECODER_TYPE_BOOLEAN);
add_map_entry(univ_mod, "Integer", DECODER_TYPE_INTEGER);
add_map_entry(univ_mod, "BitString", DECODER_TYPE_BITSTRING);
add_map_entry(univ_mod, "OctetString", DECODER_TYPE_OCTETSTRING);
add_map_entry(univ_mod, "Null", DECODER_TYPE_NULL);
add_map_entry(univ_mod, "ObjectIdentifier", DECODER_TYPE_OBJECTIDENTIFIER);
add_map_entry(univ_mod, "Enumerated", DECODER_TYPE_ENUMERATED);
add_map_entry(univ_mod, "Sequence", DECODER_TYPE_SEQUENCE);
add_map_entry(univ_mod, "SequenceOf", DECODER_TYPE_SEQUENCEOF);
add_map_entry(univ_mod, "SetOf", DECODER_TYPE_SETOF);
add_map_entry(univ_mod, "Any", DECODER_TYPE_ANY);
add_map_entry(univ_mod, "Choice", DECODER_TYPE_CHOICE);

let char_mod = py.import("pyasn1.type.char").unwrap();

add_map_entry(char_mod, "NumericString", DECODER_TYPE_NUMERICSTRING);
add_map_entry(char_mod, "PrintableString", DECODER_TYPE_PRINTABLESTRING);
add_map_entry(char_mod, "TeletexString", DECODER_TYPE_TELETEXSTRING);
add_map_entry(char_mod, "VideotexString", DECODER_TYPE_VIDEOTEXSTRING);
add_map_entry(char_mod, "IA5String", DECODER_TYPE_IA5STRING);
add_map_entry(char_mod, "GraphicString", DECODER_TYPE_GRAPHICSTRING);
add_map_entry(char_mod, "VisibleString", DECODER_TYPE_VISIBLESTRING);
add_map_entry(char_mod, "UniversalString", DECODER_TYPE_UNIVERSALSTRING);
add_map_entry(char_mod, "BMPString", DECODER_TYPE_BMPSTRING);
add_map_entry(char_mod, "UTF8String", DECODER_TYPE_UTF8STRING);

let useful_mod = py.import("pyasn1.type.useful")?;

add_map_entry(useful_mod, "UTCTime", DECODER_TYPE_UTCTIME);
add_map_entry(useful_mod, "GeneralizedTime", DECODER_TYPE_GENERALIZEDTIME);
let univ_mod = py.import_bound("pyasn1.type.univ")?;

add_map_entry(&univ_mod, "Boolean", DECODER_TYPE_BOOLEAN);
add_map_entry(&univ_mod, "Integer", DECODER_TYPE_INTEGER);
add_map_entry(&univ_mod, "BitString", DECODER_TYPE_BITSTRING);
add_map_entry(&univ_mod, "OctetString", DECODER_TYPE_OCTETSTRING);
add_map_entry(&univ_mod, "Null", DECODER_TYPE_NULL);
add_map_entry(&univ_mod, "ObjectIdentifier", DECODER_TYPE_OBJECTIDENTIFIER);
add_map_entry(&univ_mod, "Enumerated", DECODER_TYPE_ENUMERATED);
add_map_entry(&univ_mod, "Sequence", DECODER_TYPE_SEQUENCE);
add_map_entry(&univ_mod, "SequenceOf", DECODER_TYPE_SEQUENCEOF);
add_map_entry(&univ_mod, "SetOf", DECODER_TYPE_SETOF);
add_map_entry(&univ_mod, "Any", DECODER_TYPE_ANY);
add_map_entry(&univ_mod, "Choice", DECODER_TYPE_CHOICE);

let char_mod = py.import_bound("pyasn1.type.char")?;

add_map_entry(&char_mod, "NumericString", DECODER_TYPE_NUMERICSTRING);
add_map_entry(&char_mod, "PrintableString", DECODER_TYPE_PRINTABLESTRING);
add_map_entry(&char_mod, "TeletexString", DECODER_TYPE_TELETEXSTRING);
add_map_entry(&char_mod, "VideotexString", DECODER_TYPE_VIDEOTEXSTRING);
add_map_entry(&char_mod, "IA5String", DECODER_TYPE_IA5STRING);
add_map_entry(&char_mod, "GraphicString", DECODER_TYPE_GRAPHICSTRING);
add_map_entry(&char_mod, "VisibleString", DECODER_TYPE_VISIBLESTRING);
add_map_entry(&char_mod, "UniversalString", DECODER_TYPE_UNIVERSALSTRING);
add_map_entry(&char_mod, "BMPString", DECODER_TYPE_BMPSTRING);
add_map_entry(&char_mod, "UTF8String", DECODER_TYPE_UTF8STRING);

let useful_mod = py.import_bound("pyasn1.type.useful")?;

add_map_entry(&useful_mod, "UTCTime", DECODER_TYPE_UTCTIME);
add_map_entry(&useful_mod, "GeneralizedTime", DECODER_TYPE_GENERALIZEDTIME);

Ok(())
}
Loading

0 comments on commit c6f470d

Please sign in to comment.