Skip to contentSkip to conversation

Fix memory leak in x509_verify_cert_ku()

PATCH In review Steffan Karger 4 participants 4 messages May 7, 2017 – May 8, 2017

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Fix memory leak in x509_verify_cert_ku()

If keyUsage was only required to be present, but no specific value was required, we would omit to free the extracted string. This happens as of 2.4.1, if --remote-cert-tls is used. In that case we leak a bit of memory on each TLS (re)negotiation.

---
 Changes.rst                      | 9 +++++++++
 src/openvpn/ssl_verify_openssl.c | 1 +
 2 files changed, 10 insertions(+)
Changes.rst +9 -0
index c1583b3..3dba7e0 100644
@@ -318,3 +318,12 @@ Version 2.4.1
   ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage
   extension instead.  Make sure your certificates carry these to be able to
   use ``--remote-cert-tls``.
+
+
+Version 2.4.2
+=============
+
+Bugfixes
+--------
+- Fix memory leak introduced in 2.4.1: if --remote-cert-tls is used, we leaked
+  some memory on each TLS (re)negotiation.
src/openvpn/ssl_verify_openssl.c +1 -0
index 54eadbd..337729c 100644
@@ -599,6 +599,7 @@ x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku,
     if (expected_ku[0] == OPENVPN_KU_REQUIRED)
     {
         /* Extension required, value checked by TLS library */
+        ASN1_BIT_STRING_free(ku);
         return SUCCESS;
     }
 
Signature · 1 line
2.7.4
#1 lore raw
Quoted 33 lines · Steffan Karger

If keyUsage was only required to be present, but no specific value was required, we would omit to free the extracted string. This happens as of 2.4.1, if --remote-cert-tls is used. In that case we leak a bit of memory on each TLS (re)negotiation.

---
 Changes.rst                      | 9 +++++++++
 src/openvpn/ssl_verify_openssl.c | 1 +
 2 files changed, 10 insertions(+)
Changes.rst +9 -0
index c1583b3..3dba7e0 100644
@@ -318,3 +318,12 @@ Version 2.4.1
   ``--remote-cert-tls`` uses the far more common keyUsage and extendedKeyUsage
   extension instead.  Make sure your certificates carry these to be able to
   use ``--remote-cert-tls``.
+
+
+Version 2.4.2
+=============
+
+Bugfixes
+--------
+- Fix memory leak introduced in 2.4.1: if --remote-cert-tls is used, we leaked
+  some memory on each TLS (re)negotiation.
src/openvpn/ssl_verify_openssl.c +0 -0
index 54eadbd..337729c 100644

src/openvpn/ssl_verify_openssl.c x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku, · line 605

Quoted 7 lines
src/openvpn/ssl_verify_openssl.c +1 -0
@@ -599,6 +599,7 @@ x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku,
     if (expected_ku[0] == OPENVPN_KU_REQUIRED)
     {
         /* Extension required, value checked by TLS library */
+        ASN1_BIT_STRING_free(ku);
         return SUCCESS;
     }
 

Just some nit-pick from me. Below is a larger fragment of this function (I've done some word-wrapping to make it slim enough for the mail).

--------------------------------------------------------------------
result_t
x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku,
int expected_len)

{
    ASN1_BIT_STRING *ku = X509_get_ext_d2i(x509, NID_key_usage,
                                           NULL, NULL);

    if (ku == NULL)
    {
        msg(D_TLS_ERRORS, "Certificate does not have key "
                           "usage extension");
        return FAILURE;
    }

    if (expected_ku[0] == OPENVPN_KU_REQUIRED)
    {
        /* Extension required, value checked by TLS library */
        ASN1_BIT_STRING_free(ku);   /** new line **/
        return SUCCESS;
    }

    unsigned nku = 0;
    for (size_t i = 0; i < 8; i++)

--------------------------------------------------------------------

Wouldn't it make more sense to rather move the
if (expected_ku[0] == OPENVPN_KU_REQUIRED) block above the
ASN1_BIT_STRING *ku declaration? Like this:

--------------------------------------------------------------------
result_t
x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku,
int expected_len)

{
    if (expected_ku[0] == OPENVPN_KU_REQUIRED)
    {
        /* Extension required, value checked by TLS library */
        return SUCCESS;
    }

    ASN1_BIT_STRING *ku = X509_get_ext_d2i(x509, NID_key_usage,
                                           NULL, NULL);
    if (ku == NULL)
    {
        msg(D_TLS_ERRORS, "Certificate does not have key "
                           "usage extension");
        return FAILURE;
    }

    unsigned nku = 0;
    for (size_t i = 0; i < 8; i++)

--------------------------------------------------------------------

Or is the implicit check that ku != NULL important when checking OPENVPN_KU_REQUIRED ?

Except of that, it looks fine and I'm willing to ACK it.

Signature · 4 lines
kind regards,

David Sommerseth
OpenVPN Technologies, Inc
#2 lore raw

Hi,

Quoted 54 lines · David Sommerseth

On 07/05/17 13:01, Steffan Karger wrote:
--------------------------------------------------------------------
result_t
x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku,
int expected_len)

