/**
 * XML Security Library (http://www.aleksey.com/xmlsec).
 *
 * This is free software; see the Copyright file in the source distribution for precise wording.
 *
 * Copyright (C) 2002-2026 Aleksey Sanin <aleksey@aleksey.com>. All Rights Reserved.
 */
/**
 * @brief Compatibility layer for various OpenSSL versions.
 */

#ifndef __XMLSEC_OPENSSL_OPENSSL_COMPAT_H__
#define __XMLSEC_OPENSSL_OPENSSL_COMPAT_H__

#include <openssl/crypto.h>
#include <openssl/rand.h>

#include "../cast_helpers.h"


/* internal helpers */
int             xmlSecOpenSSLGenerateRandomBytes             (xmlSecByte* data, xmlSecSize size);


/******************************************************************************
 *
 * boringssl and aws-lc compatibility
 *
  *****************************************************************************/
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)

/* Not implemented by LibreSSL (yet?) */
#define XMLSEC_OPENSSL_NO_ASN1_TIME_TO_TM   1
#define XMLSEC_OPENSSL_NO_STORE             1
#define XMLSEC_OPENSSL_NO_DEEP_COPY         1
#define XMLSEC_NO_RSA_OAEP                  1
#define XMLSEC_NO_DH                        1
#define XMLSEC_NO_DSA                       1
#define XMLSEC_NO_SHA3                      1
#define XMLSEC_NO_CAMELLIA                  1
#define XMLSEC_NO_CHACHA20                  1


#define ENGINE_cleanup()                    {}

#define RAND_priv_bytes(buf,len)            RAND_bytes((buf), (len))
#define RAND_write_file(file)               (0)

#define EVP_PKEY_base_id(pkey)              EVP_PKEY_id(pkey)
#define EVP_CipherFinal(ctx, out, out_len)  EVP_CipherFinal_ex((ctx), (out), (out_len))
#define EVP_read_pw_string(buf,len, prompt, verify)     (-1)

#define X509_STORE_CTX_get_by_subject       X509_STORE_get_by_subject

/* simply return success */
#define sk_X509_reserve(crts, num)          (1)
#define sk_X509_CRL_reserve(crls, num)      (1)

#endif /* defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) */

#if defined(OPENSSL_IS_BORINGSSL)
#define X509_get0_pubkey(cert)              X509_get_pubkey((cert))
#endif /* defined(OPENSSL_IS_BORINGSSL) */


/* BoringSSL redefines int->size_t or int->unsigned */
#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)

/* when BoringSSL replaced int with unisgned */
typedef unsigned xmlSecOpenSSLUInt;

#define XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_UINT_TO_SIZE((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_UINT(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_SIZE_TO_UINT((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_BYTE(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_UINT_TO_BYTE((srcVal), (dstVal), errorAction, (errorObject))

