src/openvpn/openssl_compat.h
6554ac9f
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single TCP/UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
  *  Copyright (C) 2002-2017 OpenVPN Technologies, Inc. <sales@openvpn.net>
  *  Copyright (C) 2010-2017 Fox Crypto B.V. <openvpn@fox-it.com>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
6554ac9f
  */
 
 /**
  * @file OpenSSL compatibility stub
  *
  * This file provide compatibility stubs for the OpenSSL libraries
  * prior to version 1.1. This version introduces many changes in the
  * library interface, including the fact that various objects and
  * structures are not fully opaque.
  */
 
 #ifndef OPENSSL_COMPAT_H_
 #define OPENSSL_COMPAT_H_
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
09776c5b
 #include "buffer.h"
 
6554ac9f
 #include <openssl/ssl.h>
f05665df
 #include <openssl/x509.h>
6554ac9f
 
c481ef00
 #if !defined(HAVE_EVP_MD_CTX_RESET)
 /**
  * Reset a message digest context
  *
  * @param ctx                 The message digest context
  * @return                    1 on success, 0 on error
  */
 static inline int
 EVP_MD_CTX_reset(EVP_MD_CTX *ctx)
 {
     EVP_MD_CTX_cleanup(ctx);
     return 1;
 }
 #endif
 
 #if !defined(HAVE_EVP_MD_CTX_FREE)
 /**
  * Free an existing message digest context
  *
  * @param ctx                 The message digest context
  */
 static inline void
 EVP_MD_CTX_free(EVP_MD_CTX *ctx)
 {
     free(ctx);
 }
 #endif
 
 #if !defined(HAVE_EVP_MD_CTX_NEW)
 /**
  * Allocate a new message digest object
  *
  * @return                    A zero'ed message digest object
  */
 static inline EVP_MD_CTX *
 EVP_MD_CTX_new(void)
 {
     EVP_MD_CTX *ctx = NULL;
     ALLOC_OBJ_CLEAR(ctx, EVP_MD_CTX);
     return ctx;
 }
 #endif
 
aba98e90
 #if !defined(HAVE_HMAC_CTX_RESET)
 /**
  * Reset a HMAC context
  *
64b8a4ae
  * OpenSSL 1.1+ removes APIs HMAC_CTX_init() and HMAC_CTX_cleanup()
  * and replace them with a single call that does a cleanup followed
  * by an init. A proper _reset() for OpenSSL < 1.1 should perform
  * a similar set of operations.
  *
  * It means that before we kill a HMAC context, we'll have to cleanup
  * again, as we probably have allocated a few resources when we forced
  * an init.
  *
aba98e90
  * @param ctx                 The HMAC context
  * @return                    1 on success, 0 on error
  */
 static inline int
 HMAC_CTX_reset(HMAC_CTX *ctx)
 {
     HMAC_CTX_cleanup(ctx);
64b8a4ae
     HMAC_CTX_init(ctx);
aba98e90
     return 1;
 }
 #endif
 
 #if !defined(HAVE_HMAC_CTX_FREE)
 /**
64b8a4ae
  * Cleanup and free an existing HMAC context
aba98e90
  *
  * @param ctx                 The HMAC context
  */
 static inline void
64b8a4ae
 HMAC_CTX_free(HMAC_CTX *ctx)
aba98e90
 {
64b8a4ae
     HMAC_CTX_cleanup(ctx);
     free(ctx);
aba98e90
 }
 #endif
 
 #if !defined(HAVE_HMAC_CTX_NEW)
 /**
  * Allocate a new HMAC context object
  *
  * @return                    A zero'ed HMAC context object
  */
 static inline HMAC_CTX *
 HMAC_CTX_new(void)
 {
     HMAC_CTX *ctx = NULL;
     ALLOC_OBJ_CLEAR(ctx, HMAC_CTX);
     return ctx;
 }
 #endif
 
