Cryptography: [BUG] cryptography and Auth0 - ValueError: Unable to load certificate

Created on 8 Oct 2018  路  8Comments  路  Source: pyca/cryptography

Hi all, I'm using the following versions:

  • Python 3.6.6
  • cryptography 2.3.1
  • cffi 1.11.5
  • pipenv 2018.7.1

I used pipenv to install cryptography

Bug is produced when I do a docker-compose up

I am following this tutorial https://auth0.com/blog/building-modern-applications-with-django-and-vuejs/#django-auth0

Error snippet

service_1  |     File "/usr/local/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1138, in load_pem_x509_certificate
service_1  |     raise ValueError("Unable to load certificate")
service_1  |     ValueError: Unable to load certificate

Certificate in question appears to be well formed

MIIC+zCCAeOgAwIBAgIJQUjS7meQqGE0MA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAMTEGNzdGVzdC5hdXRoMC5jb20wHhcNMTgwOTE5MDMyODQwWhcNMzIwNTI4MDMyODQwWjAbMRkwFwYDVQQDExBjc3Rlc3QuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0MyHIRDcUNjLp1DJxOuduh8hsbv00blzNY1Jtm8ligvva9MaM2kiSNLNIO947KvFits/1I4M/TkIpMd6swNI4GPdLXSejQXsmNsfMGX+B5p1Xgk2KjuQDrBsC9sC/hG1xB+S2ycvTBbCx8hUL+iVeddMwwijQm2X+wFMt4c/MJJZ3g0ZdYDaTPvzU63FdmoCosQcEer4jnGz7duZZO6lK/RVDbENC123VyG0NBl35/y7IAckJNbpJPhySIQDcMSP6zTqGgGL0On4jjYplYAdtKST2nEwV98vbI4H7os0LzWbo17zQyZE2irSna1wLD+LYYufX2Z3lOFHExNYh+icuQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRVmruUqbvIOr5H/7wJICKAyQNyxjAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAGSDg5ecP0O2PRkmWjt1YR/VzkWW+X820FKlLJ4vKCd9HQWbkeKqzHU/zVegFPUVINThAwm48MpNCQpfcy7MtXppijNlp/gHgpi5XsoUk3caBsthvULivNmn4O1oQgAemjj2ZDcSeO6e43zN/+44IXHqAo0s9ljst40jtzZG8/KjdUESOB8+cQYVDmarpYv/LMod4NmeZIhMBVZqdWKqgun4QpBd5zyC0dC2UR0nYnMj/Z67LcCe6JTA3mYCaQcN8QAQHzJJQqA/gDYHhIu4488Rx79hScdxmgSt4XOHCty3iQjX+LbSzWV3YyB+nmObtaEfCveM9fZsRAG8NMY+NR0=

Also made a similar post on the Auth0 forums. https://community.auth0.com/t/auth0-certificate-error-valueerror-unable-to-load-certificate/16427

Any help will be appreciated!

Complete stack trace

service_1  | Traceback (most recent call last):
service_1  |   File "manage.py", line 39, in <module>
service_1  |     main()
service_1  |   File "manage.py", line 35, in main
service_1  |     execute_from_command_line(sys.argv)
service_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
service_1  |     utility.execute()
service_1  |   File "/usr/local/lib/python3.6/site-packages/django/core/management/__init__.py", line 325, in execute
service_1  |     settings.INSTALLED_APPS
service_1  |   File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 57, in __getattr__
service_1  |     self._setup(name)
service_1  |   File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 44, in _setup
service_1  |     self._wrapped = Settings(settings_module)
service_1  |   File "/usr/local/lib/python3.6/site-packages/django/conf/__init__.py", line 107, in __init__
service_1  |     mod = importlib.import_module(self.SETTINGS_MODULE)
service_1  |   File "/usr/local/lib/python3.6/importlib/__init__.py", line 126, in import_module
service_1  |     return _bootstrap._gcd_import(name[level:], package, level)
service_1  |   File "<frozen importlib._bootstrap>", line 994, in _gcd_import
service_1  |   File "<frozen importlib._bootstrap>", line 971, in _find_and_load
service_1  |   File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
service_1  |   File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
service_1  |   File "<frozen importlib._bootstrap_external>", line 678, in exec_module
service_1  |   File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
service_1  |   File "/code/server/settings/__init__.py", line 48, in <module>
service_1  |     include(*base_settings)
service_1  |   File "/usr/local/lib/python3.6/site-packages/split_settings/tools.py", line 102, in include
service_1  |     exec(compile(to_compile.read(), included_file, 'exec'), scope)
service_1  |   File "/code/server/settings/components/common.py", line 235, in <module>
service_1  |     certificate = load_pem_x509_certificate(cert.encode('utf-8'), default_backend())
service_1  |   File "/usr/local/lib/python3.6/site-packages/cryptography/x509/base.py", line 43, in load_pem_x509_certificate
service_1  |     return backend.load_pem_x509_certificate(data)
service_1  |   File "/usr/local/lib/python3.6/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1138, in load_pem_x509_certificate
service_1  |     raise ValueError("Unable to load certificate")
service_1  | ValueError: Unable to load certificate
core_service_1 exited with code 1

