Reputation: 2862
Running Python3.6.
I have a certificate bundle in pem format, that is a server certificate and its CA-certificate. ssl context load_cert_chain('aws-bundle.pem') is throwing an SSL error. Other libraries, like urllib, are having trouble validating a certificate from an HTTPS transaction.
Here is what that bundle file looks like (with lines omitted):
-----BEGIN CERTIFICATE-----
MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsF
. . .
yLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsF
. . .
akcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==
-----END CERTIFICATE-----
Here are excerpts from my ipython transcript:
In [33]: import ssl
In [34]: context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
In [35]: context.load_cert_chain('aws-bundle.pem')
---------------------------------------------------------------------------
SSLError Traceback (most recent call last)
<ipython-input-38-c955611be04f> in <module>
----> 1 context.load_cert_chain('aws-bundle.pem')
SSLError: [SSL] PEM lib (_ssl.c:3520)
By the way, openssl command line tool is able to work just fine with that bundle - dump metadata as text.
By the way, also, I would be willing to bet the requests library can handle my needs, but I am dealing with a context where it would be more desirable to not have to install additional packages.
Upvotes: 4
Views: 19598
Reputation: 12515
You probably need to use load_verify_locations
instead of load_cert_chain
.
Look at documentation:
SSLContext.load_cert_chain(certfile, keyfile=None, password=None)
Load a private key and the corresponding certificate. The certfile string must be the path to a single file in PEM format containing the certificate as well as any number of CA certificates needed to establish the certificate’s authenticity. The keyfile string, if present, must point to a file containing the private key in. Otherwise the private key will be taken from certfile as well. See the discussion of Certificates for more information on how the certificate is stored in the certfile.
Note carefully the: Load a private key and the corresponding certificate.
You are not providing a key in your call, so it will search for it inside your "certificate" file and not finding it, it will barf, for the longer explanations I wrote below before realizing you were not using the appropriate method.
By the way, you may be in fact mixing load_cert_chain
with load_verify_locations
. load_cert_chain
is to load YOUR certificate (with the optional CA certificates attached to it) and its associated private key, NOT to load the CA/intermediate certificates, this is done with load_verify_locations
.
Your "bundle" is either not your certificate, or does not contain a private key. From the name of it, I suppose it is in fact the CA/intermediate certificates, not your certificate, which is why I think you mixed two different methods.
_ssl.c
to understand the errorLooking at the sources of Python 3.6.8, line 3520 of _ssl.c
(https://github.com/python/cpython/blob/3c6b436a57893dd1fae4e072768f41a199076252/Modules/_ssl.c) matches perfectly an error:
_setSSLError(NULL, 0, __FILE__, __LINE__);
(why is that made so cryptic without any details just evades me).
If you double check, you are most probably in the appropriate place regarding your call since the function in which this appears is _ssl__SSLContext_load_cert_chain_impl
.
Now if you study the code above that leads to this line you come to:
r = SSL_CTX_use_PrivateKey_file(self->ctx,
PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), SSL_FILETYPE_PEM);
And something failed here. So just by the name of it (SSL_CTX_use_PrivateKey_file
), I suppose the problem to be with your private key attached to the certificate, so you can stop looking at the content of the certificate bundle!
Sadly, I have no idea what the problem could be with the private key but I guess you could start the obvious path of checking:
Why is this done there? Probably because the code later does:
r = SSL_CTX_check_private_key(self->ctx);
hence it makes sure the private key matches your certificate.
And if you had a problem really with the bundle file, this is done above:
r = SSL_CTX_use_certificate_chain_file(self->ctx, PyBytes_AS_STRING(certfile_bytes));
If that fails, it would trigger an error on line 3499 and hence you would then probably have instead in the stacktrace:
SSLError: [SSL] PEM lib (_ssl.c:3499)
Again, it completely escapes me why developers of those libraries and wrappers on top of libraries just decide to create so cryptic error messages except to force misery on all users. Basically without studying the source code, it is impossible to understand what is happening... And even so, there is absolutely no comments in the source code, but it may have been autogenerated in some parts anyway.
Upvotes: 12