summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2017-07-20 10:45:54 +0200
committerHynek Schlawack <hs@ox.cx>2017-07-20 10:45:54 +0200
commit59d26251efd8a2a08abd9029018194430f7f25ca (patch)
tree79a33413aaf11648d18f988e23d81456e52f4b26
parent8102128e6ad83dcbb3567dd372cdd39c9a8fab44 (diff)
downloadpyopenssl-59d26251efd8a2a08abd9029018194430f7f25ca.tar.gz
(EC)DSA signature fix (#670)
* Write a test - signatures with EC keys (#609) * Ask for signature length before allocating a buffer. This fixes a potential heap buffer overflow that may happen when a signature is longer than the private key, as with X9.62 ECDSA (#609). * change approach to EVP_PKEY_size and add changelog * add a small assert
-rw-r--r--CHANGELOG.rst2
-rw-r--r--src/OpenSSL/crypto.py7
-rw-r--r--tests/test_crypto.py41
3 files changed, 47 insertions, 3 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 738ceab..ba9a124 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -27,6 +27,8 @@ Changes:
- Fixed a bug causing ``Context.set_default_verify_paths()`` to not work with cryptography ``manylinux1`` wheels on Python 3.x.
`#665 <https://github.com/pyca/pyopenssl/pull/665>`_
+- Fixed a crash with (EC)DSA signatures in some cases.
+ `#670 <https://github.com/pyca/pyopenssl/pull/670>`_
----
diff --git a/src/OpenSSL/crypto.py b/src/OpenSSL/crypto.py
index 20cf183..4f7e4d8 100644
--- a/src/OpenSSL/crypto.py
+++ b/src/OpenSSL/crypto.py
@@ -2801,9 +2801,10 @@ def sign(pkey, data, digest):
_lib.EVP_SignInit(md_ctx, digest_obj)
_lib.EVP_SignUpdate(md_ctx, data, len(data))
- pkey_length = (PKey.bits(pkey) + 7) // 8
- signature_buffer = _ffi.new("unsigned char[]", pkey_length)
- signature_length = _ffi.new("unsigned int*")
+ length = _lib.EVP_PKEY_size(pkey._pkey)
+ _openssl_assert(length > 0)
+ signature_buffer = _ffi.new("unsigned char[]", length)
+ signature_length = _ffi.new("unsigned int *")
final_result = _lib.EVP_SignFinal(
md_ctx, signature_buffer, signature_length, pkey._pkey)
_openssl_assert(final_result == 1)
diff --git a/tests/test_crypto.py b/tests/test_crypto.py
index 47a914d..2f8a70d 100644
--- a/tests/test_crypto.py
+++ b/tests/test_crypto.py
@@ -544,6 +544,29 @@ zo0MUVPQgwJ3aJtNM1QMOQUayCrRwfklg+D/rFSUwEUqtZh7fJDiFqz3
-----END PRIVATE KEY-----
"""
+ec_root_key_pem = b"""-----BEGIN EC PRIVATE KEY-----
+MIGlAgEBBDEAz/HOBFPYLB0jLWeTpJn4Yc4m/C4mdWymVHBjOmnwiPHKT326iYN/
+ZhmSs+RM94RsoAcGBSuBBAAioWQDYgAEwE5vDdla/nLpWAPAQ0yFGqwLuw4BcN2r
+U+sKab5EAEHzLeceRa8ffncYdCXNoVsBcdob1y66CFZMEWLetPTmGapyWkBAs6/L
+8kUlkU9OsE+7IVo4QQJkgV5gM+Dim1XE
+-----END EC PRIVATE KEY-----
+"""
+
+ec_root_cert_pem = b"""-----BEGIN CERTIFICATE-----
+MIICLTCCAbKgAwIBAgIMWW/hwTl6ufz6/WkCMAoGCCqGSM49BAMDMFgxGDAWBgNV
+BAMTD1Rlc3RpbmcgUm9vdCBDQTEQMA4GA1UEChMHVGVzdGluZzEQMA4GA1UEBxMH
+Q2hpY2FnbzELMAkGA1UECBMCSUwxCzAJBgNVBAYTAlVTMCAXDTE3MDcxOTIyNDgz
+M1oYDzk5OTkxMjMxMjM1OTU5WjBYMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0Ex
+EDAOBgNVBAoTB1Rlc3RpbmcxEDAOBgNVBAcTB0NoaWNhZ28xCzAJBgNVBAgTAklM
+MQswCQYDVQQGEwJVUzB2MBAGByqGSM49AgEGBSuBBAAiA2IABMBObw3ZWv5y6VgD
+wENMhRqsC7sOAXDdq1PrCmm+RABB8y3nHkWvH353GHQlzaFbAXHaG9cuughWTBFi
+3rT05hmqclpAQLOvy/JFJZFPTrBPuyFaOEECZIFeYDPg4ptVxKNDMEEwDwYDVR0T
+AQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwQAMB0GA1UdDgQWBBSoTrF0H2m8RDzB
+MnY2KReEPfz7ZjAKBggqhkjOPQQDAwNpADBmAjEA3+G1oVCxGjYX4iUN93QYcNHe
+e3fJQJwX9+KsHRut6qNZDUbvRbtO1YIAwB4UJZjwAjEAtXCPURS5A4McZHnSwgTi
+Td8GMrwKz0557OxxtKN6uVVy4ACFMqEw0zN/KJI1vxc9
+-----END CERTIFICATE-----"""
+
@pytest.fixture
def x509_data():
@@ -3697,6 +3720,24 @@ class TestSignVerify(object):
WARNING_TYPE_EXPECTED
) == str(w[-1].message))
+ def test_sign_verify_ecdsa(self):
+ """
+ `sign` generates a cryptographic signature which `verify` can check.
+ ECDSA Signatures in the X9.62 format may have variable length,
+ different from the length of the private key.
+ """
+ content = (
+ b"It was a bright cold day in April, and the clocks were striking "
+ b"thirteen. Winston Smith, his chin nuzzled into his breast in an "
+ b"effort to escape the vile wind, slipped quickly through the "
+ b"glass doors of Victory Mansions, though not quickly enough to "
+ b"prevent a swirl of gritty dust from entering along with him."
+ ).decode("ascii")
+ priv_key = load_privatekey(FILETYPE_PEM, ec_root_key_pem)
+ cert = load_certificate(FILETYPE_PEM, ec_root_cert_pem)
+ sig = sign(priv_key, content, "sha1")
+ verify(cert, sig, content, "sha1")
+
def test_sign_nulls(self):
"""
`sign` produces a signature for a string with embedded nulls.