{ +-------------------------------------------------------------+ }
{ |                                                             | }
{ |   GM-Software                                               | }
{ |   ===========                                               | }
{ |                                                             | }
{ |   Project: All Projects                                     | }
{ |                                                             | }
{ |   Description: OpenSSL call level API.                      | }
{ |                                                             | }
{ |                                                             | }
{ |   Copyright (C) - 2017 - Gerrit Moeller.                    | }
{ |                                                             | }
{ |   Source code dstributed under MIT license.                 | }
{ |                                                             | }
{ |   See: https://www.gm-software.de                           | }
{ |                                                             | }
{ +-------------------------------------------------------------+ }


{$INCLUDE GMCompilerSettings.inc}

{$IFDEF DELAY_LOAD_WIN_DLLs}
  {$DEFINE DELAY_LOAD_OPENSSL_DLL}
{$ENDIF DELAY_LOAD_WIN_DLLs}

{.$DEFINE USE_OPENSSL_3}

unit GMOpenSSLApi;

interface

uses SysUtils, {$IFDEF JEDIAPI}jwaWinType{$ELSE}Windows{$ENDIF};

const

{$IFDEF CPU64}
 {$IFDEF USE_OPENSSL_3}
  cStrSSLDllName = 'libssl-3-x64.dll';
  cStrCryptDllName = 'libcrypto-3-x64.dll';
 {$ELSE}
  cStrSSLDllName = 'libssl-1_1-x64.dll';
  cStrCryptDllName = 'libcrypto-1_1-x64.dll';
 {$ENDIF}
{$ELSE}
 {$IFDEF USE_OPENSSL_3}
  cStrSSLDllName = 'libssl-3.dll';
  cStrCryptDllName = 'libcrypto-3.dll';
 {$ELSE}
  cStrSSLDllName = 'libssl-1_1.dll';
  cStrCryptDllName = 'libcrypto-1_1.dll';
 {$ENDIF}
{$ENDIF}


const

  EVP_MAX_MD_SIZE       = 64; //* longest known is SHA512 */
  EVP_MAX_KEY_LENGTH    = 32;
  EVP_MAX_IV_LENGTH     = 16;
  EVP_MAX_BLOCK_LENGTH  = 32;

  SHA_DIGEST_LENGTH     = 20;


type

  csize_t = LongWord;
  UInt64 = Int64;

  TSslPtr = Pointer;

  PPByte = ^PByte;

  POPENSSL_INIT_SETTINGS = type TSslPtr;

  PSslPtr = ^TSslPtr;
  PSSL_CTX = type TSslPtr;
  PSSL = type TSslPtr;
  PSSL_METHOD = type TSslPtr;
  PEVP_MD	= type TSslPtr;
  PBIO_METHOD = Type TSslPtr;
  PBIO = type TSslPtr;
  PSession = type TSslPtr;
  PX509_STORE = type TSslPtr;

  PRSA = type TSslPtr;
  PPRSA = ^PRSA;
  PDH = type TSslPtr;
  PSTACK_OFX509 = type TSslPtr;

  PX509 = type TSslPtr;
  PPX509 = ^PX509;

  PEVP_PKEY = type TSslPtr;
  PPEVP_PKEY = ^PEVP_PKEY;

  PASN1_UTCTIME = type TSslPtr;
  PASN1_cInt = type TSslPtr;
  PPasswdCb = type TSslPtr;

  PSSL_CIPHER = type TSslPtr;

  PFunction = procedure;

  X509_NAME = record
    entries: pointer;
    modified: LongInt;
    bytes: pointer;
    hash: LongWord;
  end;
  PX509_NAME = ^X509_NAME;

  DES_cblock = array[0..7] of Byte;
  PDES_cblock = ^DES_cblock;

  des_ks_struct = packed record
    ks: DES_cblock;
    weak_key: LongInt;
  end;

  des_key_schedule = array[1..16] of des_ks_struct;
  PDES_key_schedule = ^des_key_schedule;

  PRAND_METHOD = type TSslPtr;

  PEVP_MD_CTX = type TSslPtr;

  PEVP_CIPHER_CTX = type TSslPtr;

  // RSA
  PENGINE = type TSslPtr;
  PBIGNUM = type TSslPtr;
  PBN_GENCB = type TSslPtr;
  PBN_MONT_CTX = type TSslPtr;
  PBN_CTX = type TSslPtr;

  PRSA_METHOD = type TSslPtr;

  PASN1_TYPE = type TSslPtr;

  PEVP_CIPHER = type TSslPtr;

  Ppem_password_cb = type TSslPtr;

  PCRYPTO_THREADID = ^CRYPTO_THREADID;
  CRYPTO_THREADID = record
    ptr: Pointer;
    val: LongWord;
  end;

  EOpenSSLError = class (Exception);


const

  SSL_MAX_MASTER_KEY_LENGTH = 48;

  SSL3_VERSION                   = $0300;
  TLS1_VERSION                   = $0301;
  TLS1_1_VERSION                 = $0302;
  TLS1_2_VERSION                 = $0303;
  TLS1_3_VERSION                 = $0304;
  DTLS1_VERSION                  = $FEFF;
  DTLS1_2_VERSION                = $FEFD;
  DTLS1_BAD_VER                  = $0100;


  // OPENSSL_INIT flag range 0xfff00000 reserved for OPENSSL_init_ssl()
  // Max OPENSSL_INIT flag value is 0x80000000

  OPENSSL_INIT_NO_ADD_ALL_DIGESTS     = $00000020;
  OPENSSL_INIT_LOAD_CONFIG            = $00000040;
  OPENSSL_INIT_NO_LOAD_CONFIG         = $00000080;
  OPENSSL_INIT_ASYNC                  = $00000100;
  OPENSSL_INIT_ENGINE_RDRAND          = $00000200;
  OPENSSL_INIT_ENGINE_DYNAMIC         = $00000400;
  OPENSSL_INIT_ENGINE_OPENSSL         = $00000800;
  OPENSSL_INIT_ENGINE_CRYPTODEV       = $00001000;
  OPENSSL_INIT_ENGINE_CAPI            = $00002000;
  OPENSSL_INIT_ENGINE_PADLOCK         = $00004000;
  OPENSSL_INIT_ENGINE_DASYNC          = $00008000;

  OPENSSL_INIT                        = $00010000; // <-- reserved for internal use!
  OPENSSL_INIT_ENGINE_AFALG           = $00020000;

  OPENSSL_INIT_ENGINE_ALL_BUILTIN     =  OPENSSL_INIT_ENGINE_RDRAND or OPENSSL_INIT_ENGINE_DYNAMIC or OPENSSL_INIT_ENGINE_CRYPTODEV or
                                         OPENSSL_INIT_ENGINE_CAPI or OPENSSL_INIT_ENGINE_PADLOCK;

  SSL_ERROR_NONE = 0;
  SSL_ERROR_SSL = 1;
  SSL_ERROR_WANT_READ = 2;
  SSL_ERROR_WANT_WRITE = 3;
  SSL_ERROR_WANT_X509_LOOKUP = 4;
  SSL_ERROR_SYSCALL = 5; //look at error stack/return value/errno
  SSL_ERROR_ZERO_RETURN = 6;
  SSL_ERROR_WANT_CONNECT = 7;
  SSL_ERROR_WANT_ACCEPT = 8;
  SSL_ERROR_WANT_ASYNC = 9;
  SSL_ERROR_WANT_ASYNC_JOB = 10;
  SSL_ERROR_WANT_CLIENT_HELLO_CB = 11;


  //
  // SSL/TLS connection options.
  //

  // Disable Extended master secret
  SSL_OP_NO_EXTENDED_MASTER_SECRET = 1; // SSL_OP_BIT(0)
  // Cleanse plaintext copies of data delivered to the application
  SSL_OP_CLEANSE_PLAINTEXT = 1 shl 1; //                       SSL_OP_BIT(1)
  // Allow initial connection to servers that don't support RI
  SSL_OP_LEGACY_SERVER_CONNECT = 1 shl 2; // SSL_OP_BIT(2)
  // Enable support for Kernel TLS
  SSL_OP_ENABLE_KTLS = 1 shl 3; // SSL_OP_BIT(3)
  SSL_OP_TLSEXT_PADDING = 1 shl 4; // SSL_OP_BIT(4)
  SSL_OP_SAFARI_ECDHE_ECDSA_BUG = 1 shl 6; // SSL_OP_BIT(6)
  SSL_OP_IGNORE_UNEXPECTED_EOF = 1 shl 7; // SSL_OP_BIT(7)
  SSL_OP_ALLOW_CLIENT_RENEGOTIATION = 1 shl 8; // SSL_OP_BIT(8)
  SSL_OP_DISABLE_TLSEXT_CA_NAMES = 1 shl 9; // SSL_OP_BIT(9)
  // In TLSv1.3 allow a non-(ec)dhe based kex_mode
  SSL_OP_ALLOW_NO_DHE_KEX = 1 shl 10; // SSL_OP_BIT(10)

  // Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added
  // in OpenSSL 0.9.6d.  Usually (depending on the application protocol)
  // the workaround is not needed.  Unfortunately some broken SSL/TLS
  // implementations cannot handle it at all, which is why we include it
  // in SSL_OP_ALL. Added in 0.9.6e
  SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 1 shl 11; // SSL_OP_BIT(11)
  // DTLS options
  SSL_OP_NO_QUERY_MTU = 1 shl 12; // SSL_OP_BIT(12)
  // Turn on Cookie Exchange (on relevant for servers)
  SSL_OP_COOKIE_EXCHANGE = 1 shl 13; // SSL_OP_BIT(13)
  // Don't use RFC4507 ticket extension
  SSL_OP_NO_TICKET = 1 shl 14; // SSL_OP_BIT(14)
  //# ifndef OPENSSL_NO_DTLS1_METHOD
  //    /*
  //     * Use Cisco's version identifier of DTLS_BAD_VER
  //     * (only with deprecated DTLSv1_client_method())
  //     */
  SSL_OP_CISCO_ANYCONNECT = 1 shl 15; // SSL_OP_BIT(15)
  //# endif

  // As server, disallow session resumption on renegotiation
  SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 1 shl 16; // SSL_OP_BIT(16)
  // Don't use compression even if supported
  SSL_OP_NO_COMPRESSION = 1 shl 17; // SSL_OP_BIT(17)
  // Permit unsafe legacy renegotiation
  SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 1 shl 18; // SSL_OP_BIT(18)
  // Disable encrypt-then-mac
  SSL_OP_NO_ENCRYPT_THEN_MAC = 1 shl 19; // SSL_OP_BIT(19)
  ///*
  // * Enable TLSv1.3 Compatibility mode. This is on by default. A future
  // * version of OpenSSL may have this disabled by default.
  // */
  SSL_OP_ENABLE_MIDDLEBOX_COMPAT = 1 shl 20; // SSL_OP_BIT(20)
  ///*
  // * Prioritize Chacha20Poly1305 when client does.
  // * Modifies SSL_OP_CIPHER_SERVER_PREFERENCE
  // */
  SSL_OP_PRIORITIZE_CHACHA = 1 shl 21; // SSL_OP_BIT(21)
  ///*
  // * Set on servers to choose the cipher according to server's preferences.
  // */
  SSL_OP_CIPHER_SERVER_PREFERENCE = 1 shl 22; // SSL_OP_BIT(22)
  ///*
  // * If set, a server will allow a client to issue a SSLv3.0 version
  // * number as latest version supported in the premaster secret, even when
  // * TLSv1.0 (version 3.1) was announced in the client hello. Normally
  // * this is forbidden to prevent version rollback attacks.
  // */
  SSL_OP_TLS_ROLLBACK_BUG = 1 shl 23; // SSL_OP_BIT(23)
  ///*
  // * Switches off automatic TLSv1.3 anti-replay protection for early data.
  // * This is a server-side option only (no effect on the client).
  // */
  SSL_OP_NO_ANTI_REPLAY = 1 shl 24; // SSL_OP_BIT(24)
  SSL_OP_NO_SSLv3 = 1 shl 25; // SSL_OP_BIT(25)
  SSL_OP_NO_TLSv1 = 1 shl 26; // SSL_OP_BIT(26)
  SSL_OP_NO_TLSv1_2 = 1 shl 27; // SSL_OP_BIT(27)
  SSL_OP_NO_TLSv1_1 = 1 shl 28; // SSL_OP_BIT(28)
  SSL_OP_NO_TLSv1_3 = 1 shl 29; // SSL_OP_BIT(29)
  SSL_OP_NO_DTLSv1 = 1 shl 26; // SSL_OP_BIT(26)
  SSL_OP_NO_DTLSv1_2 = 1 shl 27; // SSL_OP_BIT(27)
  // Disallow all renegotiation
  SSL_OP_NO_RENEGOTIATION = 1 shl 30; // SSL_OP_BIT(30)
  //
  //  Make server add server-hello extension from early version of
  //  cryptopro draft, when GOST ciphersuite is negotiated. Required for
  //  interoperability with CryptoPro CSP 3.x
  //
  SSL_OP_CRYPTOPRO_TLSEXT_BUG = 1 shl 31; // SSL_OP_BIT(31)

  //
  // Option "collections."
  //
  SSL_OP_NO_SSL_MASK = SSL_OP_NO_SSLv3 or SSL_OP_NO_TLSv1 or SSL_OP_NO_TLSv1_1 or SSL_OP_NO_TLSv1_2 or SSL_OP_NO_TLSv1_3;
  SSL_OP_NO_DTLS_MASK = SSL_OP_NO_DTLSv1 or SSL_OP_NO_DTLSv1_2;

  // Various bug workarounds that should be rather harmless.
  SSL_OP_ALL = SSL_OP_CRYPTOPRO_TLSEXT_BUG or SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS or SSL_OP_TLSEXT_PADDING or SSL_OP_SAFARI_ECDHE_ECDSA_BUG;



{* Allow SSL_write(..., n) to return r with 0 < r < n (i.e. report success
 * when just a single record has been written): *}
  SSL_MODE_ENABLE_PARTIAL_WRITE = 1;
{* Make it possible to retry SSL_write() with changed buffer location
 * (buffer contents must stay the same!); this is not the default to avoid
 * the misconception that non-blocking SSL_write() behaves like
 * non-blocking write(): *}
  SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = 2;
{* Never bother the application with retries if the transport
 * is blocking: *}
  SSL_MODE_AUTO_RETRY = 4;
{* Don't attempt to automatically build certificate chain *}
  SSL_MODE_NO_AUTO_CHAIN = 8;

  SSL_OP_NO_SSLv2 = $01000000;
  //SSL_OP_NO_SSLv3 = $02000000;
  //SSL_OP_NO_TLSv1 = $04000000;
  //SSL_OP_ALL = $000FFFFF;
  SSL_VERIFY_NONE = $00;
  SSL_VERIFY_PEER = $01;

  OPENSSL_DES_DECRYPT = 0;
  OPENSSL_DES_ENCRYPT = 1;

  X509_V_OK =	0;
  X509_V_ILLEGAL = 1;
  X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2;
  X509_V_ERR_UNABLE_TO_GET_CRL = 3;
  X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4;
  X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5;
  X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6;
  X509_V_ERR_CERT_SIGNATURE_FAILURE = 7;
  X509_V_ERR_CRL_SIGNATURE_FAILURE = 8;
  X509_V_ERR_CERT_NOT_YET_VALID = 9;
  X509_V_ERR_CERT_HAS_EXPIRED = 10;
  X509_V_ERR_CRL_NOT_YET_VALID = 11;
  X509_V_ERR_CRL_HAS_EXPIRED = 12;
  X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 13;
  X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 14;
  X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = 15;
  X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16;
  X509_V_ERR_OUT_OF_MEM = 17;
  X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18;
  X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19;
  X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20;
  X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21;
  X509_V_ERR_CERT_CHAIN_TOO_LONG = 22;
  X509_V_ERR_CERT_REVOKED = 23;
  X509_V_ERR_INVALID_CA = 24;
  X509_V_ERR_PATH_LENGTH_EXCEEDED = 25;
  X509_V_ERR_INVALID_PURPOSE = 26;
  X509_V_ERR_CERT_UNTRUSTED = 27;
  X509_V_ERR_CERT_REJECTED = 28;
  //These are 'informational' when looking for issuer cert
  X509_V_ERR_SUBJECT_ISSUER_MISMATCH = 29;
  X509_V_ERR_AKID_SKID_MISMATCH = 30;
  X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31;
  X509_V_ERR_KEYUSAGE_NO_CERTSIGN = 32;
  X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER = 33;
  X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION = 34;
  //The application is not happy
  X509_V_ERR_APPLICATION_VERIFICATION = 50;

  SSL_FILETYPE_PEM = 1;
  SSL_FILETYPE_ASN1 = 2;

  EVP_PKEY_RSA = 6;

  // RSA
  RSA_PKCS1_PADDING      = 1;
  RSA_SSLV23_PADDING     = 2;
  RSA_NO_PADDING         = 3;
  RSA_PKCS1_OAEP_PADDING = 4;

  // BIO

  BIO_NOCLOSE	        = $00;
  BIO_CLOSE 	        = $01;

  //* modifiers */
  BIO_FP_READ		= $02;
  BIO_FP_WRITE		= $04;
  BIO_FP_APPEND		= $08;
  BIO_FP_TEXT		= $10;

  BIO_C_SET_CONNECT                 = 100;
  BIO_C_DO_STATE_MACHINE            = 101;
  BIO_C_SET_NBIO	            = 102;
  BIO_C_SET_PROXY_PARAM	            = 103;
  BIO_C_SET_FD	                    = 104;
  BIO_C_GET_FD		            = 105;
  BIO_C_SET_FILE_PTR	            = 106;
  BIO_C_GET_FILE_PTR	            = 107;
  BIO_C_SET_FILENAME	            = 108;
  BIO_C_SET_SSL		            = 109;
  BIO_C_GET_SSL		            = 110;
  BIO_C_SET_MD		            = 111;
  BIO_C_GET_MD	                    = 112;
  BIO_C_GET_CIPHER_STATUS           = 113;
  BIO_C_SET_BUF_MEM 	            = 114;
  BIO_C_GET_BUF_MEM_PTR  	    = 115;
  BIO_C_GET_BUFF_NUM_LINES          = 116;
  BIO_C_SET_BUFF_SIZE	            = 117;
  BIO_C_SET_ACCEPT 	            = 118;
  BIO_C_SSL_MODE 	            = 119;
  BIO_C_GET_MD_CTX	            = 120;
  BIO_C_GET_PROXY_PARAM	            = 121;
  BIO_C_SET_BUFF_READ_DATA 	    = 122; // data to read first */
  BIO_C_GET_CONNECT	 	    = 123;
  BIO_C_GET_ACCEPT		    = 124;
  BIO_C_SET_SSL_RENEGOTIATE_BYTES   = 125;
  BIO_C_GET_SSL_NUM_RENEGOTIATES    = 126;
  BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT = 127;
  BIO_C_FILE_SEEK		    = 128;
  BIO_C_GET_CIPHER_CTX		    = 129;
  BIO_C_SET_BUF_MEM_EOF_RETURN	= 130;//*return end of input value*/
  BIO_C_SET_BIND_MODE		= 131;
  BIO_C_GET_BIND_MODE		= 132;
  BIO_C_FILE_TELL		= 133;
  BIO_C_GET_SOCKS		= 134;
  BIO_C_SET_SOCKS		= 135;

  BIO_C_SET_WRITE_BUF_SIZE	= 136;//* for BIO_s_bio */
  BIO_C_GET_WRITE_BUF_SIZE	= 137;
  BIO_C_MAKE_BIO_PAIR		= 138;
  BIO_C_DESTROY_BIO_PAIR	= 139;
  BIO_C_GET_WRITE_GUARANTEE	= 140;
  BIO_C_GET_READ_REQUEST	= 141;
  BIO_C_SHUTDOWN_WR		= 142;
  BIO_C_NREAD0		        = 143;
  BIO_C_NREAD			= 144;
  BIO_C_NWRITE0			= 145;
  BIO_C_NWRITE			= 146;
  BIO_C_RESET_READ_REQUEST	= 147;
  BIO_C_SET_MD_CTX		= 148;

  BIO_C_SET_PREFIX		= 149;
  BIO_C_GET_PREFIX		= 150;
  BIO_C_SET_SUFFIX		= 151;
  BIO_C_GET_SUFFIX		= 152;

  BIO_C_SET_EX_ARG		= 153;
  BIO_C_GET_EX_ARG		= 154;

//DES modes
  DES_ENCRYPT = 1;
  DES_DECRYPT = 0;


  SSL_CTRL_NEED_TMP_RSA = 1;
  SSL_CTRL_SET_TMP_RSA = 2;
  SSL_CTRL_SET_TMP_RSA_CB = 5;
  SSL_CTRL_GET_SESSION_REUSED = 8;

  {$ifndef OPENSSL_NO_DEPRECATED_3_0}
  SSL_CTRL_SET_TMP_DH                    = 3;
  SSL_CTRL_SET_TMP_ECDH                  = 4;
  SSL_CTRL_SET_TMP_DH_CB                 = 6;
  {$endif}

  SSL_CTRL_GET_CLIENT_CERT_REQUEST        = 9;
  SSL_CTRL_GET_NUM_RENEGOTIATIONS         = 10;
  SSL_CTRL_CLEAR_NUM_RENEGOTIATIONS       = 11;
  SSL_CTRL_GET_TOTAL_RENEGOTIATIONS       = 12;
  SSL_CTRL_GET_FLAGS                      = 13;
  SSL_CTRL_EXTRA_CHAIN_CERT               = 14;
  SSL_CTRL_SET_MSG_CALLBACK               = 15;
  SSL_CTRL_SET_MSG_CALLBACK_ARG           = 16;
  // only applies to datagram connections
  SSL_CTRL_SET_MTU                        = 17;
  // Stats
  SSL_CTRL_SESS_NUMBER                    = 20;
  SSL_CTRL_SESS_CONNECT                   = 21;
  SSL_CTRL_SESS_CONNECT_GOOD              = 22;
  SSL_CTRL_SESS_CONNECT_RENEGOTIATE       = 23;
  SSL_CTRL_SESS_ACCEPT                    = 24;
  SSL_CTRL_SESS_ACCEPT_GOOD               = 25;
  SSL_CTRL_SESS_ACCEPT_RENEGOTIATE        = 26;
  SSL_CTRL_SESS_HIT                       = 27;
  SSL_CTRL_SESS_CB_HIT                    = 28;
  SSL_CTRL_SESS_MISSES                    = 29;
  SSL_CTRL_SESS_TIMEOUTS                  = 30;
  SSL_CTRL_SESS_CACHE_FULL                = 31;
  SSL_CTRL_MODE                           = 33;
  SSL_CTRL_GET_READ_AHEAD                 = 40;
  SSL_CTRL_SET_READ_AHEAD                 = 41;
  SSL_CTRL_SET_SESS_CACHE_SIZE            = 42;
  SSL_CTRL_GET_SESS_CACHE_SIZE            = 43;
  SSL_CTRL_SET_SESS_CACHE_MODE            = 44;
  SSL_CTRL_GET_SESS_CACHE_MODE            = 45;
  SSL_CTRL_GET_MAX_CERT_LIST              = 50;
  SSL_CTRL_SET_MAX_CERT_LIST              = 51;
  SSL_CTRL_SET_MAX_SEND_FRAGMENT          = 52;
  // see tls1.h for macros based on these
  SSL_CTRL_SET_TLSEXT_SERVERNAME_CB       = 53;
  SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG      = 54;
  SSL_CTRL_SET_TLSEXT_HOSTNAME            = 55;
  SSL_CTRL_SET_TLSEXT_DEBUG_CB            = 56;
  SSL_CTRL_SET_TLSEXT_DEBUG_ARG           = 57;
  SSL_CTRL_GET_TLSEXT_TICKET_KEYS         = 58;
  SSL_CTRL_SET_TLSEXT_TICKET_KEYS         = 59;
  // SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT    60;
  // SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB 61;
  // SSL_CTRL_SET_TLSEXT_OPAQUE_PRF_INPUT_CB_ARG 62;
  SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB       = 63;
  SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG   = 64;
  SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE     = 65;
  SSL_CTRL_GET_TLSEXT_STATUS_REQ_EXTS     = 66;
  SSL_CTRL_SET_TLSEXT_STATUS_REQ_EXTS     = 67;
  SSL_CTRL_GET_TLSEXT_STATUS_REQ_IDS      = 68;
  SSL_CTRL_SET_TLSEXT_STATUS_REQ_IDS      = 69;
  SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP = 70;
  SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP = 71;
  {$ifndef OPENSSL_NO_DEPRECATED_3_0}
  SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB       = 72;
  {$endif}
  SSL_CTRL_SET_TLS_EXT_SRP_USERNAME_CB    = 75;
  SSL_CTRL_SET_SRP_VERIFY_PARAM_CB        = 76;
  SSL_CTRL_SET_SRP_GIVE_CLIENT_PWD_CB     = 77;
  SSL_CTRL_SET_SRP_ARG                    = 78;
  SSL_CTRL_SET_TLS_EXT_SRP_USERNAME       = 79;
  SSL_CTRL_SET_TLS_EXT_SRP_STRENGTH       = 80;
  SSL_CTRL_SET_TLS_EXT_SRP_PASSWORD       = 81;
  DTLS_CTRL_GET_TIMEOUT                   = 73;
  DTLS_CTRL_HANDLE_TIMEOUT                = 74;
  SSL_CTRL_GET_RI_SUPPORT                 = 76;
  SSL_CTRL_CLEAR_MODE                     = 78;
  SSL_CTRL_SET_NOT_RESUMABLE_SESS_CB      = 79;
  SSL_CTRL_GET_EXTRA_CHAIN_CERTS          = 82;
  SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS        = 83;
  SSL_CTRL_CHAIN                          = 88;
  SSL_CTRL_CHAIN_CERT                     = 89;
  SSL_CTRL_GET_GROUPS                     = 90;
  SSL_CTRL_SET_GROUPS                     = 91;
  SSL_CTRL_SET_GROUPS_LIST                = 92;
  SSL_CTRL_GET_SHARED_GROUP               = 93;
  SSL_CTRL_SET_SIGALGS                    = 97;
  SSL_CTRL_SET_SIGALGS_LIST               = 98;
  SSL_CTRL_CERT_FLAGS                     = 99;
  SSL_CTRL_CLEAR_CERT_FLAGS               = 100;
  SSL_CTRL_SET_CLIENT_SIGALGS             = 101;
  SSL_CTRL_SET_CLIENT_SIGALGS_LIST        = 102;
  SSL_CTRL_GET_CLIENT_CERT_TYPES          = 103;
  SSL_CTRL_SET_CLIENT_CERT_TYPES          = 104;
  SSL_CTRL_BUILD_CERT_CHAIN               = 105;
  SSL_CTRL_SET_VERIFY_CERT_STORE          = 106;
  SSL_CTRL_SET_CHAIN_CERT_STORE           = 107;
  SSL_CTRL_GET_PEER_SIGNATURE_NID         = 108;
  SSL_CTRL_GET_PEER_TMP_KEY               = 109;
  SSL_CTRL_GET_RAW_CIPHERLIST             = 110;
  SSL_CTRL_GET_EC_POINT_FORMATS           = 111;
  SSL_CTRL_GET_CHAIN_CERTS                = 115;
  SSL_CTRL_SELECT_CURRENT_CERT            = 116;
  SSL_CTRL_SET_CURRENT_CERT               = 117;
  SSL_CTRL_SET_DH_AUTO                    = 118;
  DTLS_CTRL_SET_LINK_MTU                  = 120;
  DTLS_CTRL_GET_LINK_MIN_MTU              = 121;
  SSL_CTRL_GET_EXTMS_SUPPORT              = 122;
  SSL_CTRL_SET_MIN_PROTO_VERSION          = 123;
  SSL_CTRL_SET_MAX_PROTO_VERSION          = 124;
  SSL_CTRL_SET_SPLIT_SEND_FRAGMENT        = 125;
  SSL_CTRL_SET_MAX_PIPELINES              = 126;
  SSL_CTRL_GET_TLSEXT_STATUS_REQ_TYPE     = 127;
  SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB       = 128;
  SSL_CTRL_GET_TLSEXT_STATUS_REQ_CB_ARG   = 129;
  SSL_CTRL_GET_MIN_PROTO_VERSION          = 130;
  SSL_CTRL_GET_MAX_PROTO_VERSION          = 131;
  SSL_CTRL_GET_SIGNATURE_NID              = 132;
  SSL_CTRL_GET_TMP_KEY                    = 133;
  SSL_CTRL_GET_NEGOTIATED_GROUP           = 134;
  SSL_CTRL_SET_RETRY_VERIFY               = 136;
  SSL_CTRL_GET_VERIFY_CERT_STORE          = 137;
  SSL_CTRL_GET_CHAIN_CERT_STORE           = 138;


  // NameType value from RFC3546
  TLSEXT_NAMETYPE_host_name = 0;
  // status request value from RFC3546
  TLSEXT_STATUSTYPE_ocsp = 1;



 { --------------------- }
 { ---- SSL Library ---- }
 { --------------------- }

  function SSL_get_error(ASSL: PSSL; ret_code: LongInt): LongInt; cdecl;
  function SSL_library_init: LongInt; cdecl;
  procedure SSL_load_error_strings; cdecl;

  function SSL_state_string(ASsl: PSSL): PAnsiChar; cdecl;
  function SSL_state_string_long(ASsl: PSSL): PAnsiChar; cdecl;

  function SSL_set_fd(ASSL: PSSL; fd: LongInt): LongInt; cdecl;
  function SSL_ctrl(ASSL: PSSL; cmd: LongInt; larg: Int64; parg: Pointer): Int64; cdecl;

  function SSL_CTX_new(AMethod: PSSL_METHOD): PSSL_CTX; cdecl;
  function SSL_CTX_set_cipher_list(ASSL: PSSL_CTX; str: PAnsiChar): LongInt; cdecl;
  function SSL_CTX_up_ref(ASSL: PSSL_CTX): LongInt; cdecl;
  procedure SSL_CTX_free(ASSL: PSSL_CTX); cdecl;
  function SSL_CTX_ctrl(ctx: PSSL_CTX; cmd: LongInt; larg: Int64; parg: Pointer): Int64; cdecl;
  function SSL_CTX_use_PrivateKey(ctx: PSSL_CTX; pkey: TSslPtr): LongInt; cdecl;
  function SSL_CTX_use_PrivateKey_ASN1(pk: LongInt; ctx: PSSL_CTX; d: TSslPtr; len: LongInt): LongInt; cdecl;
  procedure SSL_CTX_set_verify(ctx: PSSL_CTX; mode: LongInt; arg2: TSslPtr); cdecl;

  function SSL_CTX_set_options(ctx: PSSL_CTX; options: QWord): QWord; cdecl;
  function SSL_CTX_clear_options(ctx: PSSL_CTX; options: QWord): QWord; cdecl;

  function SSL_CTX_use_RSAPrivateKey_file(ctx: PSSL_CTX; filename: PAnsiChar; _type: LongInt): LongInt; cdecl;
  function SSL_CTX_use_certificate(ctx: PSSL_CTX; cert: TSslPtr): LongInt; cdecl;
  function SSL_CTX_use_certificate_ASN1(ctx: PSSL_CTX; len: LongInt; certdata: TSslPtr): LongInt; cdecl;
  function SSL_CTX_use_certificate_file(ctx: PSSL_CTX; filename: PAnsiChar; filetype: LongInt): LongInt; cdecl;
  function SSL_CTX_use_certificate_chain_file(ctx: PSSL_CTX; filename: PAnsiChar): LongInt; cdecl;
  function SSL_CTX_check_private_key(ctx: PSSL_CTX): LongInt; cdecl;
  procedure SSL_CTX_set_default_passwd_cb(ctx: PSSL_CTX; cb: TSslPtr); cdecl;
  procedure SSL_CTX_set_default_passwd_cb_userdata(ctx: PSSL_CTX; u: TSslPtr); cdecl;
  function SSL_CTX_load_verify_locations(ctx: PSSL_CTX; filename: PAnsiChar; path: PAnsiChar): LongInt; cdecl;

  procedure SSL_CTX_set_cert_store(pSslCtx: PSSL_CTX; pCertStore: PX509_STORE); cdecl;
  procedure SSL_CTX_set1_cert_store(pSslCtx: PSSL_CTX; pCertStore: PX509_STORE); cdecl;
  function SSL_CTX_get_cert_store(pSslCtx: PSSL_Ctx): PX509_STORE; cdecl;

  function TLS_method: PSSL_METHOD; cdecl;
  function TLS_client_method: PSSL_METHOD; cdecl;
  function TLS_server_method: PSSL_METHOD; cdecl;

  function SSLv23_method: PSSL_METHOD; cdecl;
  function SSLv23_server_method: PSSL_METHOD; cdecl;
  function SSLv23_client_method: PSSL_METHOD; cdecl;

  function TLSv1_method: PSSL_METHOD; cdecl;
  function TLSv1_server_method: PSSL_METHOD; cdecl;
  function TLSv1_client_method: PSSL_METHOD; cdecl;

  function TLSv1_1_method: PSSL_METHOD; cdecl;
  function TLSv1_1_server_method: PSSL_METHOD; cdecl;
  function TLSv1_1_client_method: PSSL_METHOD; cdecl;

  function TLSv1_2_method: PSSL_METHOD; cdecl;
  function TLSv1_2_server_method: PSSL_METHOD; cdecl;
  function TLSv1_2_client_method: PSSL_METHOD; cdecl;

  function DTLS_method: PSSL_METHOD; cdecl;
  function DTLS_server_method: PSSL_METHOD; cdecl;
  function DTLS_client_method: PSSL_METHOD; cdecl;

  function DTLSv1_method: PSSL_METHOD; cdecl;
  function DTLSv1_server_method: PSSL_METHOD; cdecl;
  function DTLSv1_client_method: PSSL_METHOD; cdecl;

  function DTLSv1_2_method: PSSL_METHOD; cdecl;
  function DTLSv1_2_server_method: PSSL_METHOD; cdecl;
  function DTLSv1_2_client_method: PSSL_METHOD; cdecl;

  function SSL_use_certificate(ASSL: PSSL; cert: PX509): LongInt; cdecl;
  function SSL_use_certificate_ASN1(assl: PSSL; data: TSslPtr; datalen: LongInt): LongInt; cdecl;
  function SSL_use_certificate_file(assl: PSSL; filename: PAnsiChar; filetype: LongInt): LongInt; cdecl;

  function SSL_use_PrivateKey(assl: PSSL; pkey: PEVP_PKEY): LongInt; cdecl;
  function SSL_use_PrivateKey_ASN1(keyKind: LongInt; ssl: PSSL; keydata: Pointer; datalen: LongInt): LongInt; cdecl;
  function SSL_use_PrivateKey_file(ssl: PSSL; filename: PAnsiChar; filetype: LongInt): LongInt; cdecl;

  function SSL_new(ctx: PSSL_CTX): PSSL; cdecl;
  procedure SSL_free(ssl: PSSL); cdecl;
  function SSL_accept(ssl: PSSL): LongInt; cdecl;
  function SSL_connect(ssl: PSSL): LongInt; cdecl;
  function SSL_shutdown(ssl: PSSL): LongInt; cdecl;
  function SSL_read(ssl: PSSL; buf: PAnsiChar; buflen: LongInt): LongInt; cdecl;
  function SSL_peek(ssl: PSSL; buf: PAnsiChar; buflen: LongInt): LongInt; cdecl;
  function SSL_write(ssl: PSSL; buf: PAnsiChar; buflen: LongInt): LongInt; cdecl;
  function SSL_pending(ssl: PSSL): LongInt; cdecl;
  function SSL_get_version(ssl: PSSL): PAnsiChar; cdecl;
  function SSL_get_peer_certificate(ssl: PSSL): PX509; cdecl;
  function SSL_get_current_cipher(assl: PSSL): TSslPtr; cdecl;
  function SSL_get_verify_result(ssl: PSSL): LongInt; cdecl;

  function SSL_set_options(ssl: PSSL; options: QWord): QWord; cdecl;
  function SSL_clear_options(ssl: PSSL; options: QWord): QWord; cdecl;

  function SSL_CIPHER_get_name(cipher: PSSL_CIPHER): PAnsiChar; cdecl;
  function SSL_CIPHER_get_bits(cipher: PSSL_CIPHER; alg_bits: PLongInt): LongInt; cdecl;
  function SSL_CIPHER_get_version(cipher: PSSL_CIPHER): PAnsiChar; cdecl;
  function SSL_CIPHER_description(cipher: PSSL_CIPHER; buffer: PAnsiChar; bufSize: LongInt): PAnsiChar; cdecl;

  procedure SSL_copy_session_id(dest, src: PSSL); cdecl;
  function SSL_get_session(ssl: PSSL): PSession; cdecl;
  function SSL_set_session(ssl: PSSL; session: PSession): LongInt; cdecl;

  procedure OpenSSL_add_all_algorithms; cdecl;
  procedure OpenSSL_add_all_ciphers; cdecl;
  procedure OpenSSL_add_all_digests; cdecl;

  procedure EVP_cleanup; cdecl;


 { ------------------------ }
 { ---- Crypto Library ---- }
 { ------------------------ }

  function ERR_get_error: LongWord; cdecl;
  function ERR_peek_error: LongWord; cdecl;
  function ERR_peek_last_error: LongWord; cdecl;

  function ERR_error_string(errorCode: LongWord; buffer: PAnsiChar): PAnsiChar; cdecl;
  procedure ERR_error_string_n(errorCode: LongWord; buffer: PAnsiChar; bufSize: size_t); cdecl;

  function ERR_lib_error_string(errorCode: LongWord): PAnsiChar; cdecl;
  function ERR_func_error_string(errorCode: LongWord): PAnsiChar; cdecl;
  function ERR_reason_error_string(errorCode: LongWord): PAnsiChar; cdecl;

  procedure ERR_remove_state(threadId: LongWord); cdecl;
  procedure ERR_remove_thread_state(tid: PCRYPTO_THREADID); cdecl;

  function OPENSSL_init_new: POPENSSL_INIT_SETTINGS; cdecl;
  function OPENSSL_INIT_set_config_appname(init: POPENSSL_INIT_SETTINGS; name: PAnsiChar): LongInt; cdecl;
  procedure OPENSSL_INIT_free(init: POPENSSL_INIT_SETTINGS); cdecl;
  function OPENSSL_init_crypto(opts: UInt64; settings: POPENSSL_INIT_SETTINGS): LongInt; cdecl;
  procedure OPENSSL_cleanup; cdecl;

  procedure CRYPTO_THREADID_set_numeric(id: PCRYPTO_THREADID; val: LongWord); cdecl;
  procedure CRYPTO_THREADID_set_pointer(id: PCRYPTO_THREADID; ptr: Pointer); cdecl;
  procedure CRYPTO_THREADID_current(id: PCRYPTO_THREADID); cdecl;

  function X509_new: PX509; cdecl;
  procedure X509_free(x509: PX509); cdecl;

  procedure DES_random_key(ret: PDES_cblock); cdecl;
  function DES_set_key(Key: PDES_cblock; schedule: PDES_key_schedule): LongInt; cdecl;
  function DES_key_sched(Key: PDES_cblock; schedule: PDES_key_schedule): LongInt; cdecl;
  function DES_set_key_checked(Key: PDES_cblock; schedule: PDES_key_schedule): LongInt; cdecl;
  procedure DES_set_key_unchecked(Key: PDES_cblock; schedule: PDES_key_schedule); cdecl;

  procedure DES_set_odd_parity(Key: PDES_cblock); cdecl;
  function DES_is_weak_key(Key: PDES_cblock): LongInt; cdecl;

  procedure DES_ecb_encrypt(input, output: PDES_cblock; schedule: PDES_key_schedule; enc: LongInt); cdecl;
  procedure DES_ecb2_encrypt(input, output: PDES_cblock; schedule1, schedule2: PDES_key_schedule; enc: LongInt); cdecl;
  procedure DES_ecb3_encrypt(input, output: PDES_cblock; schedule1, schedule2, schedule3: PDES_key_schedule; enc: LongInt); cdecl;

  function X509_STORE_new: PX509_STORE; cdecl;
  procedure X509_STORE_free(pStore: PX509_STORE); cdecl;
  function X509_STORE_lock(pStore: PX509_STORE): LongInt; cdecl;
  function X509_STORE_unlock(pStore: PX509_STORE): LongInt; cdecl;
  function X509_STORE_up_ref(pStore: PX509_STORE): LongInt; cdecl;

  function d2i_X509(ppx509: PPX509; in_Data: PPByte; len: LongInt): PX509; cdecl;
  function i2d_X509(px509: PX509; out_Data: PPByte): LongInt; cdecl;
  function i2d_re_X509_tbs(px509: PX509; out_Data: PPByte): LongInt; cdecl;

  function X509_STORE_add_cert(pStore: PX509_STORE; cert: PX509): LongInt; cdecl;



//procedure InitializeOpenSSL;



implementation

uses GMStrDef, GMCommon {$IFDEF JEDIAPI}, jwaWinBase{$ENDIF};

resourcestring

  RStrRoutineNotFound = 'Routine "%s" not found in DLL "%s"';


{ ------------------------- }
{ ---- Helper Routines ---- }
{ ------------------------- }

function LoadProcAddress(const AModuleName: TGMString; const AProcName: AnsiString; const ACheck: Boolean = True): Pointer;
var moduleHandle: HMODULE; lastErr: DWORD;
begin
//Result := nil;
  moduleHandle := GetModuleHandle(PGMChar(AModuleName));
  if moduleHandle = 0 then
   begin
    moduleHandle := LoadLibrary(PGMChar(AModuleName));
    if (moduleHandle = 0) and ACheck then
     begin
      lastErr := GetLastError;
      GMAPICheckObjParams('LoadLibrary("'+AModuleName+'")', '', lastErr, moduleHandle <> 0, [PGMChar(AModuleName)]);
      //GMAPICheckObj('LoadLibrary("'+AModuleName+'")', ': "'+AModuleName+'"', lastErr, moduleHandle <> 0);
     end;
   end;

  if moduleHandle = 0 then Result := nil else Result := GetProcAddress(moduleHandle, PAnsiChar(AProcName));
  if not Assigned(Result) and ACheck then raise EOpenSSLError.Create(GMFormat(RStrRoutineNotFound, [AProcName, AModuleName]));
end;

//procedure InitializeOpenSSL;
//type TSslLibraryInit = function: LongInt; cdecl;
//   TSslLoadErrorStrings = procedure; cdecl;
//var _SslLibraryInit: TSslLibraryInit; _SslLoadErrorStrings: TSslLoadErrorStrings;
//begin
//_SslLibraryInit := LoadProcAddress(cStrSSLDllName, 'SSL_library_init', False);
//if Assigned(_SslLibraryInit) then _SslLibraryInit;
//
//_SslLoadErrorStrings := LoadProcAddress(cStrSSLDllName, 'SSL_load_error_strings', False);
//if Assigned(_SslLoadErrorStrings) then _SslLoadErrorStrings;
//
////OpenSSL_add_all_algorithms;
////if assigned(_RandScreen) then _RandScreen;
//end;


{ --------------------- }
{ ---- SSL Library ---- }
{ --------------------- }

{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_get_error: function (ASSL: PSSL; ret_code: LongInt): LongInt; cdecl = nil;

function SSL_get_error;
begin
  if not Assigned(vf_SSL_get_error) then vf_SSL_get_error := LoadProcAddress(cStrSSLDllName, 'SSL_get_error');
  Result := vf_SSL_get_error(ASSL, ret_code);
end;
{$ELSE}
function SSL_get_error; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_library_init: function: LongInt; cdecl = nil;

function SSL_library_init;
begin
  if not Assigned(vf_SSL_library_init) then vf_SSL_library_init := LoadProcAddress(cStrSSLDllName, 'SSL_library_init');
  Result := vf_SSL_library_init;
end;
{$ELSE}
function SSL_library_init; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_load_error_strings: procedure; cdecl = nil;

procedure SSL_load_error_strings;
begin
  if not Assigned(vf_SSL_load_error_strings) then vf_SSL_load_error_strings := LoadProcAddress(cStrSSLDllName, 'SSL_load_error_strings');
  vf_SSL_load_error_strings;
end;
{$ELSE}
procedure SSL_load_error_strings; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_set_cipher_list: function (ASSL: PSSL_CTX; str: PAnsiChar): LongInt; cdecl = nil;

function SSL_CTX_set_cipher_list;
begin
  if not Assigned(vf_SSL_CTX_set_cipher_list) then vf_SSL_CTX_set_cipher_list := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_set_cipher_list');
  Result := vf_SSL_CTX_set_cipher_list(ASSL, str);
end;
{$ELSE}
function SSL_CTX_set_cipher_list; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_new: function (AMethod: PSSL_METHOD): PSSL_CTX; cdecl = nil;

function SSL_CTX_new;
begin
  if not Assigned(vf_SSL_CTX_new) then vf_SSL_CTX_new := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_new');
  Result := vf_SSL_CTX_new(AMethod);
end;
{$ELSE}
function SSL_CTX_new; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_up_ref: function (ASSL: PSSL_CTX): LongInt; cdecl = nil;

function SSL_CTX_up_ref;
begin
  if not Assigned(vf_SSL_CTX_up_ref) then vf_SSL_CTX_up_ref := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_up_ref');
  Result := vf_SSL_CTX_up_ref(ASSL);
end;
{$ELSE}
function SSL_CTX_up_ref; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_free: procedure (ASSL: PSSL_CTX); cdecl = nil;

procedure SSL_CTX_free;
begin
  if not Assigned(vf_SSL_CTX_free) then vf_SSL_CTX_free := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_free');
  vf_SSL_CTX_free(ASSL);
end;
{$ELSE}
procedure SSL_CTX_free; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_state_string: function (ASsl: PSSL): PAnsiChar; cdecl = nil;

function SSL_state_string;
begin
  if not Assigned(vf_SSL_state_string) then vf_SSL_state_string := LoadProcAddress(cStrSSLDllName, 'SSL_state_string');
  Result := vf_SSL_state_string(ASsl);
end;
{$ELSE}
function SSL_state_string; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_state_string_long: function (ASsl: PSSL): PAnsiChar; cdecl = nil;

function SSL_state_string_long;
begin
  if not Assigned(vf_SSL_state_string_long) then vf_SSL_state_string_long := LoadProcAddress(cStrSSLDllName, 'SSL_state_string_long');
  Result := vf_SSL_state_string_long(ASsl);
end;
{$ELSE}
function SSL_state_string_long; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_set_fd: function (ASSL: PSSL; fd: LongInt): LongInt; cdecl = nil;

function SSL_set_fd;
begin
  if not Assigned(vf_SSL_set_fd) then vf_SSL_set_fd := LoadProcAddress(cStrSSLDllName, 'SSL_set_fd');
  Result := vf_SSL_set_fd(ASSL, fd);
end;
{$ELSE}
function SSL_set_fd; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_ctrl: function (ASSL: PSSL; cmd: LongInt; larg: Int64; parg: Pointer): Int64; cdecl = nil;

function SSL_ctrl;
begin
  if not Assigned(vf_SSL_ctrl) then vf_SSL_ctrl := LoadProcAddress(cStrSSLDllName, 'SSL_ctrl');
  Result := vf_SSL_ctrl(ASSL, cmd, larg, parg);
end;
{$ELSE}
function SSL_ctrl; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_ctrl: function (ctx: PSSL_CTX; cmd: LongInt; larg: Int64; parg: Pointer): Int64; cdecl = nil;

function SSL_CTX_ctrl;
begin
  if not Assigned(vf_SSL_CTX_ctrl) then vf_SSL_CTX_ctrl := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_ctrl');
  Result := vf_SSL_CTX_ctrl(ctx, cmd, larg, parg);
end;
{$ELSE}
function SSL_CTX_ctrl; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLS_method: function: PSSL_METHOD; cdecl = nil;

function TLS_method;
begin
  if not Assigned(vf_TLS_method) then vf_TLS_method := LoadProcAddress(cStrSSLDllName, 'TLS_method');
  Result := vf_TLS_method;
end;
{$ELSE}
function TLS_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLS_client_method: function: PSSL_METHOD; cdecl = nil;

function TLS_client_method;
begin
  if not Assigned(vf_TLS_client_method) then vf_TLS_client_method := LoadProcAddress(cStrSSLDllName, 'TLS_client_method');
  Result := vf_TLS_client_method;
end;
{$ELSE}
function TLS_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLS_server_method: function: PSSL_METHOD; cdecl = nil;

function TLS_server_method;
begin
  if not Assigned(vf_TLS_server_method) then vf_TLS_server_method := LoadProcAddress(cStrSSLDllName, 'TLS_server_method');
  Result := vf_TLS_server_method;
end;
{$ELSE}
function TLS_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSLv23_method: function: PSSL_METHOD; cdecl = nil;

function SSLv23_method;
begin
  if not Assigned(vf_SSLv23_method) then vf_SSLv23_method := LoadProcAddress(cStrSSLDllName, 'SSLv23_method');
  Result := vf_SSLv23_method;
end;
{$ELSE}
function SSLv23_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSLv23_server_method: function: PSSL_METHOD; cdecl = nil;

function SSLv23_server_method;
begin
  if not Assigned(vf_SSLv23_server_method) then vf_SSLv23_server_method := LoadProcAddress(cStrSSLDllName, 'SSLv23_server_method');
  Result := vf_SSLv23_server_method;
end;
{$ELSE}
function SSLv23_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSLv23_client_method: function: PSSL_METHOD; cdecl = nil;

function SSLv23_client_method;
begin
  if not Assigned(vf_SSLv23_client_method) then vf_SSLv23_client_method := LoadProcAddress(cStrSSLDllName, 'SSLv23_client_method');
  Result := vf_SSLv23_client_method;
end;
{$ELSE}
function SSLv23_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_method;
begin
  if not Assigned(vf_TLSv1_method) then vf_TLSv1_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_method');
  Result := vf_TLSv1_method;
end;
{$ELSE}
function TLSv1_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_server_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_server_method;
begin
  if not Assigned(vf_TLSv1_server_method) then vf_TLSv1_server_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_server_method');
  Result := vf_TLSv1_server_method;
end;
{$ELSE}
function TLSv1_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_client_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_client_method;
begin
  if not Assigned(vf_TLSv1_client_method) then vf_TLSv1_client_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_client_method');
  Result := vf_TLSv1_client_method;
end;
{$ELSE}
function TLSv1_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_1_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_1_method;
begin
  if not Assigned(vf_TLSv1_1_method) then vf_TLSv1_1_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_1_method');
  Result := vf_TLSv1_1_method;
end;
{$ELSE}
function TLSv1_1_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_1_server_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_1_server_method;
begin
  if not Assigned(vf_TLSv1_1_server_method) then vf_TLSv1_1_server_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_1_server_method');
  Result := vf_TLSv1_1_server_method;
end;
{$ELSE}
function TLSv1_1_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_1_client_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_1_client_method;
begin
  if not Assigned(vf_TLSv1_1_client_method) then vf_TLSv1_1_client_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_1_client_method');
  Result := vf_TLSv1_1_client_method;
end;
{$ELSE}
function TLSv1_1_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_2_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_2_method;
begin
  if not Assigned(vf_TLSv1_2_method) then vf_TLSv1_2_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_2_method');
  Result := vf_TLSv1_2_method;
end;
{$ELSE}
function TLSv1_2_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_2_server_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_2_server_method;
begin
  if not Assigned(vf_TLSv1_2_server_method) then vf_TLSv1_2_server_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_2_server_method');
  Result := vf_TLSv1_2_server_method;
end;
{$ELSE}
function TLSv1_2_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_TLSv1_2_client_method: function: PSSL_METHOD; cdecl = nil;

function TLSv1_2_client_method;
begin
  if not Assigned(vf_TLSv1_2_client_method) then vf_TLSv1_2_client_method := LoadProcAddress(cStrSSLDllName, 'TLSv1_2_client_method');
  Result := vf_TLSv1_2_client_method;
end;
{$ELSE}
function TLSv1_2_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLS_method: function: PSSL_METHOD; cdecl = nil;

function DTLS_method;
begin
  if not Assigned(vf_DTLS_method) then vf_DTLS_method := LoadProcAddress(cStrSSLDllName, 'DTLS_method');
  Result := vf_DTLS_method;
end;
{$ELSE}
function DTLS_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLS_server_method: function: PSSL_METHOD; cdecl = nil;

function DTLS_server_method;
begin
  if not Assigned(vf_DTLS_server_method) then vf_DTLS_server_method := LoadProcAddress(cStrSSLDllName, 'DTLS_server_method');
  Result := vf_DTLS_server_method;
end;
{$ELSE}
function DTLS_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLS_client_method: function: PSSL_METHOD; cdecl = nil;

function DTLS_client_method;
begin
  if not Assigned(vf_DTLS_client_method) then vf_DTLS_client_method := LoadProcAddress(cStrSSLDllName, 'DTLS_client_method');
  Result := vf_DTLS_client_method;
end;
{$ELSE}
function DTLS_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLSv1_method: function: PSSL_METHOD; cdecl = nil;

function DTLSv1_method;
begin
  if not Assigned(vf_DTLSv1_method) then vf_DTLSv1_method := LoadProcAddress(cStrSSLDllName, 'DTLSv1_method');
  Result := vf_DTLSv1_method;
end;
{$ELSE}
function DTLSv1_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLSv1_server_method: function: PSSL_METHOD; cdecl = nil;

function DTLSv1_server_method;
begin
  if not Assigned(vf_DTLSv1_server_method) then vf_DTLSv1_server_method := LoadProcAddress(cStrSSLDllName, 'DTLSv1_server_method');
  Result := vf_DTLSv1_server_method;
end;
{$ELSE}
function DTLSv1_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLSv1_client_method: function: PSSL_METHOD; cdecl = nil;

function DTLSv1_client_method;
begin
  if not Assigned(vf_DTLSv1_client_method) then vf_DTLSv1_client_method := LoadProcAddress(cStrSSLDllName, 'DTLSv1_client_method');
  Result := vf_DTLSv1_client_method;
end;
{$ELSE}
function DTLSv1_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLSv1_2_method: function: PSSL_METHOD; cdecl = nil;

function DTLSv1_2_method;
begin
  if not Assigned(vf_DTLSv1_2_method) then vf_DTLSv1_2_method := LoadProcAddress(cStrSSLDllName, 'DTLSv1_2_method');
  Result := vf_DTLSv1_2_method;
end;
{$ELSE}
function DTLSv1_2_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLSv1_2_server_method: function: PSSL_METHOD; cdecl = nil;

function DTLSv1_2_server_method;
begin
  if not Assigned(vf_DTLSv1_2_server_method) then vf_DTLSv1_2_server_method := LoadProcAddress(cStrSSLDllName, 'DTLSv1_2_server_method');
  Result := vf_DTLSv1_2_server_method;
end;
{$ELSE}
function DTLSv1_2_server_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DTLSv1_2_client_method: function: PSSL_METHOD; cdecl = nil;

function DTLSv1_2_client_method;
begin
  if not Assigned(vf_DTLSv1_2_client_method) then vf_DTLSv1_2_client_method := LoadProcAddress(cStrSSLDllName, 'DTLSv1_2_client_method');
  Result := vf_DTLSv1_2_client_method;
end;
{$ELSE}
function DTLSv1_2_client_method; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_use_certificate: function (ASSL: PSSL; cert: PX509): LongInt; cdecl = nil;

function SSL_use_certificate;
begin
  if not Assigned(vf_SSL_use_certificate) then vf_SSL_use_certificate := LoadProcAddress(cStrSSLDllName, 'SSL_use_certificate');
  Result := vf_SSL_use_certificate(ASSL, cert);
end;
{$ELSE}
function SSL_use_certificate; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_use_certificate_ASN1: function (ASSL: PSSL; data: TSslPtr; datalen: LongInt): LongInt; cdecl = nil;

function SSL_use_certificate_ASN1;
begin
  if not Assigned(vf_SSL_use_certificate_ASN1) then vf_SSL_use_certificate_ASN1 := LoadProcAddress(cStrSSLDllName, 'SSL_use_certificate_ASN1');
  Result := vf_SSL_use_certificate_ASN1(ASSL, data, dataLen);
end;
{$ELSE}
function SSL_use_certificate_ASN1; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_use_certificate_file: function (assl: PSSL; filename: PAnsiChar; filetype: LongInt): LongInt; cdecl = nil;

function SSL_use_certificate_file;
begin
  if not Assigned(vf_SSL_use_certificate_file) then vf_SSL_use_certificate_file := LoadProcAddress(cStrSSLDllName, 'SSL_use_certificate_file');
  Result := vf_SSL_use_certificate_file(assl, filename, filetype);
end;
{$ELSE}
function SSL_use_certificate_file; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_use_PrivateKey: function (assl: PSSL; pkey: PEVP_PKEY): LongInt; cdecl = nil;

function SSL_use_PrivateKey;
begin
  if not Assigned(vf_SSL_use_PrivateKey) then vf_SSL_use_PrivateKey := LoadProcAddress(cStrSSLDllName, 'SSL_use_PrivateKey');
  Result := vf_SSL_use_PrivateKey(assl, pkey);
end;
{$ELSE}
function SSL_use_PrivateKey; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_use_PrivateKey_ASN1: function (keyKind: LongInt; ssl: PSSL; keydata: Pointer; datalen: LongInt): LongInt; cdecl = nil;

function SSL_use_PrivateKey_ASN1;
begin
  if not Assigned(vf_SSL_use_PrivateKey_ASN1) then vf_SSL_use_PrivateKey_ASN1 := LoadProcAddress(cStrSSLDllName, 'SSL_use_PrivateKey_ASN1');
  Result := vf_SSL_use_PrivateKey_ASN1(keykind, ssl, keydata, datalen);
end;
{$ELSE}
function SSL_use_PrivateKey_ASN1; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_use_PrivateKey_file: function (ssl: PSSL; filename: PAnsiChar; filetype: LongInt): LongInt; cdecl = nil;

function SSL_use_PrivateKey_file;
begin
  if not Assigned(vf_SSL_use_PrivateKey_file) then vf_SSL_use_PrivateKey_file := LoadProcAddress(cStrSSLDllName, 'SSL_use_PrivateKey_file');
  Result := vf_SSL_use_PrivateKey_file(ssl, filename, filetype);
end;
{$ELSE}
function SSL_use_PrivateKey_file; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_use_PrivateKey: function (ctx: PSSL_CTX; pkey: TSslPtr): LongInt; cdecl = nil;

function SSL_CTX_use_PrivateKey;
begin
  if not Assigned(vf_SSL_CTX_use_PrivateKey) then vf_SSL_CTX_use_PrivateKey := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_use_PrivateKey');
  Result := vf_SSL_CTX_use_PrivateKey(ctx, pkey);
end;
{$ELSE}
function SSL_CTX_use_PrivateKey; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_use_PrivateKey_ASN1: function (pk: LongInt; ctx: PSSL_CTX; d: TSslPtr; len: LongInt): LongInt; cdecl = nil;

function SSL_CTX_use_PrivateKey_ASN1;
begin
  if not Assigned(vf_SSL_CTX_use_PrivateKey_ASN1) then vf_SSL_CTX_use_PrivateKey_ASN1 := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_use_PrivateKey_ASN1');
  Result := vf_SSL_CTX_use_PrivateKey_ASN1(pk, ctx, d, len);
end;
{$ELSE}
function SSL_CTX_use_PrivateKey_ASN1; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_use_RSAPrivateKey_file: function (ctx: PSSL_CTX; filename: PAnsiChar; _type: LongInt): LongInt; cdecl = nil;

function SSL_CTX_use_RSAPrivateKey_file;
begin
  if not Assigned(vf_SSL_CTX_use_RSAPrivateKey_file) then vf_SSL_CTX_use_RSAPrivateKey_file := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_use_RSAPrivateKey_file');
  Result := vf_SSL_CTX_use_RSAPrivateKey_file(ctx, filename, _type);
end;
{$ELSE}
function SSL_CTX_use_RSAPrivateKey_file; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_use_certificate: function (ctx: PSSL_CTX; cert: TSslPtr): LongInt; cdecl = nil;

function SSL_CTX_use_certificate;
begin
  if not Assigned(vf_SSL_CTX_use_certificate) then vf_SSL_CTX_use_certificate := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_use_certificate');
  Result := vf_SSL_CTX_use_certificate(ctx, cert);
end;
{$ELSE}
function SSL_CTX_use_certificate; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_use_certificate_ASN1: function (ctx: PSSL_CTX; len: LongInt; certdata: TSslPtr): LongInt; cdecl = nil;

function SSL_CTX_use_certificate_ASN1;
begin
  if not Assigned(vf_SSL_CTX_use_certificate_ASN1) then vf_SSL_CTX_use_certificate_ASN1 := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_use_certificate_ASN1');
  Result := vf_SSL_CTX_use_certificate_ASN1(ctx, len, certdata);
end;
{$ELSE}
function SSL_CTX_use_certificate_ASN1; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_use_certificate_file: function (ctx: PSSL_CTX; filename: PAnsiChar; filetype: LongInt): LongInt; cdecl = nil;

function SSL_CTX_use_certificate_file;
begin
  if not Assigned(vf_SSL_CTX_use_certificate_file) then vf_SSL_CTX_use_certificate_file := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_use_certificate_file');
  Result := vf_SSL_CTX_use_certificate_file(ctx, filename, filetype);
end;
{$ELSE}
function SSL_CTX_use_certificate_file; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_use_certificate_chain_file: function (ctx: PSSL_CTX; filename: PAnsiChar): LongInt; cdecl = nil;

function SSL_CTX_use_certificate_chain_file;
begin
  if not Assigned(vf_SSL_CTX_use_certificate_chain_file) then vf_SSL_CTX_use_certificate_chain_file := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_use_certificate_chain_file');
  Result := vf_SSL_CTX_use_certificate_chain_file(ctx, filename);
end;
{$ELSE}
function SSL_CTX_use_certificate_chain_file; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_check_private_key: function (ctx: PSSL_CTX): LongInt; cdecl = nil;

function SSL_CTX_check_private_key;
begin
  if not Assigned(vf_SSL_CTX_check_private_key) then vf_SSL_CTX_check_private_key := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_check_private_key');
  Result := vf_SSL_CTX_check_private_key(ctx);
end;
{$ELSE}
function SSL_CTX_check_private_key; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_set_default_passwd_cb: procedure (ctx: PSSL_CTX; cb: TSslPtr); cdecl = nil;

procedure SSL_CTX_set_default_passwd_cb;
begin
  if not Assigned(vf_SSL_CTX_set_default_passwd_cb) then vf_SSL_CTX_set_default_passwd_cb := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_set_default_passwd_cb');
  vf_SSL_CTX_set_default_passwd_cb(ctx, cb);
end;
{$ELSE}
procedure SSL_CTX_set_default_passwd_cb; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_set_default_passwd_cb_userdata: procedure (ctx: PSSL_CTX; u: TSslPtr); cdecl = nil;

procedure SSL_CTX_set_default_passwd_cb_userdata;
begin
  if not Assigned(vf_SSL_CTX_set_default_passwd_cb_userdata) then vf_SSL_CTX_set_default_passwd_cb_userdata := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_set_default_passwd_cb_userdata');
  vf_SSL_CTX_set_default_passwd_cb_userdata(ctx, u);
end;
{$ELSE}
procedure SSL_CTX_set_default_passwd_cb_userdata; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_load_verify_locations: function (ctx: PSSL_CTX; filename: PAnsiChar; path: PAnsiChar): LongInt; cdecl = nil;

function SSL_CTX_load_verify_locations;
begin
  if not Assigned(vf_SSL_CTX_load_verify_locations) then vf_SSL_CTX_load_verify_locations := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_load_verify_locations');
  Result := vf_SSL_CTX_load_verify_locations(ctx, filename, path);
end;
{$ELSE}
function SSL_CTX_load_verify_locations; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_set_cert_store: procedure (pSslCtx: PSSL_CTX; pCertStore: PX509_STORE); cdecl = nil;

procedure SSL_CTX_set_cert_store;
begin
  if not Assigned(vf_SSL_CTX_set_cert_store) then vf_SSL_CTX_set_cert_store := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_set_cert_store');
  vf_SSL_CTX_set_cert_store(pSslCtx, pCertStore);
end;
{$ELSE}
procedure SSL_CTX_set_cert_store; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_set1_cert_store: procedure (pSslCtx: PSSL_CTX; pCertStore: PX509_STORE); cdecl = nil;

procedure SSL_CTX_set1_cert_store;
begin
  if not Assigned(vf_SSL_CTX_set1_cert_store) then vf_SSL_CTX_set1_cert_store := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_set1_cert_store');
  vf_SSL_CTX_set1_cert_store(pSslCtx, pCertStore);
end;
{$ELSE}
procedure SSL_CTX_set1_cert_store; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_get_cert_store: function (pSslCtx: PSSL_Ctx): PX509_STORE; cdecl = nil;

function SSL_CTX_get_cert_store;
begin
  if not Assigned(vf_SSL_CTX_get_cert_store) then vf_SSL_CTX_get_cert_store := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_get_cert_store');
  Result := vf_SSL_CTX_get_cert_store(pSslCtx);
end;
{$ELSE}
function SSL_CTX_get_cert_store; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_new: function (ctx: PSSL_CTX): PSSL; cdecl = nil;

function SSL_new;
begin
  if not Assigned(vf_SSL_new) then vf_SSL_new := LoadProcAddress(cStrSSLDllName, 'SSL_new');
  Result := vf_SSL_new(ctx);
end;
{$ELSE}
function SSL_new; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_free: procedure (ssl: PSSL); cdecl = nil;

procedure SSL_free;
begin
  if not Assigned(vf_SSL_free) then vf_SSL_free := LoadProcAddress(cStrSSLDllName, 'SSL_free');
  vf_SSL_free(ssl);
end;
{$ELSE}
procedure SSL_free; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_accept: function (ssl: PSSL): LongInt; cdecl = nil;

function SSL_accept;
begin
  if not Assigned(vf_SSL_accept) then vf_SSL_accept := LoadProcAddress(cStrSSLDllName, 'SSL_accept');
  Result := vf_SSL_accept(ssl);
end;
{$ELSE}
function SSL_accept; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_connect: function (ssl: PSSL): LongInt; cdecl = nil;

function SSL_connect;
begin
  if not Assigned(vf_SSL_connect) then vf_SSL_connect := LoadProcAddress(cStrSSLDllName, 'SSL_connect');
  Result := vf_SSL_connect(ssl);
end;
{$ELSE}
function SSL_connect; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_shutdown: function (ssl: PSSL): LongInt; cdecl = nil;

function SSL_shutdown;
begin
  if not Assigned(vf_SSL_shutdown) then vf_SSL_shutdown := LoadProcAddress(cStrSSLDllName, 'SSL_shutdown');
  Result := vf_SSL_shutdown(ssl);
end;
{$ELSE}
function SSL_shutdown; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_read: function (ssl: PSSL; buf: PAnsiChar; buflen: LongInt): LongInt; cdecl = nil;

function SSL_read;
begin
  if not Assigned(vf_SSL_read) then vf_SSL_read := LoadProcAddress(cStrSSLDllName, 'SSL_read');
  Result := vf_SSL_read(ssl, buf, buflen);
end;
{$ELSE}
function SSL_read; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_peek: function (ssl: PSSL; buf: PAnsiChar; buflen: LongInt): LongInt; cdecl = nil;

function SSL_peek;
begin
  if not Assigned(vf_SSL_peek) then vf_SSL_peek := LoadProcAddress(cStrSSLDllName, 'SSL_peek');
  Result := vf_SSL_peek(ssl, buf, buflen);
end;
{$ELSE}
function SSL_peek; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_write: function (ssl: PSSL; buf: PAnsiChar; buflen: LongInt): LongInt; cdecl = nil;

function SSL_write;
begin
  if not Assigned(vf_SSL_write) then vf_SSL_write := LoadProcAddress(cStrSSLDllName, 'SSL_write');
  Result := vf_SSL_write(ssl, buf, buflen);
end;
{$ELSE}
function SSL_write; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_pending: function (ssl: PSSL): LongInt; cdecl = nil;

function SSL_pending;
begin
  if not Assigned(vf_SSL_pending) then vf_SSL_pending := LoadProcAddress(cStrSSLDllName, 'SSL_pending');
  Result := vf_SSL_pending(ssl);
end;
{$ELSE}
function SSL_pending; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_get_version: function (ssl: PSSL): PAnsiChar; cdecl = nil;

function SSL_get_version;
begin
  if not Assigned(vf_SSL_get_version) then vf_SSL_get_version := LoadProcAddress(cStrSSLDllName, 'SSL_get_version');
  Result := vf_SSL_get_version(ssl);
end;
{$ELSE}
function SSL_get_version; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_get_peer_certificate: function (ssl: PSSL): PX509; cdecl = nil;

function SSL_get_peer_certificate;
begin
  if not Assigned(vf_SSL_get_peer_certificate) then vf_SSL_get_peer_certificate := LoadProcAddress(cStrSSLDllName, 'SSL_get_peer_certificate');
  Result := vf_SSL_get_peer_certificate(ssl);
end;
{$ELSE}
function SSL_get_peer_certificate; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_set_verify: procedure (ctx: PSSL_CTX; mode: LongInt; arg2: TSslPtr); cdecl = nil;

procedure SSL_CTX_set_verify;
begin
  if not Assigned(vf_SSL_CTX_set_verify) then vf_SSL_CTX_set_verify := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_set_verify');
  vf_SSL_CTX_set_verify(ctx, mode, arg2);
end;
{$ELSE}
procedure SSL_CTX_set_verify; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_set_options: function (ctx: PSSL_CTX; options: QWord): QWord; cdecl = nil;

function SSL_CTX_set_options;
begin
  if not Assigned(vf_SSL_CTX_set_options) then vf_SSL_CTX_set_options := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_set_options');
  Result := vf_SSL_CTX_set_options(ctx, options);
end;
{$ELSE}
function SSL_CTX_set_options; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CTX_clear_options: function (ctx: PSSL_CTX; options: QWord): QWord; cdecl = nil;

function SSL_CTX_clear_options;
begin
  if not Assigned(vf_SSL_CTX_clear_options) then vf_SSL_CTX_clear_options := LoadProcAddress(cStrSSLDllName, 'SSL_CTX_clear_options');
  Result := vf_SSL_CTX_clear_options(ctx, options);
end;
{$ELSE}
function SSL_CTX_clear_options; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_get_current_cipher: function (assl: PSSL): TSslPtr; cdecl = nil;

function SSL_get_current_cipher;
begin
  if not Assigned(vf_SSL_get_current_cipher) then vf_SSL_get_current_cipher := LoadProcAddress(cStrSSLDllName, 'SSL_get_current_cipher');
  Result := vf_SSL_get_current_cipher(assl);
end;
{$ELSE}
function SSL_get_current_cipher; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CIPHER_get_name: function (cipher: PSSL_CIPHER): PAnsiChar; cdecl = nil;

function SSL_CIPHER_get_name;
begin
  if not Assigned(vf_SSL_CIPHER_get_name) then vf_SSL_CIPHER_get_name := LoadProcAddress(cStrSSLDllName, 'SSL_CIPHER_get_name');
  Result := vf_SSL_CIPHER_get_name(cipher);
end;
{$ELSE}
function SSL_CIPHER_get_name; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CIPHER_get_bits: function (cipher: PSSL_CIPHER; alg_bits: PLongInt): LongInt; cdecl = nil;

function SSL_CIPHER_get_bits;
begin
  if not Assigned(vf_SSL_CIPHER_get_bits) then vf_SSL_CIPHER_get_bits := LoadProcAddress(cStrSSLDllName, 'SSL_CIPHER_get_bits');
  Result := vf_SSL_CIPHER_get_bits(cipher, alg_bits);
end;
{$ELSE}
function SSL_CIPHER_get_bits; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CIPHER_get_version: function (cipher: PSSL_CIPHER): PAnsiChar; cdecl = nil;

function SSL_CIPHER_get_version;
begin
  if not Assigned(vf_SSL_CIPHER_get_version) then vf_SSL_CIPHER_get_version := LoadProcAddress(cStrSSLDllName, 'SSL_CIPHER_get_version');
  Result := vf_SSL_CIPHER_get_version(cipher);
end;
{$ELSE}
function SSL_CIPHER_get_version; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_CIPHER_description: function (cipher: PSSL_CIPHER; buffer: PAnsiChar; bufSize: LongInt): PAnsiChar; cdecl = nil;

function SSL_CIPHER_description;
begin
  if not Assigned(vf_SSL_CIPHER_description) then vf_SSL_CIPHER_description := LoadProcAddress(cStrSSLDllName, 'SSL_CIPHER_description');
  Result := vf_SSL_CIPHER_description(cipher, buffer, bufSize);
end;
{$ELSE}
function SSL_CIPHER_description; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_get_verify_result: function (ssl: PSSL): LongInt; cdecl = nil;

function SSL_get_verify_result;
begin
  if not Assigned(vf_SSL_get_verify_result) then vf_SSL_get_verify_result := LoadProcAddress(cStrSSLDllName, 'SSL_get_verify_result');
  Result := vf_SSL_get_verify_result(ssl);
end;
{$ELSE}
function SSL_get_verify_result; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_set_options: function (ssl: PSSL; options: QWord): QWord; cdecl = nil;

function SSL_set_options;
begin
  if not Assigned(vf_SSL_set_options) then vf_SSL_set_options := LoadProcAddress(cStrSSLDllName, 'SSL_set_options');
  Result := vf_SSL_set_options(ssl, options);
end;
{$ELSE}
function SSL_set_options; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_clear_options: function (ssl: PSSL; options: QWord): QWord; cdecl = nil;

function SSL_clear_options;
begin
  if not Assigned(vf_SSL_clear_options) then vf_SSL_clear_options := LoadProcAddress(cStrSSLDllName, 'SSL_clear_options');
  Result := vf_SSL_clear_options(ssl, options);
end;
{$ELSE}
function SSL_clear_options; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_copy_session_id: procedure (dest, src: PSSL); cdecl = nil;

procedure SSL_copy_session_id;
begin
  if not Assigned(vf_SSL_copy_session_id) then vf_SSL_copy_session_id := LoadProcAddress(cStrSSLDllName, 'SSL_copy_session_id');
  vf_SSL_copy_session_id(dest, src);
end;
{$ELSE}
procedure SSL_copy_session_id; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_get_session: function (ssl: PSSL): PSession; cdecl = nil;

function SSL_get_session;
begin
  if not Assigned(vf_SSL_get_session) then vf_SSL_get_session := LoadProcAddress(cStrSSLDllName, 'SSL_get_session');
  Result := vf_SSL_get_session(ssl);
end;
{$ELSE}
function SSL_get_session; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_SSL_set_session: function (ssl: PSSL; session: PSession): LongInt; cdecl = nil;

function SSL_set_session;
begin
  if not Assigned(vf_SSL_set_session) then vf_SSL_set_session := LoadProcAddress(cStrSSLDllName, 'SSL_set_session');
  Result := vf_SSL_set_session(ssl, session);
end;
{$ELSE}
function SSL_set_session; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OpenSSL_add_all_algorithms: procedure; cdecl = nil;

procedure OpenSSL_add_all_algorithms;
begin
  if not Assigned(vf_OpenSSL_add_all_algorithms) then vf_OpenSSL_add_all_algorithms := LoadProcAddress(cStrSSLDllName, 'OpenSSL_add_all_algorithms');
  vf_OpenSSL_add_all_algorithms;
end;
{$ELSE}
procedure OpenSSL_add_all_algorithms; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OpenSSL_add_all_ciphers: procedure; cdecl = nil;

procedure OpenSSL_add_all_ciphers;
begin
  if not Assigned(vf_OpenSSL_add_all_ciphers) then vf_OpenSSL_add_all_ciphers := LoadProcAddress(cStrSSLDllName, 'OpenSSL_add_all_ciphers');
  vf_OpenSSL_add_all_ciphers;
end;
{$ELSE}
procedure OpenSSL_add_all_ciphers; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OpenSSL_add_all_digests: procedure; cdecl = nil;

procedure OpenSSL_add_all_digests;
begin
  if not Assigned(vf_OpenSSL_add_all_digests) then vf_OpenSSL_add_all_digests := LoadProcAddress(cStrSSLDllName, 'OpenSSL_add_all_digests');
  vf_OpenSSL_add_all_digests;
end;
{$ELSE}
procedure OpenSSL_add_all_digests; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_EVP_cleanup: procedure; cdecl = nil;

procedure EVP_cleanup;
begin
  if not Assigned(vf_EVP_cleanup) then vf_EVP_cleanup := LoadProcAddress(cStrSSLDllName, 'EVP_cleanup');
  vf_EVP_cleanup;
end;
{$ELSE}
procedure EVP_cleanup; external cStrSSLDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{ ------------------------ }
{ ---- Crypto Library ---- }
{ ------------------------ }

{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_get_error: function: LongWord; cdecl = nil;

function ERR_get_error;
begin
  if not Assigned(vf_ERR_get_error) then vf_ERR_get_error := LoadProcAddress(cStrCryptDllName, 'ERR_get_error');
  Result := vf_ERR_get_error;
end;
{$ELSE}
function ERR_get_error; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_peek_error: function: LongWord; cdecl = nil;

function ERR_peek_error;
begin
  if not Assigned(vf_ERR_peek_error) then vf_ERR_peek_error := LoadProcAddress(cStrCryptDllName, 'ERR_peek_error');
  Result := vf_ERR_peek_error;
end;
{$ELSE}
function ERR_peek_error; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_peek_last_error: function: LongWord; cdecl = nil;

function ERR_peek_last_error;
begin
  if not Assigned(vf_ERR_peek_last_error) then vf_ERR_peek_last_error := LoadProcAddress(cStrCryptDllName, 'ERR_peek_last_error');
  Result := vf_ERR_peek_last_error;
end;
{$ELSE}
function ERR_peek_last_error; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_error_string: function (errorCode: LongWord; buffer: PAnsiChar): PAnsiChar; cdecl = nil;

function ERR_error_string;
begin
  if not Assigned(vf_ERR_error_string) then vf_ERR_error_string := LoadProcAddress(cStrCryptDllName, 'ERR_error_string');
  Result := vf_ERR_error_string(errorCode, buffer);
end;
{$ELSE}
function ERR_error_string; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_error_string_n: procedure (errorCode: LongWord; buffer: PAnsiChar; bufSize: size_t); cdecl = nil;

procedure ERR_error_string_n;
begin
  if not Assigned(vf_ERR_error_string_n) then vf_ERR_error_string_n := LoadProcAddress(cStrCryptDllName, 'ERR_error_string_n');
  vf_ERR_error_string_n(errorCode, buffer, bufSize);
end;
{$ELSE}
procedure ERR_error_string_n; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_lib_error_string: function (errorCode: LongWord): PAnsiChar; cdecl = nil;

function ERR_lib_error_string;
begin
  if not Assigned(vf_ERR_lib_error_string) then vf_ERR_lib_error_string := LoadProcAddress(cStrCryptDllName, 'ERR_lib_error_string');
  Result := vf_ERR_lib_error_string(errorCode);
end;
{$ELSE}
function ERR_lib_error_string; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_func_error_string: function (errorCode: LongWord): PAnsiChar; cdecl = nil;

function ERR_func_error_string;
begin
  if not Assigned(vf_ERR_func_error_string) then vf_ERR_func_error_string := LoadProcAddress(cStrCryptDllName, 'ERR_func_error_string');
  Result := vf_ERR_func_error_string(errorCode);
end;
{$ELSE}
function ERR_func_error_string; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_reason_error_string: function (errorCode: LongWord): PAnsiChar; cdecl = nil;

function ERR_reason_error_string;
begin
  if not Assigned(vf_ERR_reason_error_string) then vf_ERR_reason_error_string := LoadProcAddress(cStrCryptDllName, 'ERR_reason_error_string');
  Result := vf_ERR_reason_error_string(errorCode);
end;
{$ELSE}
function ERR_reason_error_string; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_remove_state: procedure (threadId: LongWord); cdecl = nil;

procedure ERR_remove_state;
begin
  if not Assigned(vf_ERR_remove_state) then vf_ERR_remove_state := LoadProcAddress(cStrCryptDllName, 'ERR_remove_state');
  vf_ERR_remove_state(threadId);
end;
{$ELSE}
procedure ERR_remove_state; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_ERR_remove_thread_state: procedure (tid: PCRYPTO_THREADID); cdecl = nil;

procedure ERR_remove_thread_state;
begin
  if not Assigned(vf_ERR_remove_thread_state) then vf_ERR_remove_thread_state := LoadProcAddress(cStrCryptDllName, 'ERR_remove_thread_state');
  vf_ERR_remove_thread_state(tid);
end;
{$ELSE}
procedure ERR_remove_thread_state; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OPENSSL_init_new: function: POPENSSL_INIT_SETTINGS; cdecl = nil;

function OPENSSL_init_new;
begin
  if not Assigned(vf_OPENSSL_init_new) then vf_OPENSSL_init_new := LoadProcAddress(cStrCryptDllName, 'OPENSSL_init_new');
  Result := vf_OPENSSL_init_new;
end;
{$ELSE}
function OPENSSL_init_new; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OPENSSL_INIT_set_config_appname: function (init: POPENSSL_INIT_SETTINGS; name: PAnsiChar): LongInt; cdecl = nil;

function OPENSSL_INIT_set_config_appname;
begin
  if not Assigned(vf_OPENSSL_INIT_set_config_appname) then vf_OPENSSL_INIT_set_config_appname := LoadProcAddress(cStrCryptDllName, 'OPENSSL_INIT_set_config_appname');
  Result := vf_OPENSSL_INIT_set_config_appname(init, name);
end;
{$ELSE}
function OPENSSL_INIT_set_config_appname; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OPENSSL_INIT_free: procedure (init: POPENSSL_INIT_SETTINGS); cdecl = nil;

procedure OPENSSL_INIT_free;
begin
  if not Assigned(vf_OPENSSL_INIT_free) then vf_OPENSSL_INIT_free := LoadProcAddress(cStrCryptDllName, 'OPENSSL_INIT_free');
  vf_OPENSSL_INIT_free(init);
end;
{$ELSE}
procedure OPENSSL_INIT_free; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OPENSSL_init_crypto: function (opts: UInt64; settings: POPENSSL_INIT_SETTINGS): LongInt; cdecl = nil;

function OPENSSL_init_crypto;
begin
  if not Assigned(vf_OPENSSL_init_crypto) then vf_OPENSSL_init_crypto := LoadProcAddress(cStrCryptDllName, 'OPENSSL_init_crypto');
  Result := vf_OPENSSL_init_crypto(opts, settings);
end;
{$ELSE}
function OPENSSL_init_crypto; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_OPENSSL_cleanup: procedure; cdecl = nil;

procedure OPENSSL_cleanup;
begin
  if not Assigned(vf_OPENSSL_cleanup) then vf_OPENSSL_cleanup := LoadProcAddress(cStrCryptDllName, 'OPENSSL_cleanup');
  vf_OPENSSL_cleanup;
end;
{$ELSE}
procedure OPENSSL_cleanup; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_CRYPTO_THREADID_set_numeric: procedure (id: PCRYPTO_THREADID; val: LongWord); cdecl = nil;

procedure CRYPTO_THREADID_set_numeric;
begin
  if not Assigned(vf_CRYPTO_THREADID_set_numeric) then vf_CRYPTO_THREADID_set_numeric := LoadProcAddress(cStrCryptDllName, 'CRYPTO_THREADID_set_numeric');
  vf_CRYPTO_THREADID_set_numeric(id, val);
end;
{$ELSE}
procedure CRYPTO_THREADID_set_numeric; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_CRYPTO_THREADID_set_pointer: procedure (id: PCRYPTO_THREADID; ptr: Pointer); cdecl = nil;

procedure CRYPTO_THREADID_set_pointer;
begin
  if not Assigned(vf_CRYPTO_THREADID_set_pointer) then vf_CRYPTO_THREADID_set_pointer := LoadProcAddress(cStrCryptDllName, 'CRYPTO_THREADID_set_pointer');
  vf_CRYPTO_THREADID_set_pointer(id, ptr);
end;
{$ELSE}
procedure CRYPTO_THREADID_set_pointer; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_CRYPTO_THREADID_current: procedure (id: PCRYPTO_THREADID); cdecl = nil;

procedure CRYPTO_THREADID_current;
begin
  if not Assigned(vf_CRYPTO_THREADID_current) then vf_CRYPTO_THREADID_current := LoadProcAddress(cStrCryptDllName, 'CRYPTO_THREADID_current');
  vf_CRYPTO_THREADID_current(id);
end;
{$ELSE}
procedure CRYPTO_THREADID_current; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_new: function: PX509; cdecl = nil;

function X509_new;
begin
  if not Assigned(vf_X509_new) then vf_X509_new := LoadProcAddress(cStrCryptDllName, 'X509_new');
  Result := vf_X509_new;
end;
{$ELSE}
function X509_new; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_free: procedure (x509: PX509); cdecl = nil;

procedure X509_free;
begin
  if not Assigned(vf_X509_free) then vf_X509_free := LoadProcAddress(cStrCryptDllName, 'X509_free');
  vf_X509_free(x509);
end;
{$ELSE}
procedure X509_free; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_random_key: procedure (ret: PDES_cblock); cdecl = nil;

procedure DES_random_key;
begin
  if not Assigned(vf_DES_random_key) then vf_DES_random_key := LoadProcAddress(cStrCryptDllName, 'DES_random_key');
  vf_DES_random_key(ret);
end;
{$ELSE}
procedure DES_random_key; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_set_key: function (Key: PDES_cblock; schedule: PDES_key_schedule): LongInt; cdecl = nil;

function DES_set_key;
begin
  if not Assigned(vf_DES_set_key) then vf_DES_set_key := LoadProcAddress(cStrCryptDllName, 'DES_set_key');
  Result := vf_DES_set_key(key, schedule);
end;
{$ELSE}
function DES_set_key; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_key_sched: function (Key: PDES_cblock; schedule: PDES_key_schedule): LongInt; cdecl = nil;

function DES_key_sched;
begin
  if not Assigned(vf_DES_key_sched) then vf_DES_key_sched := LoadProcAddress(cStrCryptDllName, 'DES_key_sched');
  Result := vf_DES_key_sched(key, schedule);
end;
{$ELSE}
function DES_key_sched; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_set_key_checked: function (Key: PDES_cblock; schedule: PDES_key_schedule): LongInt; cdecl = nil;

function DES_set_key_checked;
begin
  if not Assigned(vf_DES_set_key_checked) then vf_DES_set_key_checked := LoadProcAddress(cStrCryptDllName, 'DES_set_key_checked');
  Result := vf_DES_set_key_checked(key, schedule);
end;
{$ELSE}
function DES_set_key_checked; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_set_key_unchecked: procedure (Key: PDES_cblock; schedule: PDES_key_schedule); cdecl = nil;

procedure DES_set_key_unchecked;
begin
  if not Assigned(vf_DES_set_key_unchecked) then vf_DES_set_key_unchecked := LoadProcAddress(cStrCryptDllName, 'DES_set_key_unchecked');
  vf_DES_set_key_unchecked(key, schedule);
end;
{$ELSE}
procedure DES_set_key_unchecked; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_set_odd_parity: procedure (Key: PDES_cblock); cdecl = nil;

procedure DES_set_odd_parity;
begin
  if not Assigned(vf_DES_set_odd_parity) then vf_DES_set_odd_parity := LoadProcAddress(cStrCryptDllName, 'DES_set_odd_parity');
  vf_DES_set_odd_parity(key);
end;
{$ELSE}
procedure DES_set_odd_parity; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_is_weak_key: function (Key: PDES_cblock): LongInt; cdecl = nil;

function DES_is_weak_key;
begin
  if not Assigned(vf_DES_is_weak_key) then vf_DES_is_weak_key := LoadProcAddress(cStrCryptDllName, 'DES_is_weak_key');
  Result := vf_DES_is_weak_key(key);
end;
{$ELSE}
function DES_is_weak_key; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_ecb_encrypt: procedure (input, output: PDES_cblock; schedule: PDES_key_schedule; enc: LongInt); cdecl = nil;

procedure DES_ecb_encrypt;
begin
  if not Assigned(vf_DES_ecb_encrypt) then vf_DES_ecb_encrypt := LoadProcAddress(cStrCryptDllName, 'DES_ecb_encrypt');
  vf_DES_ecb_encrypt(input, output, schedule, enc);
end;
{$ELSE}
procedure DES_ecb_encrypt; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_ecb2_encrypt: procedure (input, output: PDES_cblock; schedule1, schedule2: PDES_key_schedule; enc: LongInt); cdecl = nil;

procedure DES_ecb2_encrypt;
begin
  if not Assigned(vf_DES_ecb2_encrypt) then vf_DES_ecb2_encrypt := LoadProcAddress(cStrCryptDllName, 'DES_ecb2_encrypt');
  vf_DES_ecb2_encrypt(input, output, schedule1, schedule2, enc);
end;
{$ELSE}
procedure DES_ecb2_encrypt; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_DES_ecb3_encrypt: procedure (input, output: PDES_cblock; schedule1, schedule2, schedule3: PDES_key_schedule; enc: LongInt); cdecl = nil;

procedure DES_ecb3_encrypt;
begin
  if not Assigned(vf_DES_ecb3_encrypt) then vf_DES_ecb3_encrypt := LoadProcAddress(cStrCryptDllName, 'DES_ecb3_encrypt');
  vf_DES_ecb3_encrypt(input, output, schedule1, schedule2, schedule3, enc);
end;
{$ELSE}
procedure DES_ecb3_encrypt; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_STORE_new: function: PX509_STORE; cdecl = nil;

function X509_STORE_new;
begin
  if not Assigned(vf_X509_STORE_new) then vf_X509_STORE_new := LoadProcAddress(cStrCryptDllName, 'X509_STORE_new');
  Result := vf_X509_STORE_new;
end;
{$ELSE}
function X509_STORE_new; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_STORE_free: procedure (pStore: PX509_STORE); cdecl = nil;

procedure X509_STORE_free;
begin
  if not Assigned(vf_X509_STORE_free) then vf_X509_STORE_free := LoadProcAddress(cStrCryptDllName, 'X509_STORE_free');
  vf_X509_STORE_free(pStore);
end;
{$ELSE}
procedure X509_STORE_free; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_STORE_lock: function (pStore: PX509_STORE): LongInt; cdecl = nil;

function X509_STORE_lock;
begin
  if not Assigned(vf_X509_STORE_lock) then vf_X509_STORE_lock := LoadProcAddress(cStrCryptDllName, 'X509_STORE_lock');
  Result := vf_X509_STORE_lock(pStore);
end;
{$ELSE}
function X509_STORE_lock; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_STORE_unlock: function (pStore: PX509_STORE): LongInt; cdecl = nil;

function X509_STORE_unlock;
begin
  if not Assigned(vf_X509_STORE_unlock) then vf_X509_STORE_unlock := LoadProcAddress(cStrCryptDllName, 'X509_STORE_unlock');
  Result := vf_X509_STORE_unlock(pStore);
end;
{$ELSE}
function X509_STORE_unlock; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_STORE_up_ref: function (pStore: PX509_STORE): LongInt; cdecl = nil;

function X509_STORE_up_ref;
begin
  if not Assigned(vf_X509_STORE_up_ref) then vf_X509_STORE_up_ref := LoadProcAddress(cStrCryptDllName, 'X509_STORE_up_ref');
  Result := vf_X509_STORE_up_ref(pStore);
end;
{$ELSE}
function X509_STORE_up_ref; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_d2i_X509: function (ppx509: PPX509; in_Data: PPByte; len: LongInt): PX509; cdecl = nil;

function d2i_X509;
begin
  if not Assigned(vf_d2i_X509) then vf_d2i_X509 := LoadProcAddress(cStrCryptDllName, 'd2i_X509');
  Result := vf_d2i_X509(ppx509, in_Data, len);
end;
{$ELSE}
function d2i_X509; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_i2d_X509: function (px509: PX509; out_Data: PPByte): LongInt; cdecl = nil;

function i2d_X509;
begin
  if not Assigned(vf_i2d_X509) then vf_i2d_X509 := LoadProcAddress(cStrCryptDllName, 'i2d_X509');
  Result := vf_i2d_X509(px509, out_Data);
end;
{$ELSE}
function i2d_X509; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_i2d_re_X509_tbs: function (px509: PX509; out_Data: PPByte): LongInt; cdecl = nil;

function i2d_re_X509_tbs;
begin
  if not Assigned(vf_i2d_re_X509_tbs) then vf_i2d_re_X509_tbs := LoadProcAddress(cStrCryptDllName, 'i2d_re_X509_tbs');
  Result := vf_i2d_re_X509_tbs(px509, out_Data);
end;
{$ELSE}
function i2d_re_X509_tbs; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


{$IFDEF DELAY_LOAD_OPENSSL_DLL}
var vf_X509_STORE_add_cert: function (pStore: PX509_STORE; cert: PX509): LongInt; cdecl = nil;

function X509_STORE_add_cert;
begin
  if not Assigned(vf_X509_STORE_add_cert) then vf_X509_STORE_add_cert := LoadProcAddress(cStrCryptDllName, 'X509_STORE_add_cert');
  Result := vf_X509_STORE_add_cert(pStore, cert);
end;
{$ELSE}
function X509_STORE_add_cert; external cStrCryptDllName;
{$ENDIF DELAY_LOAD_OPENSSL_DLL}


end.