6554ac9f
 #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB_USERDATA)
 /**
  * Fetch the default password callback user data from the SSL context
  *
  * @param ctx                SSL context
  * @return                   The password callback user data
  */
 static inline void *
 SSL_CTX_get_default_passwd_cb_userdata(SSL_CTX *ctx)
 {
     return ctx ? ctx->default_passwd_callback_userdata : NULL;
 }
 #endif
 
 #if !defined(HAVE_SSL_CTX_GET_DEFAULT_PASSWD_CB)
 /**
  * Fetch the default password callback from the SSL context
  *
  * @param ctx                SSL context
  * @return                   The password callback
  */
 static inline pem_password_cb *
 SSL_CTX_get_default_passwd_cb(SSL_CTX *ctx)
 {
     return ctx ? ctx->default_passwd_callback : NULL;
 }
 #endif
 
17d1ab90
 #if !defined(HAVE_X509_GET0_PUBKEY)
 /**
  * Get the public key from a X509 certificate
  *
  * @param x                  X509 certificate
  * @return                   The certificate public key
  */
 static inline EVP_PKEY *
 X509_get0_pubkey(const X509 *x)
 {
     return (x && x->cert_info && x->cert_info->key) ?
            x->cert_info->key->pkey : NULL;
 }
 #endif
 
f05665df
 #if !defined(HAVE_X509_STORE_GET0_OBJECTS)
 /**
  * Fetch the X509 object stack from the X509 store
  *
  * @param store              X509 object store
  * @return                   the X509 object stack
  */
 static inline STACK_OF(X509_OBJECT) *
 X509_STORE_get0_objects(X509_STORE *store)
 {
     return store ? store->objs : NULL;
 }
 #endif
 
47191f49
 #if !defined(HAVE_X509_OBJECT_FREE)
 /**
  * Destroy a X509 object
  *
  * @param obj                X509 object
  */
 static inline void
 X509_OBJECT_free(X509_OBJECT *obj)
 {
     if (obj)
     {
         X509_OBJECT_free_contents(obj);
         OPENSSL_free(obj);
     }
 }
 #endif
 
 #if !defined(HAVE_X509_OBJECT_GET_TYPE)
 /**
  * Get the type of an X509 object
  *
  * @param obj                X509 object
  * @return                   The underlying object type
  */
 static inline int
 X509_OBJECT_get_type(const X509_OBJECT *obj)
 {
     return obj ? obj->type : X509_LU_FAIL;
 }
 #endif
 
b8ca5bc3
 #if !defined(HAVE_EVP_PKEY_GET0_RSA)
 /**
  * Get the RSA object of a public key
  *
  * @param pkey                Public key object
  * @return                    The underlying RSA object
  */
 static inline RSA *
 EVP_PKEY_get0_RSA(EVP_PKEY *pkey)
 {
e603afab
     return (pkey && pkey->type == EVP_PKEY_RSA) ? pkey->pkey.rsa : NULL;
b8ca5bc3
 }
 #endif
 
bb23eca8
 #if !defined(HAVE_EVP_PKEY_GET0_EC_KEY) && !defined(OPENSSL_NO_EC)
 /**
  * Get the EC_KEY object of a public key
  *
  * @param pkey                Public key object
  * @return                    The underlying EC_KEY object
  */
 static inline EC_KEY *
 EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
 {
e603afab
     return (pkey && pkey->type == EVP_PKEY_EC) ? pkey->pkey.ec : NULL;
bb23eca8
 }
 #endif
 
b8ca5bc3
 #if !defined(HAVE_EVP_PKEY_ID)
 /**
  * Get the PKEY type
  *
  * @param pkey                Public key object
  * @return                    The key type
  */
 static inline int
 EVP_PKEY_id(const EVP_PKEY *pkey)
 {
     return pkey ? pkey->type : EVP_PKEY_NONE;
 }
 #endif
 
 #if !defined(HAVE_EVP_PKEY_GET0_DSA)
 /**
  * Get the DSA object of a public key
  *
  * @param pkey                Public key object
  * @return                    The underlying DSA object
  */
 static inline DSA *
 EVP_PKEY_get0_DSA(EVP_PKEY *pkey)
 {
e603afab
     return (pkey && pkey->type == EVP_PKEY_DSA) ? pkey->pkey.dsa : NULL;
b8ca5bc3
 }
 #endif
 