{
    ASN1_BIT_STRING *ku = X509_get_ext_d2i(x509, NID_key_usage,
                                           NULL, NULL);

    if (ku == NULL)
    {
        msg(D_TLS_ERRORS, "Certificate does not have key "
                           "usage extension");
        return FAILURE;
    }

    if (expected_ku[0] == OPENVPN_KU_REQUIRED)
    {
        /* Extension required, value checked by TLS library */
        ASN1_BIT_STRING_free(ku);   /** new line **/
        return SUCCESS;
    }

    unsigned nku = 0;
    for (size_t i = 0; i < 8; i++)

--------------------------------------------------------------------

Wouldn't it make more sense to rather move the
if (expected_ku[0] == OPENVPN_KU_REQUIRED) block above the
ASN1_BIT_STRING *ku declaration? Like this:

--------------------------------------------------------------------
result_t
x509_verify_cert_ku(X509 *x509, const unsigned *const expected_ku,
int expected_len)

{
    if (expected_ku[0] == OPENVPN_KU_REQUIRED)
    {
        /* Extension required, value checked by TLS library */
        return SUCCESS;
    }

    ASN1_BIT_STRING *ku = X509_get_ext_d2i(x509, NID_key_usage,
                                           NULL, NULL);
    if (ku == NULL)
    {
        msg(D_TLS_ERRORS, "Certificate does not have key "
                           "usage extension");
        return FAILURE;
    }

    unsigned nku = 0;
    for (size_t i = 0; i < 8; i++)
Quoted 4 lines

--------------------------------------------------------------------

Or is the implicit check that ku != NULL important when checking OPENVPN_KU_REQUIRED ?

Exactly. OPENVPN_KU_REQUIRED means that we need *some* ku, so we need to first get ku, and error out if it's NULL. At the location in my patch, we know that it's non-null, so it's good.

-Steffan

#3 lore raw
In reply to Steffan Karger

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Looking good to me. ACK!

Your patch has been applied to the following branches

commit 7b94d3bbbea46efcea12e1df24da52fe508d0173 (master) commit d7a13af789daecf38fb6a3ca2d6e6cf0ab939a73 (release/2.4)

Author: Steffan Karger
Date:   Sun May 7 13:01:18 2017 +0200
     Fix memory leak in x509_verify_cert_ku()

     Signed-off-by: Steffan Karger <[email protected]...>
     Acked-by: David Sommerseth <[email protected]...>
     Message-Id: <[email protected]...>
     URL: https://www.mail-archive.com/[email protected]/msg14563.html
     Signed-off-by: David Sommerseth <[email protected]...>

- --
kind regards,

David Sommerseth

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)

iQIcBAEBCAAGBQJZEJswAAoJEIbPlEyWcf3ys1oP/jeCx+xu9GRMbcgR3hudPHQY c7ujhO0jvRMbWdaFtdNcX9QDfVSTCHAnAyGSnI/z33oQIz45uI3PS+Z3O3KwrOdQ 2ZI5UnG1l/QlBvdDvsD9dCNxTIzTXwHLPAxLtL4KsRMlefZPPYC5W9ziMkEBcYvr wLEShlK8IFx3zpU+wpND9xvBTA71wPQmzKqtJYv6O7qI+7FZUEphFGDmVdu4hPxu /owH6BCBqxCK9Tkcg7tJeMfIdZ+1dQz1fG6rLz/HVtDdRDq/FtT/3wISTMqKmmsL ugwGm39v3QaDuHQzOyCr2ORX6Ht44AbMwjgyDnblg9rWvsRy/wWCOFSaJqQdPQVV BquYDh3tALcCkCMByMQDnXZkeKww+3bIxOEagj1f0C+RjzzUT87OoWm/qOj/jLs+ fvEnZTf4Zeh5Icx2Xd0kEHzM2+Y9q06qm6iZoAgDI383mvgTcQNXCzAHQijEsZC1 mlJ65GWQcdgAB+A3vUPuy1qoUSyB5ZGucCLebGpn4THyzeMC3ihWn1shxlH66XoL GeKvuJmyRWjTItuLg0CHles1/11XQSCeBqrkJKgKS51IOistpP2Pgy6tyS5POIzn Q/DP7O+n3g3ezU/mB7UQ2/ctpk938iq/ecMEtD3/qH8MxQd8Abq2QwbjBAj6gT6N tiHhKxFdQTy9bw/uSVjZ
=gRag
-----END PGP SIGNATURE-----