Most helpful comment

If you're pulling it out of a JW{K,T} you should also be able to do

x509.load_der_x509_certificate(base64.b64decode(jwks['keys'][0]['x5c'][0]), backend)

If that works someone may want to suggest to auth0 that they change their tutorial.

All 8 comments

I believe we've seen this before and the issue was that the certificate didn't have the proper PEM line wrapping. Take a look at your certificate and see if it looks like

-----BEGIN CERTIFICATE-----
<base64 encoded lines that are 64 characters long>
-----END CERTIFICIATE-----

If any line except the last line is greater or less than 64 characters OpenSSL (which cryptography uses) will not be able to parse it.

Hi reaperhulk, thanks for the reply.

Nope, this is my cert

service_1  | -----BEGIN CERTIFICATE-----
service_1  | MIIC+zCCAeOgAwIBAgIJQUjS7meQqGE0MA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNVBAMTEGNzdGVzdC5hdXRoMC5jb20wHhcNMTgwOTE5MDMyODQwWhcNMzIwNTI4MDMyODQwWjAbMRkwFwYDVQQDExBjc3Rlc3QuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0MyHIRDcUNjLp1DJxOuduh8hsbv00blzNY1Jtm8ligvva9MaM2kiSNLNIO947KvFits/1I4M/TkIpMd6swNI4GPdLXSejQXsmNsfMGX+B5p1Xgk2KjuQDrBsC9sC/hG1xB+S2ycvTBbCx8hUL+iVeddMwwijQm2X+wFMt4c/MJJZ3g0ZdYDaTPvzU63FdmoCosQcEer4jnGz7duZZO6lK/RVDbENC123VyG0NBl35/y7IAckJNbpJPhySIQDcMSP6zTqGgGL0On4jjYplYAdtKST2nEwV98vbI4H7os0LzWbo17zQyZE2irSna1wLD+LYYufX2Z3lOFHExNYh+icuQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRVmruUqbvIOr5H/7wJICKAyQNyxjAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAGSDg5ecP0O2PRkmWjt1YR/VzkWW+X820FKlLJ4vKCd9HQWbkeKqzHU/zVegFPUVINThAwm48MpNCQpfcy7MtXppijNlp/gHgpi5XsoUk3caBsthvULivNmn4O1oQgAemjj2ZDcSeO6e43zN/+44IXHqAo0s9ljst40jtzZG8/KjdUESOB8+cQYVDmarpYv/LMod4NmeZIhMBVZqdWKqgun4QpBd5zyC0dC2UR0nYnMj/Z67LcCe6JTA3mYCaQcN8QAQHzJJQqA/gDYHhIu4488Rx79hScdxmgSt4XOHCty3iQjX+LbSzWV3YyB+nmObtaEfCveM9fZsRAG8NMY+NR0=
service_1  | -----END CERTIFICATE-----

Yep, re-wrap it to 64 characters per line and it will load. That is not technically a valid PEM certificate right now.

ah right I get what you mean now, okay I'll give it a try.

yes wrapping in into 64 chars per line solves this issue. Thanks once again @reaperhulk

For those wondering how to do this, I was able to solve it replacing this:
cert = '-----BEGIN CERTIFICATE-----\n' + jwks['keys'][0]['x5c'][0] + '\n-----END CERTIFICATE-----'

with this:

import textwrap
wrapped_base64_text = textwrap.wrap(jwks['keys'][0]['x5c'][0],64)
cert = '\n'.join(['-----BEGIN CERTIFICATE-----', *wrapped_base64_text, '-----END CERTIFICATE-----'])

If you're pulling it out of a JW{K,T} you should also be able to do

x509.load_der_x509_certificate(base64.b64decode(jwks['keys'][0]['x5c'][0]), backend)

If that works someone may want to suggest to auth0 that they change their tutorial.

hey there, thanks for bringing this up... I will take a look at it and take the appropriate action

Was this page helpful?
0 / 5 - 0 ratings

Related issues

TrollNation picture TrollNation  路  20Comments

reaperhulk picture reaperhulk  路  22Comments

clarius-deploy picture clarius-deploy  路  22Comments

Naddiseo picture Naddiseo  路  45Comments

ctismer picture ctismer  路  29Comments