f7780af6
 #if !defined(HAVE_RSA_SET_FLAGS)
 /**
  * Set the RSA flags
  *
  * @param rsa                 The RSA object
  * @param flags               New flags value
  */
 static inline void
 RSA_set_flags(RSA *rsa, int flags)
 {
     if (rsa)
     {
         rsa->flags = flags;
     }
 }
 #endif
 
 #if !defined(HAVE_RSA_GET0_KEY)
 /**
  * Get the RSA parameters
  *
  * @param rsa                 The RSA object
  * @param n                   The @c n parameter
  * @param e                   The @c e parameter
  * @param d                   The @c d parameter
  */
 static inline void
 RSA_get0_key(const RSA *rsa, const BIGNUM **n,
              const BIGNUM **e, const BIGNUM **d)
 {
     if (n != NULL)
     {
         *n = rsa ? rsa->n : NULL;
     }
     if (e != NULL)
     {
         *e = rsa ? rsa->e : NULL;
     }
     if (d != NULL)
     {
         *d = rsa ? rsa->d : NULL;
     }
 }
 #endif
 
 #if !defined(HAVE_RSA_SET0_KEY)
 /**
  * Set the RSA parameters
  *
  * @param rsa                 The RSA object
  * @param n                   The @c n parameter
  * @param e                   The @c e parameter
  * @param d                   The @c d parameter
  * @return                    1 on success, 0 on error
  */
 static inline int
 RSA_set0_key(RSA *rsa, BIGNUM *n, BIGNUM *e, BIGNUM *d)
 {
     if ((rsa->n == NULL && n == NULL)
         || (rsa->e == NULL && e == NULL))
     {
         return 0;
     }
 
     if (n != NULL)
     {
         BN_free(rsa->n);
         rsa->n = n;
     }
     if (e != NULL)
     {
         BN_free(rsa->e);
         rsa->e = e;
     }
     if (d != NULL)
     {
         BN_free(rsa->d);
         rsa->d = d;
     }
 
     return 1;
 }
 #endif
 
 #if !defined(HAVE_RSA_BITS)
 /**
  * Number of significant RSA bits
  *
  * @param rsa                The RSA object ; shall not be NULL
  * @return                   The number of RSA bits or 0 on error
  */
 static inline int
 RSA_bits(const RSA *rsa)
 {
     const BIGNUM *n = NULL;
     RSA_get0_key(rsa, &n, NULL, NULL);
     return n ? BN_num_bits(n) : 0;
 }
 #endif
 
c07c0358
 #if !defined(HAVE_DSA_GET0_PQG)
 /**
  * Get the DSA parameters
  *
  * @param dsa                 The DSA object
  * @param p                   The @c p parameter
  * @param q                   The @c q parameter
  * @param g                   The @c g parameter
  */
 static inline void
 DSA_get0_pqg(const DSA *dsa, const BIGNUM **p,
              const BIGNUM **q, const BIGNUM **g)
 {
     if (p != NULL)
     {
         *p = dsa ? dsa->p : NULL;
     }
     if (q != NULL)
     {
         *q = dsa ? dsa->q : NULL;
     }
     if (g != NULL)
     {
         *g = dsa ? dsa->g : NULL;
     }
 }
 #endif
 
 #if !defined(HAVE_DSA_BITS)
 /**
  * Number of significant DSA bits
  *
  * @param rsa                The DSA object ; shall not be NULL
  * @return                   The number of DSA bits or 0 on error
  */
 static inline int
 DSA_bits(const DSA *dsa)
 {
     const BIGNUM *p = NULL;
     DSA_get0_pqg(dsa, &p, NULL, NULL);
     return p ? BN_num_bits(p) : 0;
 }
 #endif
 