/* when BoringSSL replaced int with size_t */
typedef size_t xmlSecOpenSSLSizeT;

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_T_TO_SIZE(srcVal, dstVal, errorAction, errorObject)  \
       (dstVal) = (srcVal)

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_SIZE_T(srcVal, dstVal, errorAction, errorObject) \
       (dstVal) = (srcVal)

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_T_TO_UINT(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_SIZE_T_TO_UINT((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_T_TO_INT(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_SIZE_T_TO_INT((srcVal), (dstVal), errorAction, (errorObject))

#else /* defined(OPENSSL_IS_BORINGSSL) */

/* when BoringSSL replaced int with unisgned */
typedef int xmlSecOpenSSLUInt;

#define XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_SIZE(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_INT_TO_SIZE((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_UINT(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_SIZE_TO_INT((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_UINT_TO_BYTE(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_INT_TO_BYTE((srcVal), (dstVal), errorAction, (errorObject))

/* when BoringSSL replaced int with size_t */
typedef int xmlSecOpenSSLSizeT;

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_T_TO_SIZE(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_INT_TO_SIZE((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_TO_SIZE_T(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_SIZE_TO_INT((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_T_TO_UINT(srcVal, dstVal, errorAction, errorObject) \
       XMLSEC_SAFE_CAST_INT_TO_UINT((srcVal), (dstVal), errorAction, (errorObject))

#define XMLSEC_OPENSSL_SAFE_CAST_SIZE_T_TO_INT(srcVal, dstVal, errorAction, errorObject) \
       (dstVal) = (srcVal)

#endif /* defined(OPENSSL_IS_BORINGSSL) */


/******************************************************************************
 *
 * LibreSSL compatibility (implements most of OpenSSL 1.1 API)
 *
  *****************************************************************************/
#if defined(LIBRESSL_VERSION_NUMBER)

/* Not implemented by LibreSSL (yet?) */
#define XMLSEC_OPENSSL_NO_ASN1_TIME_TO_TM   1
#define XMLSEC_OPENSSL_NO_STORE             1
#define XMLSEC_OPENSSL_NO_PWD_CALLBACK      1
#define XMLSEC_OPENSSL_NO_DEEP_COPY         1
#define XMLSEC_NO_DH                        1
#define XMLSEC_NO_CAMELLIA                  1
#define XMLSEC_NO_CHACHA20                  1

#define RAND_priv_bytes(buf,len)            RAND_bytes((buf), (len))

/* simply return success */
#define sk_X509_reserve(crts, num)          (1)
#define sk_X509_CRL_reserve(crls, num)      (1)

#endif /* defined(LIBRESSL_VERSION_NUMBER) */

/******************************************************************************
 *
 * OpenSSL 4.0.0 compatibility
 *
  *****************************************************************************/
#if !defined(XMLSEC_OPENSSL_API_400)
/* OpenSSL 4.0.0 or newer adds "const" in a few places */
#define XMLSEC_OPENSSL400_CONST
#else   /* !defined(XMLSEC_OPENSSL_API_400) */
#define XMLSEC_OPENSSL400_CONST  const
#endif /* !defined(XMLSEC_OPENSSL_API_400) */

/******************************************************************************
 *
 * OpenSSL 3.5.0 compatibility
 *
  *****************************************************************************/
#if !defined(XMLSEC_OPENSSL_API_350)
#define XMLSEC_NO_MLDSA                     1
#define XMLSEC_NO_SLHDSA                    1
#define XMLSEC_NO_EDDSA                     1
#define XMLSEC_NO_XDH                       1
#endif /* !defined(XMLSEC_OPENSSL_API_350) */

/******************************************************************************
 *
 * OpenSSL 3.0.0 compatibility
 *
  *****************************************************************************/
#if !defined(XMLSEC_OPENSSL_API_300)

/* ConcatKDF (SSKDF) key derivation algorithm is only available on OpenSSL 3.0.0 or newer
 * (https://www.openssl.org/docs/man3.0/man7/EVP_KDF-SS.html)
 */
#define XMLSEC_NO_CONCATKDF     1

/* PBKDF2 key derivation algorithm is only available on OpenSSL 3.0.0 or newer
 * (https://www.openssl.org/docs/man3.0/man7/EVP_KDF-PBKDF2.html)
 */
#define XMLSEC_NO_PBKDF2        1

/* HKDF key derivation algorithm is only available on OpenSSL 3.0.0 or newer
 * (https://www.openssl.org/docs/man3.0/man7/EVP_KDF-HKDF.html)
 */
#define XMLSEC_NO_HKDF          1


#define BIO_new_ex(libctx,type)                                     BIO_new((type))
#define PEM_read_bio_PrivateKey_ex(bp,x,cb,u,libctx,propq)          PEM_read_bio_PrivateKey((bp),(x),(cb),(u))
#define PEM_read_bio_PUBKEY_ex(bp,x,cb,u,libctx,propq)              PEM_read_bio_PUBKEY((bp),(x),(cb),(u))
#define d2i_PrivateKey_ex_bio(bp,a,libctx,propq)                    d2i_PrivateKey_bio((bp),(a))

#define EVP_SignFinal_ex(ctx,md,s,pkey,libctx,propq)                EVP_SignFinal((ctx),(md),(s),(pkey))
#define EVP_VerifyFinal_ex(ctx,sigbuf,siglen,pkey,libctx,propq)     EVP_VerifyFinal((ctx),(sigbuf),(siglen),(pkey))

#define X509_new_ex(libctx,propq)                                   X509_new()
#define X509_CRL_new_ex(libctx,propq)                               X509_CRL_new()
#define X509_STORE_CTX_new_ex(libctx,propq)                         X509_STORE_CTX_new()
#define X509_STORE_set_default_paths_ex(ctx,libctx,propq)           X509_STORE_set_default_paths((ctx))
#define X509_NAME_hash_ex(x,libctx,propq,ok)                        X509_NAME_hash((x))

#endif /* !defined(XMLSEC_OPENSSL_API_300) */


/******************************************************************************
 *
 * Common constants that aren't defined anywhere.
 *
  *****************************************************************************/
#ifndef XMLSEC_NO_GOST
#define XMLSEC_OPENSSL_DIGEST_NAME_GOST94       "md_gost94"
#endif /* XMLSEC_NO_GOST*/

#ifndef XMLSEC_NO_GOST2012
#define XMLSEC_OPENSSL_DIGEST_NAME_GOST12_256   "md_gost12_256"
#define XMLSEC_OPENSSL_DIGEST_NAME_GOST12_512   "md_gost12_512"
#endif /* XMLSEC_NO_GOST2012 */


#ifdef XMLSEC_OPENSSL_API_300

/* Cipher names, hopefully OpenSSL defines them one day */
#define XMLSEC_OPENSSL_CIPHER_NAME_DES3_EDE         "DES3"
#define XMLSEC_OPENSSL_CIPHER_NAME_AES128_CBC       "AES-128-CBC"
#define XMLSEC_OPENSSL_CIPHER_NAME_AES192_CBC       "AES-192-CBC"
#define XMLSEC_OPENSSL_CIPHER_NAME_AES256_CBC       "AES-256-CBC"
#define XMLSEC_OPENSSL_CIPHER_NAME_AES128_GCM       "AES-128-GCM"
#define XMLSEC_OPENSSL_CIPHER_NAME_AES192_GCM       "AES-192-GCM"
#define XMLSEC_OPENSSL_CIPHER_NAME_AES256_GCM       "AES-256-GCM"


#endif /* XMLSEC_OPENSSL_API_300 */


#endif /* __XMLSEC_OPENSSL_OPENSSL_COMPAT_H__ */
