|
| 1 | +This "proposed update" to IndySockets/Indy adds support for OpenSSL 3.0 and |
| 2 | +later to Indy. Both Delphi and Lazarus/fpc are fully supported by this source code tree. |
| 3 | + |
| 4 | +This provides a new (optional) OpenSSL package separate from Indy's "protocols" package |
| 5 | +and adds support for OpenSSL 3.0 and later. Both Delphi and Lazarus/fpc are fully |
| 6 | +supported by this source code tree. |
| 7 | + |
| 8 | +Three link models are supported. |
| 9 | + * Dynamic Library Load (the default and the approach used in previous versions) |
| 10 | + * compile time linkage to a shared (.so or .dll) library (OpenSSL 3.x only) |
| 11 | + * compile time linkage to a static library (FPC only with gcc compiled OpenSSL). |
| 12 | + |
| 13 | +For dynamic library load, a "Just in Time" approach is used where each API call is initialised to a local proc "loader" function. |
| 14 | +The intent is that on the first call a given API function, the actual entry point in the OpenSSL function |
| 15 | +is loaded and the API call is set to the loaded entry point. The API function is now called on the user's |
| 16 | +behalf. If the call fails to load then it is replaced by a compatibility function (if one exists). If none exists |
| 17 | +then an exception is raised. If an API function is allowed to be nil (as set in the template), then the function |
| 18 | +is loaded at library load time. |
| 19 | + |
| 20 | + |
| 21 | +The updated package has been tested under the following scenarios: |
| 22 | + |
| 23 | +1. Static Linking to Static Library (Lazarus/Linux only with gcc generated libssl.a and libcrypto.a). |
| 24 | + |
| 25 | +2. Static Linking to Shared Library (DLL/so). Delphi and Lazarus (Windows and Linux). |
| 26 | + |
| 27 | +3. Dynamic Load and Link. Delphi and Lazarus (Windows and Linux). OpenSSL 1.0.2, 1.1.1. and 3.x |
| 28 | + |
| 29 | +For (2) and (3) above, the different link strategies are selected at compile time by a "defined symbol" set in the OpenSSL |
| 30 | +package options (not the using program), as follows: |
| 31 | + |
| 32 | +- OPENSSL_USE_STATIC_LIBRARY (Static Linking to Static Library) |
| 33 | +- OPENSSL_USE_SHARED_LIBRARY (Static Linking to Shared Library) |
| 34 | +- Neither of the above (Dynamic Load and Link). |
| 35 | + |
| 36 | +Note that (2) and (3) behave identically for Static and Shared library linking). |
| 37 | + |
| 38 | +The defined synbol OPENSSL_NO_LEGACY_SUPPORT may also be set at compile time and applies to Dynamic |
| 39 | +loading. If set, no compatibility functions are compile in to the executeable. Only 3.0 or later |
| 40 | +API calls may be used. |
| 41 | + |
| 42 | + |
| 43 | +Delphi Builds |
| 44 | +============= |
| 45 | + |
| 46 | +All Protocols/IndyProtocolsnnn.dpk and dproj files have been edited to remove references to the moved files. |
| 47 | +However only Protocols/IndyProtocols290 has been tested (with Delphi Berlin edition). |
| 48 | + |
| 49 | +New Packages: |
| 50 | + |
| 51 | +IndyOpenSSL290 and |
| 52 | +dclIndyOpenSSL290 (design time only) |
| 53 | + |
| 54 | +may be found in Lib\OpenSSL\. |
| 55 | + |
| 56 | +These are dependent on IndyProtocols290 and dclIndyProtocols290,IndyOpenSSLLegacy290 respectively. |
| 57 | + |
| 58 | +To use OpenSSL in a given project, the IndyOpenSSL290 package must now be included. |
| 59 | + |
| 60 | +Lib\Indy290.groupproj has been updated to include the new packages in the project group. |
| 61 | + |
| 62 | +icons\makedcr.bat has been updated to generate a .dcr package for the OpenSSL packages. |
| 63 | + |
| 64 | +Lazarus/FPC Builds |
| 65 | +================== |
| 66 | + |
| 67 | +All lazarus packages may be found in the "lazarus-fpc/" top level folder. These are: |
| 68 | + |
| 69 | +indysystem.lpk |
| 70 | +indycore.lpk |
| 71 | +indyprotocols.lpk |
| 72 | +indyopenssl.lpk |
| 73 | + |
| 74 | +and the design time only packages |
| 75 | + |
| 76 | +indylaz.lpk |
| 77 | +indylaz_indyopenssl |
| 78 | + |
| 79 | +In order to install this proposed update for Lazarus (Windows and Linux), Open first |
| 80 | +that package indylaz.lpk and click on install. Then Open the package indylaz_openssl.lpk and |
| 81 | +click on install. The Indy Library should now be available for use. |
| 82 | + |
| 83 | +You can also use fpcmake to create a makefile for building the full package. Run |
| 84 | + |
| 85 | +fpcmake -r |
| 86 | + |
| 87 | +in the package's root directiory. |
| 88 | + |
| 89 | +Test Programs |
| 90 | +============= |
| 91 | + |
| 92 | +Two test programs are available with variants for Delphi and Lazarus. These may be found in: |
| 93 | + |
| 94 | +1. Test/OpenSSL/openssl-client and |
| 95 | +2. Test/OpenSSL/openssl-server. |
| 96 | + |
| 97 | +openssl-client uses an HTTP Client to issue an http Get on an https target and returns |
| 98 | +the result. The server certificate is also verified. |
| 99 | + |
| 100 | +openssl-server provides both and a server and uses a local PKI to retrieve a web page |
| 101 | +from the server, with both client and server certificate verification and to return the result. |
| 102 | + |
| 103 | +Note: in all cases the compiled programs are placed in the openssl-client or openssl-server |
| 104 | +directories. |
| 105 | + |
| 106 | +Note that for Delphi, a convenience project group is provided: |
| 107 | + |
| 108 | +Test\OpenSSL\OpenSSLTests.groupprog |
| 109 | + |
| 110 | +These build both test programs and their supporting packages as a single project group. You do |
| 111 | +not have to install the design time packages in order to use the test programs. |
| 112 | + |
| 113 | +When testing under Lazarus, similarly you do not need to have installed the design time packages. |
| 114 | +However, you need to at least "open" the dependent packages so that the IDE knows where to find |
| 115 | +them. |
| 116 | + |
| 117 | +Test program command line arguments: |
| 118 | + |
| 119 | +Usage: fpc_openssl_client [-h] [-n] [-l <cacerts dir>] [-L] [OpenSSL lib dir] |
| 120 | + |
| 121 | +Usage: fpc_openssl_client [-h] [-n] [-l <cacerts dir>] [-L] [OpenSSL lib dir] |
| 122 | + |
| 123 | +-L is useful under Linux when the OpenSSL Library used has not been installed and |
| 124 | + hence does not know where to find its X.509 certificate store. When -L is |
| 125 | + given, the program searches a list of possible locations. |
| 126 | + |
| 127 | +Runtime Control of the Library Loader |
| 128 | +===================================== |
| 129 | + |
| 130 | +The OpenSSLAPI unit provides two Pascal COM interfaces which provide information and option selection for the OpenSSL Library. |
| 131 | + |
| 132 | +The IOpenSSL Interface |
| 133 | +---------------------- |
| 134 | + |
| 135 | +This interface is available for all link strategies and the interface is accessed using the function: |
| 136 | + function GetIOpenSSL: IOpenSSL; |
| 137 | + |
| 138 | +The interface is declared as: |
| 139 | + IOpenSSL = interface |
| 140 | + ['{aed66223-1700-4199-b1c5-8222648e8cd5}'] |
| 141 | + function GetOpenSSLPath: string; |
| 142 | + function GetOpenSSLVersionStr: string; |
| 143 | + function GetOpenSSLVersion: TOpenSSL_C_ULONG; |
| 144 | + function Init: boolean; |
| 145 | + end; |
| 146 | + |
| 147 | +function GetOpenSSLPath: string; |
| 148 | + |
| 149 | +Static Linking: Returns the OpenSSL installation path as compiled into the OpenSSL library. |
| 150 | +Dynamic Loading: Returns |
| 151 | + • The same as above when the library is loaded |
| 152 | + • the specified OpenSSL installation path, otherwise. |
| 153 | + |
| 154 | +function GetOpenSSLVersionStr: string |
| 155 | + |
| 156 | +Returns the OpenSSL library version string. e.g “OpenSSL 3.2.0 23 Nov 2023” |
| 157 | + |
| 158 | +function GetOpenSSLVersion: TOpenSSL_C_ULONG; |
| 159 | + |
| 160 | +Returns the OpenSSL library version as an integer as defined by the OpenSSL documentation. |
| 161 | + |
| 162 | +function Init: boolean; |
| 163 | + |
| 164 | +Called to initialise the OpenSSL library prior to use. This must be called when using static linking. |
| 165 | +It is optional for dynamic linking (implicitly called on library load). |
| 166 | + |
| 167 | +The IOpenSSLDLL Interface |
| 168 | +------------------------- |
| 169 | + |
| 170 | +This interface is only available when the API is configured at compile time for dynamic library loading. |
| 171 | +The interface is accessed using the function: |
| 172 | + |
| 173 | +function GetIOpenSSLDDL: IOpenSSLDLL; |
| 174 | + |
| 175 | +This function returns “nil” if the interface is not available. This may be used as a runtime test to |
| 176 | +determine if dynamic library loading if been configured. |
| 177 | + |
| 178 | +Note The OpenSSLAPI unit only declares the constant |
| 179 | + |
| 180 | +OpenSSL_Using_Dynamic_Library_Load = true; |
| 181 | + |
| 182 | +when configured at compile time for dynamic library loading. The constant is not declared otherwise. This feature may be used as a compile time test for the dynamic library loading strategy e.g. |
| 183 | + |
| 184 | +{$if declared(OpenSSL_Using_Dynamic_Library_Load)} |
| 185 | +… |
| 186 | +{$ifend} |
| 187 | + |
| 188 | +The interface includes the IOpenSSL interface and is declared as: |
| 189 | + IOpenSSLDLL = interface(IOpenSSL) |
| 190 | + procedure SetOpenSSLPath(const Value: string); |
| 191 | + function GetSSLLibVersions: string; |
| 192 | + procedure SetSSLLibVersions(AValue: string); |
| 193 | + function GetSSLBaseLibName: string; |
| 194 | + procedure SetSSLBaseLibName(AValue: string); |
| 195 | + function GetCryptoBaseLibName: string; |
| 196 | + procedure SetCryptoBaseLibName(AValue: string); |
| 197 | + function GetAllowLegacyLibsFallback: boolean; |
| 198 | + procedure SetAllowLegacyLibsFallback(AValue: boolean); |
| 199 | + function GetLibCryptoHandle: TLibHandle; |
| 200 | + function GetLibSSLHandle: TLibHandle; |
| 201 | + function GetLibCryptoFilePath: string; |
| 202 | + function GetLibSSLFilePath: string; |
| 203 | + function GetFailedToLoadList: TStrings; |
| 204 | + function Load: Boolean; |
| 205 | + procedure Unload; |
| 206 | + function IsLoaded: boolean; |
| 207 | + property SSLLibVersions: string read GetSSLLibVersions write SetSSLLibVersions; |
| 208 | + property SSLBaseLibame: string read GetSSLBaseLibName write SetSSLBaseLibName; |
| 209 | + property CryptoBaseLibName: string read GetCryptoBaseLibName |
| 210 | + write SetCryptoBaseLibName; |
| 211 | + property AllowLegacyLibsFallback: boolean read GetAllowLegacyLibsFallback |
| 212 | + write SetAllowLegacyLibsFallback;end; |
| 213 | + |
| 214 | +procedure SetOpenSSLPath(const Value: string); |
| 215 | + |
| 216 | +This sets the OpenSSLPath used to locate the OpenSSL library modules (e.g. libcrypto.so). It |
| 217 | +needs to be set when OpenSSL has not been installed in a default location and/or multiple |
| 218 | +versions of OpenSSL have been installed on the same system. |
| 219 | + |
| 220 | +function GetSSLLibVersions: string; |
| 221 | +procedure SetSSLLibVersions(AValue: string); |
| 222 | + |
| 223 | +This is a colon separated (Unixes) or semi-colon separated (Windows) ordered list of OpenSSL |
| 224 | +version numbers that can be used as suffices for the OpenSSL library modules (e.g. for |
| 225 | +libcrypto-3-x64.dll, the suffix is '-3-x64'). When searching for the OpenSSL library, the loader |
| 226 | +searches the default (or specified) OpenSSLPath for OpenSSL libraries using these suffices in turn. |
| 227 | + |
| 228 | +Unix: defaults to |
| 229 | + '.3:.1.1:.1.0.2:.1.0.0:.0.9.9:.0.9.8:.0.9.7:.0.9.6' |
| 230 | + |
| 231 | +Note includes legacy versions. |
| 232 | + |
| 233 | +Windows defaults to |
| 234 | +'-3-x64;-1-x64;' (64 bit) |
| 235 | +'-3;-1;' (32 bit) |
| 236 | + |
| 237 | +Changing the libversions will automatically unload the ssl and crypto libraries if currently loaded. |
| 238 | + |
| 239 | +function GetSSLBaseLibName: string; |
| 240 | +procedure SetSSLBaseLibName(AValue: string); |
| 241 | + |
| 242 | +These are used to respectively get and set the basename for the SSL dynamic library. Defaults to 'libssl'. |
| 243 | +Changing the base name will automatically unload the ssl and crypto libraries if currently loaded. |
| 244 | + |
| 245 | +function GetCryptoBaseLibName: string; |
| 246 | +procedure SetCryptoBaseLibName(AValue: string); |
| 247 | + |
| 248 | +These are used to respectively get and set the basename for the crypto dynamic library. |
| 249 | +Defaults to 'libcrypto'. Changing the base name will automatically unload the ssl and crypto |
| 250 | +libraries if currently loaded. |
| 251 | + |
| 252 | +function GetAllowLegacyLibsFallback: boolean; |
| 253 | +procedure SetAllowLegacyLibsFallback(AValue: boolean); |
| 254 | + |
| 255 | +These are used to respectively get and set the AllowLegacyLibsFallback flag. This is only used |
| 256 | +when running under Windows. If set and no OpenSSL libraries have been found when searching for |
| 257 | +them using the Base Library names and libversions, then the loader will attempt to load the |
| 258 | +OpenSSL libraries using the legacy library names 'libeay32' and 'ssleay32'. |
| 259 | + |
| 260 | +Defaults to 'false'. |
| 261 | + |
| 262 | +Changing this flag will automatically unload the ssl and crypto libraries if currently loaded. |
| 263 | + |
| 264 | +function GetLibCryptoHandle: TLibHandle; |
| 265 | + |
| 266 | +After a successful library load, this returns the value of the internal handle to libcrypto (internal use only recommended). |
| 267 | + |
| 268 | +function GetLibSSLHandle: TLibHandle; |
| 269 | + |
| 270 | +After a successful library load, this returns the value of the internal handle to libssl (internal use only recommended). |
| 271 | + |
| 272 | +function GetLibCryptoFilePath: string; |
| 273 | + |
| 274 | +After a successful library load, this returns the path to the loaded libcrypto library. |
| 275 | +(note: may be empty if default library loaded). |
| 276 | + |
| 277 | +function GetLibSSLFilePath: string; |
| 278 | + |
| 279 | +After a successful library load, this returns the path to the loaded libssl library. ( |
| 280 | +note: may be empty if default library loaded). |
| 281 | + |
| 282 | +function GetFailedToLoadList: TStrings; |
| 283 | + |
| 284 | +After a successful library load, this returns a list of API call names that failed to load at |
| 285 | +library load time. Note: only applies to a small number of functions that are not suitable |
| 286 | +for "just in time" loading. |
| 287 | + |
| 288 | +function Load: Boolean; |
| 289 | + |
| 290 | +Explicitly loads the library if not already loaded and returns “true” on successful load. |
| 291 | + |
| 292 | +procedure Unload; |
| 293 | + |
| 294 | +Explicitly unloads the library if current loaded. |
| 295 | + |
| 296 | +function IsLoaded: boolean; |
| 297 | + |
| 298 | +Returns true if the OpenSSL library has been successfully loaded. |
| 299 | + |
| 300 | + |
| 301 | + |
| 302 | + |
| 303 | + |
| 304 | + |
| 305 | + |
0 commit comments