09776c5b
 #if !defined(HAVE_RSA_METH_NEW)
 /**
  * Allocate a new RSA method object
  *
  * @param name               The object name
  * @param flags              Configuration flags
  * @return                   A new RSA method object
  */
 static inline RSA_METHOD *
 RSA_meth_new(const char *name, int flags)
 {
     RSA_METHOD *rsa_meth = NULL;
     ALLOC_OBJ_CLEAR(rsa_meth, RSA_METHOD);
     rsa_meth->name = string_alloc(name, NULL);
     rsa_meth->flags = flags;
     return rsa_meth;
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_FREE)
 /**
  * Free an existing RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  */
 static inline void
 RSA_meth_free(RSA_METHOD *meth)
 {
     if (meth)
     {
3fd07c31
         /* OpenSSL defines meth->name to be a const pointer, yet we
          * feed it with an allocated string (from RSA_meth_new()).
          * Thus we are allowed to free it here. In order to avoid a
          * "passing 'const char *' to parameter of type 'void *' discards
          * qualifiers" warning, we force the pointer to be a non-const value.
          */
         free((char *)meth->name);
09776c5b
         free(meth);
     }
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_SET_PUB_ENC)
 /**
  * Set the public encoding function of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @param pub_enc            the public encoding function
  * @return                   1 on success, 0 on error
  */
 static inline int
 RSA_meth_set_pub_enc(RSA_METHOD *meth,
                      int (*pub_enc) (int flen, const unsigned char *from,
                                      unsigned char *to, RSA *rsa,
                                      int padding))
 {
     if (meth)
     {
         meth->rsa_pub_enc = pub_enc;
         return 1;
     }
     return 0;
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_SET_PUB_DEC)
 /**
  * Set the public decoding function of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @param pub_dec            the public decoding function
  * @return                   1 on success, 0 on error
  */
 static inline int
 RSA_meth_set_pub_dec(RSA_METHOD *meth,
                      int (*pub_dec) (int flen, const unsigned char *from,
                                      unsigned char *to, RSA *rsa,
                                      int padding))
 {
     if (meth)
     {
         meth->rsa_pub_dec = pub_dec;
         return 1;
     }
     return 0;
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_SET_PRIV_ENC)
 /**
  * Set the private encoding function of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @param priv_enc           the private encoding function
  * @return                   1 on success, 0 on error
  */
 static inline int
 RSA_meth_set_priv_enc(RSA_METHOD *meth,
                       int (*priv_enc) (int flen, const unsigned char *from,
                                        unsigned char *to, RSA *rsa,
                                        int padding))
 {
     if (meth)
     {
         meth->rsa_priv_enc = priv_enc;
         return 1;
     }
     return 0;
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_SET_PRIV_DEC)
 /**
  * Set the private decoding function of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @param priv_dec           the private decoding function
  * @return                   1 on success, 0 on error
  */
 static inline int
 RSA_meth_set_priv_dec(RSA_METHOD *meth,
                       int (*priv_dec) (int flen, const unsigned char *from,
                                        unsigned char *to, RSA *rsa,
                                        int padding))
 {
     if (meth)
     {
         meth->rsa_priv_dec = priv_dec;
         return 1;
     }
     return 0;
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_SET_INIT)
 /**
  * Set the init function of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @param init               the init function
  * @return                   1 on success, 0 on error
  */
 static inline int
 RSA_meth_set_init(RSA_METHOD *meth, int (*init) (RSA *rsa))
 {
     if (meth)
     {
         meth->init = init;
         return 1;
     }
     return 0;
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_SET_FINISH)
 /**
  * Set the finish function of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @param finish             the finish function
  * @return                   1 on success, 0 on error
  */
 static inline int
 RSA_meth_set_finish(RSA_METHOD *meth, int (*finish) (RSA *rsa))
 {
     if (meth)
     {
         meth->finish = finish;
         return 1;
     }
     return 0;
 }
 #endif
 
 #if !defined(HAVE_RSA_METH_SET0_APP_DATA)
 /**
  * Set the application data of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @param app_data           Application data
  * @return                   1 on success, 0 on error
  */
 static inline int
 RSA_meth_set0_app_data(RSA_METHOD *meth, void *app_data)
 {
     if (meth)
     {
         meth->app_data = app_data;
         return 1;
     }
     return 0;
 }
 #endif
 
862cbe53
 #if !defined(HAVE_RSA_METH_GET0_APP_DATA)
 /**
  * Get the application data of an RSA_METHOD object
  *
  * @param meth               The RSA_METHOD object
  * @return                   pointer to application data, may be NULL
  */
 static inline void *
 RSA_meth_get0_app_data(const RSA_METHOD *meth)
 {
     return meth ? meth->app_data : NULL;
 }
 #endif
 
