Uh oh!
There was an error while loading. Please reload this page.
Add python 3.12 and 3.13 support - #707
Conversation
blink1073
commented
Oct 4, 2023
The traceback on my fork is: kmip/tests/integration/conftest.py:49: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ kmip/pie/client.py:173: inopenself.proxy.open()
kmip/services/kmip_client.py:285: inopensix.reraise(*last_error)
.tox/integration/lib/python3.9/site-packages/six.py:719: inreraiseraisevaluekmip/services/kmip_client.py:274: inopenself.socket.connect((self.host, self.port))
/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/ssl.py:1376: inconnectself._real_connect(addr, False)
/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/ssl.py:1367: in_real_connectself.do_handshake()
__ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self=<ssl.SSLSocket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>block=False@_sslcopydocdefdo_handshake(self, block=False):
self._check_connected()
timeout=self.gettimeout()
try:
iftimeout==0.0andblock:
self.settimeout(None)
>self._sslobj.do_handshake()
Essl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificateverifyfailed: self-signedcertificate (_ssl.c:1129)
/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/ssl.py:1343: SSLCertVerificationError_ERRORatsetupofTestProxyKmipClientIntegration.test_x509_certificate_register_get_destroy_request=<SubRequest'simple'for<TestCaseFunctiontest_asymmetric_key_pair_create_get_destroy>>
@pytest.fixture(scope="class")
defsimple(request):
config=request.config.getoption("--config")
client=pclient.ProxyKmipClient(config=config)
>client.open()
kmip/tests/integration/conftest.py:49: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ kmip/pie/client.py:173: inopenself.proxy.open()
kmip/services/kmip_client.py:285: inopensix.reraise(*last_error)
.tox/integration/lib/python3.9/site-packages/six.py:719: inreraiseraisevaluekmip/services/kmip_client.py:274: inopenself.socket.connect((self.host, self.port))
/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/ssl.py:1376: inconnectself._real_connect(addr, False)
/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/ssl.py:1367: in_real_connectself.do_handshake()
__ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ self=<ssl.SSLSocket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0>block=False@_sslcopydocdefdo_handshake(self, block=False):
self._check_connected()
timeout=self.gettimeout()
try:
iftimeout==0.0andblock:
self.settimeout(None)
>self._sslobj.do_handshake()
Essl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificateverifyfailed: self-signedcertificate (_ssl.c:1129)
/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/ssl.py:1343: SSLCertVerificationError |
| context.check_hostname = False | ||
| if self.certfile: | ||
| context.load_cert_chain(self.certfile, self.keyfile) | ||
| self.socket = context.wrap_socket( |
Check failure
Code scanning / CodeQL
Use of insecure SSL/TLS version
| keyfile = self.config.settings.get('key_path') | ||
| context.load_cert_chain(certfile, keyfile=keyfile) | ||
| self._socket = context.wrap_socket( |
Check failure
Code scanning / CodeQL
Use of insecure SSL/TLS version
s-t-e-v-e-n-k
commented
Mar 28, 2024
The problem with your mocking is that you can't mock I've edited the test changes for your patch (and not your code changes, which looks good) thusly: And I've confirmed the tests pass with Python 3.9-3.12. |
This reverts commit 4618b1d.
blink1073
commented
Mar 29, 2024
Thanks @s-t-e-v-e-n-k, new build in progress on my fork. |
blink1073
commented
Mar 29, 2024
Still no joy: |
avikivity
commented
Jun 2, 2024
@blink1073 were you able to make this work? |
blink1073
commented
Jun 3, 2024
No, I haven't been able to figure out the testing portion. |
| def _create_socket(self, sock): | ||
| self.socket = ssl.wrap_socket( | ||
| purpose = ssl.Purpose.SERVER_AUTH | ||
| context = ssl.create_default_context(purpose=purpose, capath=self.ca_certs) |
There was a problem hiding this comment.
This should be cafile=... instead of capath=..., because the underlying configuration parameter points to a file.
| self._socket = ssl.wrap_socket( | ||
| purpose = ssl.Purpose.CLIENT_AUTH | ||
| capath = self.config.settings.get('ca_path') | ||
| context = ssl.create_default_context(purpose=purpose, capath=capath) |
There was a problem hiding this comment.
This should be cafile=capath instead of capath=capath, because the underlying configuration parameter points to a file. (The naming is unfortunately inconsistent between the Python ssl module and pykmip.)
There was a problem hiding this comment.
This no longer pays attention to the configuration settings self.cert_reqs and self.ssl_versions. That's probably okay in practice, since the defaults are good, but these settings are documented, so they should work.
One option might be to not use ssl.create_default_context() and instead use ssl.SSLContext directly and apply these settings. Like
context=ssl.SSLContext(self.ssl_version)
context.verify_mode=self.cert_reqsifself.ca_certs:
context.load_verify_locations(self.ca_certs)This is just about as much code as before but it reproduces the previous behavior more precisely.
There was a problem hiding this comment.
Similar to the client, we should make sure that this change does not lose any previously working configuration settings. I see for example that ssl_version=self.auth_suite.protocol and ciphers=self.auth_suite.ciphers don't get used anymore.
| self._socket = ssl.wrap_socket( | ||
| purpose = ssl.Purpose.CLIENT_AUTH | ||
| capath = self.config.settings.get('ca_path') | ||
| context = ssl.create_default_context(purpose=purpose, capath=capath) |
There was a problem hiding this comment.
You must set
context.verify_mode=ssl.CERT_REQUIREDafter creating context. This matches what the previous code did. Without this, the server won't ask the client to send a certificate, and without a client certificate this will later fail at higher levels (such as
PyKMIP/kmip/services/server/session.py
Line 144 in 4d3b5a5
blink1073
commented
Jul 25, 2024
Thanks @petere! I believe I've addressed your feedback. |
| context.verify_mode = self.cert_reqs | ||
| if self.ca_certs: | ||
| context.load_verify_locations(self.ca_certs) | ||
| context.check_hostname = False |
There was a problem hiding this comment.
This line doesn't appear to be needed. Probably left over from a previous version that used create_default_context().
| if self.ca_certs: | ||
| context.load_verify_locations(self.ca_certs) | ||
| context.check_hostname = False | ||
| if self.certfile: |
There was a problem hiding this comment.
I'm testing combinations of "forgetting" to specify certfile or keyfile in the configuration file. With this code, if you specify certfile but not keyfile, you'll get an exception from load_cert_chain. If you specify keyfile but not certfile, this code is skipped and you'll get whatever the SSL stack ends up deciding. The old module-level wrap_socket had an additional check
ifkeyfileandnotcertfile:
raiseValueError("certfile must be specified")to prevent this. Maybe this would be good to have here as well.
| self._socket = ssl.wrap_socket( | ||
| cafile = self.config.settings.get('ca_path') | ||
| context = ssl.SSLContext(self.ssl_version) |
There was a problem hiding this comment.
This should be
context=ssl.SSLContext(self.auth_suite.protocol)(wrongly copy-pasted from client code?)
| cafile = self.config.settings.get('ca_path') | ||
| context = ssl.SSLContext(self.ssl_version) | ||
| context.verify_mode = ssl.CERT_REQUIRED | ||
| if auth_suite_ciphers: |
There was a problem hiding this comment.
This should be self.auth_suite.ciphers. I'm not sure exactly what the relationship between that and auth_suite_ciphers is, but this one crashes.
| context.load_verify_locations(cafile) | ||
| certfile = self.config.settings.get('certificate_path') | ||
| if certfile: |
There was a problem hiding this comment.
As with the client, it's worth checking here about how different combinations of not specifying certificate or key behave. For example, the old module-level wrap_socket() had a check
ifserver_sideandnotcertfile:
raiseValueError("certfile must be specified for server-side ""operations")so omitting the certificate would have been a hard error.
There was a problem hiding this comment.
I think what I had in mind was like
if certfile:
keyfile = self.config.settings.get('key_path')
context.load_cert_chain(certfile, keyfile=keyfile)
+ else:+ raise ValueError("certfile must be specified for server-side operations")There was a problem hiding this comment.
I instead let the context raise an appropriate error. This has the benefit of letting us mock the context behavior in the tests.
blink1073
commented
Nov 14, 2024
@petere is there anything else you'd like me to try? |
petere
commented
Nov 27, 2024
Other than the single comment I just added (which I just got my looking at my local copy, but it's been a while since I played with this), I am content with this version. How we get from that to getting this merged and released, I don't know. |
blink1073
commented
Dec 2, 2024
This is now ready for review. cc @arp102. |
blink1073
commented
Dec 2, 2024
The workflows are all passing on my fork: https://github.com/blink1073/PyKMIP/actions/runs/12119149288?pr=1 |
tomamoto
commented
May 9, 2025
@arp102 Are you able to merge this PR, and if not, what else is needed? Getting 3.12 support in master branch would be great, and seeing a new release to pypi would be even nicer. |
wdelgenio
commented
Jul 10, 2025
@arp102@BourgoisMickael@petere@PeterHamilton |
BourgoisMickael
commented
Jul 11, 2025
I'm not related to the project I just want to see it merged |
wdelgenio
commented
Jul 14, 2025
Looks like this repo is no longer maintained, might be time for a fork or a switch to a different library. |
(cherry picked from commit b76e74e)
Fixes#706