Skip to content

Improve TLS connection implementation to support use of one way TLS certificates without needing OS recognition #65

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

Closed
FrancoisNoyez opened this issue Sep 20, 2022 · 20 comments
Labels
enhancement New feature or request patch available

Comments

@FrancoisNoyez
Copy link

Talking about version 1.1.0.

The current version does not allow to use unencrypted .pem file for mTLS connection, for which the following code, found at line 134 of the 'src/oracledb/impl/thin/crypto.pyx' module, fails in that case:

ssl_context.load_cert_chain(pem_file_name,
                            password=params._get_wallet_password())

Things work if we make this code line conditional, for instance on whether a password to decrypt the certificate is actually provided:

password = params._get_wallet_password()
if password is not None:
   ssl_context.load_cert_chain(pem_file_name,
                               password=password)

Cf this discussion on the forum: something like that is necessary when one is using the Oracle Cloud functionality of the Amazon Cloud service, and notably when one is not admin of the server actually hosting the Oracle database.

@FrancoisNoyez FrancoisNoyez added the enhancement New feature or request label Sep 20, 2022
@anthony-tuininga
Copy link
Member

anthony-tuininga commented Sep 20, 2022

To be clear: unencrypted .pem for mTLS connections work just fine. The issue is that if the .pem file does NOT contain a private key, the code fails -- this occurs with one-way TLS, when only the certificates are included. The usual solution is to get the OS to recognize the certificates, but if this is not an option, some approach is needed to get Python to recognize them for this particular TLS connection.

As such, simply checking for the wallet_password value being None is insufficient. I'll give it some more thought as to how this can be accomplished!

@FrancoisNoyez FrancoisNoyez changed the title Improve TLS connection implementation to support use of unencrypted certificate .pem files Improve TLS connection implementation to support use of one way TLS certificates without needing OS recognition Sep 21, 2022
@FrancoisNoyez
Copy link
Author

Hi Anthony,

Ok, I see. Sorry for me using the wrong terminology here, I don't have speific knowledge about encryption protocols in general, and TLS connection in particular. I have updated the title of the issue, but not my first post.

Hm, ok. I agree that, ideally, the change that I suggested is not enough, insofar as the behavior of the function / of the library needs to be consistent overall, and that this change would need to be properly advertised / we would need to let people know how it works.
But maybe you think that this is insufficient for other reasons. In that case, I'm not sure to understand why. Would it be possible for you to explain this, please?

Anyway, thank you for considering it.

@anthony-tuininga
Copy link
Member

anthony-tuininga commented Sep 21, 2022

Looking further into this, I suspect it may be possible to just do this:

try:
    ssl_context.load_cert_chain(pem_file_name,
                                password=params._get_wallet_password())
except ssl.SSLError:
    pass

In other words, try to load the certificate chain from the supplied PEM file and simply ignore the error if it is unsuccessful. The error (as noted) isn't really all that helpful anyway! If one-way TLS is set up, it will work, and if 2-way TLS is required, a different error will be raised. I'm just checking internally to see what that looks like with an older database. Stay tuned!

@FrancoisNoyez
Copy link
Author

Hi Anthony,
So, was it possible for you to assess whether the change that you suggested to implement would be possible without breaking compatibility with older databases?

@anthony-tuininga
Copy link
Member

Not yet, unfortunately. I'm still waiting but will prod internally again. :-)

anthony-tuininga added a commit that referenced this issue Oct 18, 2022
than requiring OS recognition of certificates (#65).
@anthony-tuininga
Copy link
Member

I was finally able to test with an older database. When supplying an invalid password for an encrypted PEM file, instead of this error

oracledb.exceptions.OperationalError: DPY-6005: cannot connect to database. Connection failed with "[SSL] PEM lib (_ssl.c:3895)"

you will now get

oracledb.exceptions.OperationalError: DPY-6005: cannot connect to database. Connection failed with "[SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)"

And for your case, you can now supply a PEM file containing just certificates and this will be used to validate the server without requiring the OS to recognize the server certificate.

This patch will go into the next release of python-oracledb. Thanks for your patience!

@FrancoisNoyez
Copy link
Author

Hi Anthony,

Awesome, thank you!
I have tested out the code currently associated to the top of the 'main' branch (commit bb69402), and it works for me / for my use case.
Thank you for having taken this in consideration. If I understand properly, this will part of the 1.1.2 version? Or the 1.2.0 version?
Is there a way for me to be warned when a new version of this library will be released, or should I just regularly check the state of the repository for this project?

@anthony-tuininga
Copy link
Member

You're welcome. This will likely become part of 1.1.2, but it depends on a number of factors. You can "watch" this repository -- just for new releases if that is all you're interested in!

@FrancoisNoyez
Copy link
Author

Nice, did not know about this functionality of github, thank you!
Then it's all set, all that's left to do is to wait for the release : )

Should I let you close this issue, once the release has occurred? Or should I do it myself?

@anthony-tuininga
Copy link
Member

I usually add one more comment when the release is made and then close it, but if you prefer to close it now, that's fine, too!

@FrancoisNoyez
Copy link
Author

Ok, then no, I would prefer that you do as you usually do : )

@anthony-tuininga
Copy link
Member

This is part of oracledb 1.2.0 which was just released.

@FrancoisNoyez
Copy link
Author

Got it, I saw that, now things work great on my end, thank you : ) !

@rudolfnoe
Copy link

Hi Francois,
I'try to connect to an AWS RDS Oracle Instance but always get get the error mentioned above.
I copied the contents of https://truststore.pki.rds.amazonaws.com/eu-central-1/eu-central-1-bundle.pem into a file called ewallet.pem and set the appropriate wallet_location in the connect method.
But I still get the SSL-Handshake error.
This is my code:
connection = oracledb.connect(user='<usernam>', password=userpwd, host='...', port='..', protocol='tcps', sid='...', ssl_server_dn_match=False, wallet_location='path_to_ewallet_pem')
I'am using oracledb version 1.3.1.
Can you provide a running example please?
Thanks a lot

@FrancoisNoyez
Copy link
Author

Hi @rudolfnoe ,

I'm sorry, but I'm not a maintainer of this library, and now that the need that I had opened this issue for has been met, I have forgotten much about it.
To solve your issue, I would suggest to perform some experiments and review the documentation, and if that's not enough, then I would suggest opening an issue in this repository, by giving full context and info regarding the experiments that you would have performed.

@rudolfnoe
Copy link

Hi @FrancoisNoyez,
I solved the problem myself. The cause was a mismatch in the available cipher suites. AWS RDS applies the cipher SSL_RSA_WITH_AES_256_CBC_SHA by default which is not available in the default security context of the python SSL library as it assessed as insecure. When changing the RDS Cipher to a more secure one like TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 it works.

@FrancoisNoyez
Copy link
Author

Hi @rudolfnoe
I see, glad for you!
Out of curiosity, how did you do, in order to perform the change of cipher? Is it something that you did within the python code? Or something done in the environment in which the python program runs?

@rudolfnoe
Copy link

Hi @FrancoisNoyez,
see my answer in
#138

@FrancoisNoyez
Copy link
Author

Hi @rudolfnoe
Got it, thank you!

@harshshah1618
Copy link

Hello @rudolfnoe
i have the same error as you
can i know what is the final oracledb.connect() string you passed?
i did not understand how to use the ssl_context param in the new version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request patch available
Projects
None yet
Development

No branches or pull requests

4 participants