bb23eca8
 #if !defined(HAVE_EC_GROUP_ORDER_BITS) && !defined(OPENSSL_NO_EC)
 /**
  * Gets the number of bits of the order of an EC_GROUP
  *
  *  @param  group               EC_GROUP object
  *  @return                     number of bits of group order.
  */
 static inline int
 EC_GROUP_order_bits(const EC_GROUP *group)
 {
     BIGNUM* order = BN_new();
     EC_GROUP_get_order(group, order, NULL);
     int bits = BN_num_bits(order);
     BN_free(order);
     return bits;
 }
 #endif
 
c828ffc6
 /* SSLeay symbols have been renamed in OpenSSL 1.1 */
 #if !defined(RSA_F_RSA_OSSL_PRIVATE_ENCRYPT)
 #define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT       RSA_F_RSA_EAY_PRIVATE_ENCRYPT
 #endif
 
0e8a30c0
 #ifndef SSL_CTX_get_min_proto_version
 /** Dummy SSL_CTX_get_min_proto_version for OpenSSL < 1.1 (not really needed) */
 static inline int
 SSL_CTX_get_min_proto_version(SSL_CTX *ctx)
 {
     return 0;
 }
 #endif /* SSL_CTX_get_min_proto_version */
 
9e272106
 #ifndef SSL_CTX_get_max_proto_version
 /** Return the max SSL protocol version currently enabled in the context.
  *  If no valid version >= TLS1.0 is found, return 0. */
 static inline int
 SSL_CTX_get_max_proto_version(SSL_CTX *ctx)
 {
     long sslopt = SSL_CTX_get_options(ctx);
     if (!(sslopt & SSL_OP_NO_TLSv1_2))
     {
 	return TLS1_2_VERSION;
     }
     if (!(sslopt & SSL_OP_NO_TLSv1_1))
     {
 	return TLS1_1_VERSION;
     }
     if (!(sslopt & SSL_OP_NO_TLSv1))
     {
 	return TLS1_VERSION;
     }
     return 0;
 }
 #endif /* SSL_CTX_get_max_proto_version */
 
0e8a30c0
 #ifndef SSL_CTX_set_min_proto_version
 /** Mimics SSL_CTX_set_min_proto_version for OpenSSL < 1.1 */
 static inline int
 SSL_CTX_set_min_proto_version(SSL_CTX *ctx, long tls_ver_min)
 {
     long sslopt = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; /* Never do < TLS 1.0 */
 
     if (tls_ver_min > TLS1_VERSION)
     {
         sslopt |= SSL_OP_NO_TLSv1;
     }
 #ifdef SSL_OP_NO_TLSv1_1
     if (tls_ver_min > TLS1_1_VERSION)
     {
         sslopt |= SSL_OP_NO_TLSv1_1;
     }
 #endif
 #ifdef SSL_OP_NO_TLSv1_2
     if (tls_ver_min > TLS1_2_VERSION)
     {
         sslopt |= SSL_OP_NO_TLSv1_2;
     }
 #endif
     SSL_CTX_set_options(ctx, sslopt);
 
     return 1;
 }
 #endif /* SSL_CTX_set_min_proto_version */
 
 #ifndef SSL_CTX_set_max_proto_version
 /** Mimics SSL_CTX_set_max_proto_version for OpenSSL < 1.1 */
 static inline int
 SSL_CTX_set_max_proto_version(SSL_CTX *ctx, long tls_ver_max)
 {
     long sslopt = 0;
 
     if (tls_ver_max < TLS1_VERSION)
     {
         sslopt |= SSL_OP_NO_TLSv1;
     }
 #ifdef SSL_OP_NO_TLSv1_1
     if (tls_ver_max < TLS1_1_VERSION)
     {
         sslopt |= SSL_OP_NO_TLSv1_1;
     }
 #endif
 #ifdef SSL_OP_NO_TLSv1_2
     if (tls_ver_max < TLS1_2_VERSION)
     {
         sslopt |= SSL_OP_NO_TLSv1_2;
     }
 #endif
     SSL_CTX_set_options(ctx, sslopt);
 
     return 1;
 }
 #endif /* SSL_CTX_set_max_proto_version */
 
6554ac9f
 #endif /* OPENSSL_COMPAT_H_ */