cryptography
cryptography copied to clipboard
DH exchange fails in 42.0.0
The following code works with cryptography 41.0.7 and earlier, and fails with 42.0.0 and later:
from cryptography.hazmat.primitives.serialization import load_pem_public_key
key = b"""-----BEGIN PUBLIC KEY-----
MIICJTCCARcGCSqGSIb3DQEDATCCAQgCggEBAP//////////yQ/aoiFowjTExmKL
gNwc0SkCTgiKZ8x0Agu+pjsTmyJRSgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVt
bVHCReSFtXZiXn7G9ExC6aY37WsL/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR
7ORbPcIAfLihY78FmNpINhxV05ppFj+o/STPX4NlXSPco62WHGLzViCFUrue1SkH
cJaWbWcMNU5KvJgE8XRsCMoYIXwykF5GLjbOO+OedywYDoYDmyeDouwHoo+1xV3w
b0xSyd4ry/aVWBcYOZVJfOqVauUV0iYYmPoFEBVyjlqKrKpo//////////8CAQID
ggEGAAKCAQEAoely6vSHw+/Q3zGYLaJj7eeQkfd25K8SvtC+FMY9D7jwS4g71pyr
U3FJ98Fi45Wdksh+d4u7U089trF5Xbgui29bZ0HcQZtfHEEz0Mh69tkipCm2/QIj
6eDlo6sPk9hhhvgg4MMGiWKhCtHrub3x1FHdmf7KjOhrGeb5apiudo7blGFzGhZ3
NFnbff+ArVNd+rdVmSoZn0aMhXRConlDu/44IYe5/24VLl7G+BzZlIZO4P2M83fd
mBOvR13cmYssQjEFTbaZVQvQHa3t0+aywfdCgsXGmTTK6QDCBP8D+vf1bmhEswzs
oYn1GLtJ3VyYyMBPDBomd2ctchZgTzsX1w==
-----END PUBLIC KEY-----"""
peer_key = load_pem_public_key(key)
params = peer_key.parameters()
private_key = params.generate_private_key()
# Create a shared secret
shared_secret = private_key.exchange(peer_key)
The exchange call fails with a cryptic in 42.0.0 and later
shared_secret = private_key.exchange(peer_key)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: Error computing shared key.
If I swap out OpenSSL versions (e.g. 3.1.4 with cryptography 42.0.0) the results are the same, so the issue seems to be in the cryptography code.
I have tracked this down to evp_pkey_export_to_provider
where, in 42.0.0 the key types are DHX and DH, whereas earlier they seem to be DH and DH. I suspect the issue is in the transition of load_pem_public_key
to rust in 42.0.0.
Any insights appreciated.
There is a partial workaround for this. Reconstruct the peer key as follows:
# Reconstruct the public key
peer_key = DHPublicNumbers(peer_key.public_numbers().y, peer_key.parameters().parameter_numbers()).public_key()
However in my case the server side is unhappy with the result
This issue exists in keys generated by cryptography 41.0.7 and loaded into 42.0.0. If the following code is run on 41.0.7 to generate a key (to stdout)
from cryptography.hazmat.primitives.serialization import load_pem_parameters
from cryptography.hazmat.primitives import serialization
pem_params = b"""-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb
IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft
awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT
mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh
fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq
5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg==
-----END DH PARAMETERS-----"""
params = load_pem_parameters(pem_params)
pk = params.generate_private_key()
k = pk.public_key()
x = k.public_bytes(encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo)
print(x.decode())
And then the following is run on 42.0.0 to load the same key (from stdin), it will fail
import sys
from cryptography.hazmat.primitives.serialization import load_pem_public_key
public_key = load_pem_public_key(sys.stdin.read().encode())
params = public_key.parameters()
private_key = params.generate_private_key()
shared_key = private_key.exchange(public_key)
This is definitely a bug, though how we should fix it is not immediately obvious to me.
On Sun, Apr 21, 2024, 10:24 AM Dave Boutcher @.***> wrote:
This issue exists in keys generated by cryptography 41.0.7 and loaded into 42.0.0. If the following code is run on 41.0.7 to generate a key (to stdout)
from cryptography.hazmat.primitives.serialization import load_pem_parameters from cryptography.hazmat.primitives import serialization
pem_params = b"""-----BEGIN DH PARAMETERS----- MIIBCAKCAQEA///////////JD9qiIWjCNMTGYouA3BzRKQJOCIpnzHQCC76mOxOb IlFKCHmONATd75UZs806QxswKwpt8l8UN0/hNW1tUcJF5IW1dmJefsb0TELppjft awv/XLb0Brft7jhr+1qJn6WunyQRfEsf5kkoZlHs5Fs9wgB8uKFjvwWY2kg2HFXT mmkWP6j9JM9fg2VdI9yjrZYcYvNWIIVSu57VKQdwlpZtZww1Tkq8mATxdGwIyhgh fDKQXkYuNs474553LBgOhgObJ4Oi7Aeij7XFXfBvTFLJ3ivL9pVYFxg5lUl86pVq 5RXSJhiY+gUQFXKOWoqsqmj//////////wIBAg== -----END DH PARAMETERS-----"""
params = load_pem_parameters(pem_params) pk = params.generate_private_key() k = pk.public_key() x = k.public_bytes(encoding=serialization.Encoding.PEM, format=serialization.PublicFormat.SubjectPublicKeyInfo) print(x.decode())
And then the following is run on 42.0.0 to load the same key (from stdin), it will fail
import sys from cryptography.hazmat.primitives.serialization import load_pem_public_key
public_key = load_pem_public_key(sys.stdin.read().encode())
params = public_key.parameters()
private_key = params.generate_private_key()
shared_key = private_key.exchange(public_key)
— Reply to this email directly, view it on GitHub https://github.com/pyca/cryptography/issues/10790#issuecomment-2068063349, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAAAGBHU2GHNUNAQKHSM3MLY6PD2HAVCNFSM6AAAAABGCA2FF2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANRYGA3DGMZUHE . You are receiving this because you are subscribed to this thread.Message ID: @.***>
PR proposed.....passes all the tests and Works For Me™
@alex is there a process for requesting a review of a PR? Or an irc/discord/mailing list thats worth joining?
Reviewing is on my TODO list, hopefully will have time this weekend.
On Fri, Apr 26, 2024 at 11:30 AM Dave Boutcher @.***> wrote:
@alex is there a process for requesting a review of a PR? Or an irc/discord/mailing list thats worth joining?
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you were mentioned.Message ID: @.***>
-- All that is necessary for evil to succeed is for good people to do nothing.
The more I poke at this, the more I'm convinced this is an OpenSSL bug: https://github.com/openssl/openssl/issues/24804