Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed certificates in NodeMetadataPayload #12

Closed
wants to merge 2 commits into from

Conversation

fjarri
Copy link
Contributor

@fjarri fjarri commented Mar 6, 2022

  • renamed NodeMetadataPayload.certificate_bytes to certificate and made it a type of x509_certificate::certificate::X509Certificate.
  • bindings expose it as certificate_der, returning a DER-encoded certificate
  • the certificate is serialized as DER bytes

DER vs PEM is ~370 vs ~570 bytes, so not a small difference.

There is one issue though. When I serialize a certificate created in Python (in cryptograpgy) as DER, pass it to the Rust object, and then serialize the Rust object to DER, it returns a slightly different certificate.

Example:

Python:

b'0\x82\x01u0\x81\xfc\xa0\x03\x02\x01\x02\x02\x14\x1c\xfd>PM\x9a_\x07AO&C\xaeW\xd4\xa1$0\x86\x0e0\n\x06\x08*\x86H\xce=\x04\x03\x040\x121\x100\x0e\x06\x03U\x04\x03\x0c\x071.2.3.40\x1e\x17\r220306002352Z\x17\r230306002352Z0\x121\x100\x0e\x06\x03U\x04\x03\x0c\x071.2.3.40v0\x10\x06\x07*\x86H\xce=\x02\x01\x06\x05+\x81\x04\x00"\x03b\x00\x04?\x1e5\x811j\x92\xfd\t\x82\x0f\xb4\xb1\xff\xfd,?\xc1%N`\x96=\rTR\x9a[X\xd1Fca\x86\xec\xdb\x1a]\x054(\x0cm\x97\xf5\xedv\x7f\xe0~@\xfe\x17m\xfd\xe4/\x0b5\xb3\xe4\xf7Q\xf0\xd1C\x9f\x07\x8c\xf2\xdb]\x88\x13P\xc2Q\xb2Ak\t\x12\'\xcb\xaf\x8aK\xfb\x00\x9a\xee\x81\xedP\x8c2\xa3\x130\x110\x0f\x06\x03U\x1d\x11\x04\x080\x06\x87\x04\x01\x02\x03\x040\n\x06\x08*\x86H\xce=\x04\x03\x04\x03h\x000e\x020Y\xb2\xa2\x10uX\x07p\xabM\xe2L\xa23\xfbM\x8d.\x16(!\xf9\xe8\x06\xf7\xd3\x9aJ*\xf5i!\xba^\xfc\x07\x122v{\xe5\xd0\xacF\xe3{\xa4\x85\x021\x00\xac\xa9\xbb^\n\x0f\x8d?\r\xa4\xa4\xacS\xee\xe4Gh\xe9\x9a|\xd1l\xf3\x1f\x07a\x9c\xc327_\xfc2O\xe5\xea\xaa\xe4,\x0cL\x02\x80\xdd\xf2;\xe1C'

Rust:

b'0\x82\x01y0\x81\xfe\xa0\x03\x02\x01\x02\x02\x14\x1c\xfd>PM\x9a_\x07AO&C\xaeW\xd4\xa1$0\x86\x0e0\x0c\x06\x08*\x86H\xce=\x04\x03\x04\x05\x000\x121\x100\x0e\x06\x03U\x04\x03\x0c\x071.2.3.40\x1e\x17\r220306002352Z\x17\r230306002352Z0\x121\x100\x0e\x06\x03U\x04\x03\x0c\x071.2.3.40v0\x10\x06\x07*\x86H\xce=\x02\x01\x06\x05+\x81\x04\x00"\x03b\x00\x04?\x1e5\x811j\x92\xfd\t\x82\x0f\xb4\xb1\xff\xfd,?\xc1%N`\x96=\rTR\x9a[X\xd1Fca\x86\xec\xdb\x1a]\x054(\x0cm\x97\xf5\xedv\x7f\xe0~@\xfe\x17m\xfd\xe4/\x0b5\xb3\xe4\xf7Q\xf0\xd1C\x9f\x07\x8c\xf2\xdb]\x88\x13P\xc2Q\xb2Ak\t\x12\'\xcb\xaf\x8aK\xfb\x00\x9a\xee\x81\xedP\x8c2\xa3\x130\x110\x0f\x06\x03U\x1d\x11\x04\x080\x06\x87\x04\x01\x02\x03\x040\x0c\x06\x08*\x86H\xce=\x04\x03\x04\x05\x00\x03h\x000e\x020Y\xb2\xa2\x10uX\x07p\xabM\xe2L\xa23\xfbM\x8d.\x16(!\xf9\xe8\x06\xf7\xd3\x9aJ*\xf5i!\xba^\xfc\x07\x122v{\xe5\xd0\xacF\xe3{\xa4\x85\x021\x00\xac\xa9\xbb^\n\x0f\x8d?\r\xa4\xa4\xacS\xee\xe4Gh\xe9\x9a|\xd1l\xf3\x1f\x07a\x9c\xc327_\xfc2O\xe5\xea\xaa\xe4,\x0cL\x02\x80\xdd\xf2;\xe1C'

The difference here is two occurrences of b'\x06\x08*\x86H\xce=\x04\x03\x04' in Python and b'\x06\x08*\x86H\xce=\x04\x03\x04\x05\x00' in Rust. It is kind of at the place where OID (1.2.840.10045.4.3.4) would be, and looks like it, but not quite.

The Rust version can be deserialized back into Python, but the resulting certificate is not equal to the original one. openssl x509 -inform der does not show any differences.

@fjarri fjarri added API Related to public API ABI Changes the format of serialized objects labels Mar 6, 2022
@codecov-commenter
Copy link

Codecov Report

Merging #12 (0475d45) into master (82702fc) will not change coverage.
The diff coverage is 0.00%.

Impacted file tree graph

@@          Coverage Diff           @@
##           master     #12   +/-   ##
======================================
  Coverage    0.00%   0.00%           
======================================
  Files          12      12           
  Lines         423     434   +11     
======================================
- Misses        423     434   +11     
Impacted Files Coverage Δ
nucypher-core/src/node_metadata.rs 0.00% <0.00%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 82702fc...0475d45. Read the comment docs.

@fjarri
Copy link
Contributor Author

fjarri commented Mar 6, 2022

Okay, so after some investigation of the difference:

The differing substrings do encode the OID. In Python, we have b'0\n\x06\x08*\x86H\xce=\x04\x03\x04', which parses as:

0 # SEQUENCE tag (0x30)
\n # length of the contents (10 bytes)
  \x06 # OID tag
  \x08 # length of the contents
    *\x86H\xce=\x04\x03\x04 # OID itself

In the Rust version, we have b'0\x0c\x06\x08*\x86H\xce=\x04\x03\x04\x05\x00', which parses as:

0 # SEQUENCE tag (0x30)
\x0c # length of the contents (12 bytes)
  \x06 # OID tag
  \x08 # length of the contents
    *\x86H\xce=\x04\x03\x04 # OID itself
  \x05 # NULL tag
  \x00 # zero length, the only possible thing to follow after a NULL tag  

So, according to RFC 5280, this encodes an empty parameters for the AlgorithmIdentifier (the whole thing). In the standard, parameters is OPTIONAL, which means, if it is empty, it should be omitted. But Rust has a different opinion:

        // parameters is strictly OPTIONAL, which means we can omit it completely.
        // However, it is common to see this field encoded as NULL and some
        // parsers seem to insist the NULL be there or else they refuse to
        // parse the ASN.1. So we ensure this field is always set.

So, I guess, we have to live with this discrepancy and make sure that we consistently use either Rust-made or Python-made certificates on the Python side. It seems that when Python opens the certificate, it preserves the original DER, and maps it to the fields it knows, so when one serializes it again, the null field is there. But you cannot reproduce this behavior in a certificate made in Python (unless you do some byte manipulation manually).

P.S. Thanks to this article which explains ASN.1 much better than the standard.

Copy link
Contributor

@piotr-roslaniec piotr-roslaniec left a comment

Choose a reason for hiding this comment

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

LGTM 🎉

@fjarri
Copy link
Contributor Author

fjarri commented Mar 13, 2022

Closing in favor of #13.

@fjarri fjarri closed this Mar 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ABI Changes the format of serialized objects API Related to public API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants