Skip to content

encode arbitrary-precision integers in declarative asn1#15008

Open
dxbjavid wants to merge 1 commit into
pyca:mainfrom
dxbjavid:declarative-asn1-bigint-encode
Open

encode arbitrary-precision integers in declarative asn1#15008
dxbjavid wants to merge 1 commit into
pyca:mainfrom
dxbjavid:declarative-asn1-bigint-encode

Conversation

@dxbjavid

Copy link
Copy Markdown
Contributor

the declarative asn1 decoder reads INTEGER fields as arbitrary-precision values, but the encoder narrows them to an i64, so an integer outside the signed 64-bit range that round-trips through decode_der cannot be re-encoded and instead raises OverflowError. this trips up otherwise valid structures whose integers exceed 64 bits, like RSA moduli or large serial numbers. i've changed the INTEGER arm to emit minimal two's-complement bytes through a BigInt, matching what the decoder already accepts.

@alex alex left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please take a look at the CI results as well.

Thank you!

});
}

#[test]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to add rust tests (except when that's the only way to test something) -- python tests only are fine.

Type::PyInt() => {
let val: i64 = value.extract()?;
let int_value = value.cast::<pyo3::types::PyInt>()?;
let bytes = crate::asn1::py_int_to_der_bytes(py, int_value.clone())?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let bytes = crate::asn1::py_int_to_der_bytes(py, int_value.clone())?;
let bytes = crate::asn1::py_int_to_der_bytes(py, int_value)?;

there's no need to clone since this is the only user of this value.

Comment on lines +207 to +211
let val = asn1::BigInt::new(&bytes).ok_or_else(|| {
CryptographyError::Py(pyo3::exceptions::PyValueError::new_err(
"invalid value for INTEGER",
))
})?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This or-else should be unreachable -- we should never be computing an invalid encoding. Therefore it should be an unwrap()

Comment thread src/rust/src/asn1.rs
.extract::<usize>()?;
// One extra octet leaves room for the sign bit and yields the minimal
// DER length once the high bit is accounted for.
let length = bit_length / 8 + 1;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to think a bit harder to ensure this is correct, but one note to self: a part of this correctness is that if the high bit is set in hte value, then bit_length becomes divisible by 8, otherwise its no (and / 8 rounds down)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants