Repository: pyca/cryptography

Issue:
serial_number parse error

[serialNumberNegative.txt](https://github.com/pyca/cryptography/files/3041594/serialNumberNegative.txt)
if i use the function : x509.load_pem_x509_certificate(f.read(), default_backend()) to parse the above certificate , the serialnumber should be a negitive number, but it be parsed in to a positive one, so i think whether some logic error insome where.
3.6 of Python, ``cryptography``,



Discussion:
Interesting, this bug impacts Python3 but Python2 does the right thing.
https://github.com/pyca/cryptography/blob/master/src/cryptography/hazmat/backends/openssl/backend.py#L331-L337

The bug here is that `BN_bn2bin` gives us the data of the absolute value of the BN, but we ignore the sign.
I'm using the cryptography to parse certificate, and i meet a trouble that if some major error ouccered in one field of the certificate's extensions, it will raise a error, and meanwhile i can't extract other irrelevant extension fields，i think it is illogical or i miss something important.
If you encounter other issues, please file seperate bugs for them.

On Wed, Apr 3, 2019 at 11:57 PM 846468230 <notifications@github.com> wrote:

> I'm using the cryptography to parse certificate, and i meet a trouble that
> if some major error ouccered in one field of the certificate's extensions,
> it will raise a error, and meanwhile i can't extract other irrelevant
> extension fields，i think it is illogical or i miss something important.
>
> —
> You are receiving this because you commented.
> Reply to this email directly, view it on GitHub
> <https://github.com/pyca/cryptography/issues/4830#issuecomment-479741016>,
> or mute the thread
> <https://github.com/notifications/unsubscribe-auth/AAADBFXsw6CMqNtUtVoXprWOXQNZED5Rks5vdXgagaJpZM4cb2Ma>
> .
>


-- 
All that is necessary for evil to succeed is for good people to do nothing.


Resolving patch:
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -334,7 +334,10 @@ def _bn_to_int(self, bn):
             bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
             # A zero length means the BN has value 0
             self.openssl_assert(bin_len >= 0)
-            return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
+            val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
+            if self._lib.BN_is_negative(bn):
+                val = -val
+            return val
         else:
             # Under Python 2 the best we can do is hex()
             hex_cdata = self._lib.BN_bn2hex(bn)


Test patch:
diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py
--- a/tests/x509/test_x509.py
+++ b/tests/x509/test_x509.py
@@ -597,6 +597,14 @@ def test_load_pem_cert(self, backend):
             cert.signature_algorithm_oid == SignatureAlgorithmOID.RSA_WITH_SHA1
         )
 
+    def test_negative_serial_number(self, backend):
+        cert = _load_cert(
+            os.path.join("x509", "custom", "negative_serial.pem"),
+            x509.load_pem_x509_certificate,
+            backend,
+        )
+        assert cert.serial_number == -18008675309
+
     def test_alternate_rsa_with_sha1_oid(self, backend):
         cert = _load_cert(
             os.path.join("x509", "alternate-rsa-sha1-oid.pem"),