Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

delphi - Error "Could not load SSL library" on Android with TidHTTP

I'm trying to download a file with TIdHTTP.Get in Delphi Seattle. It's an app for android and all my attempts fails. All i get it's the same error "Could not load SSL library". This is the procedure:

procedure TfrmMain.DownloadPicture(const AURL: string);
var
  MeS: TMemoryStream;
  cidSSL: TIdSSLIOHandlerSocketOpenSSL;
  cidHTTP: TIdHTTP;
begin
  cidHTTP:= TIdHTTP.Create(nil);
  cidSSL:= TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  Mes := TMemoryStream.Create;

  try
    cidHTTP.ReadTimeout := 30000;
    cidHTTP.IOHandler := IdSSL;
    cidSSL.SSLOptions.Method := sslvSSLv3;
    cidSSL.SSLOptions.Mode := sslmUnassigned;
    cidSSL.StartSSL;
    cidHTTP.Get(AURL, Mes);
  except
    on E : Exception do
      begin showmessage('Error: '+E.Message);
      end;
  end;
  Mes.Position := 0;
  frmImage.Image.Bitmap.LoadFromStream(Mes);
end;
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

If you are NOT using Android 6 Marshmallow, OpenSSL should be working fine on Android. When you get the "could not load" error, you can call Indy's WhichFailedToLoad() function in the IdSSLOpenSSLHeaders unit to find out why OpenSSL could not be loaded. If your device does not have OpenSSL pre-installed, you can deploy the OpenSSL binaries with your app, and use Indy's IdOpenSSLSetLibPath() function to tell Indy where to load them from.

That being said, starting with Android 6 Marshmallow, Google no longer supports OpenSSL on Android. It has been replaced with a custom fork named BoringSSL, which Indy does not fully support yet (although some BoringSSL-related changes have been made to Indy after Seattle's release). So, if you are having trouble with using Indy SSL/TLS on Android 6, you can try upgrading to the latest Github snapshot to see if it helps.

BoringSSL makes some major changes to the OpenSSL API interface (dropping functions, changing data types, etc), so it is not backwards-compatible with existing OpenSSL code. But to make matters worse, BoringSSL uses the same library filenames as OpenSSL, and is pre-loaded at device startup, so it is not possible to deploy custom-built OpenSSL library binaries with your Android app. Android will simply use the pre-loaded BoringSSL binaries when the app tries to load the OpenSSL library filenames at runtime (regardless of whether you call Indy's IdOpenSSLSetLibPath() function).

Indy operates at the NDK level of Android, not the Java level, so to make Indy avoid BoringSSL would require users to either:

  1. recompile the OpenSSL libraries with new filenames that don't conflict with BoringSSL (AFAIK no known version of this is available), and then update Indy to use those filenames.

  2. compile the OpenSSL source code directly into their Android app. Indy is not currently setup to support static-linking of OpenSSL on any platform other than iOS, but this should be a minor change to update Indy's IdSSLOpenSSLHeaders_static unit with the relevant definitions if someone can produce viable .a files for OpenSSL on Android. I do know of at least one user attempting this route, but that user has not had success yet (errors getting the source code to fully link correctly).

  3. switch to Android's higher-level Java-based crypto APIs. This is Google's preferred solution. But Indy does not support it at this time. Doing so would require writing a whole new set of TIdStack and TIdIOHandler classes for Android socket I/O and SSL/TLS, using JNI calls to access the Java APIs. But this has performance and threading issues that need to be dealt with.

So, there is no known viable workaround available at this time to make Indy SSL/TLS work on Android 6+.


Update: a user in the Embarcadero forums was able to find OpenSSL .so files that are compatible with Indy and work on Android 6:

https://forums.embarcadero.com/thread.jspa?threadID=211089

After many reports of my apps crashing if installed in Android 6 devices I've searched the net for some tips and the couple of needed .so compiled files, 1.02 version, added the two files to the play store deployment of my apps (assetsinternal) and changed the Indy's path calling

IdOpenSSLSetLibPath(TPath.GetDocumentsPath)

in the OnCreate of my datamodule.

After those modifications of my code my Apps run perfectly on my brand new S7 with Android 6.0.1, and on all the other recent Android devices (tested using the Play Store deployment).

And now the Google warning pops up telling me that the OpsnSSL files deployed with my apps are not of the minimum required 1.02f version (or 1.01r).... and so my post in this forum.

...

Anyway you can download here the latest .so files, the ones that I deploy at this moment: https://drive.google.com/file/d/0B7AxqW32K0oXWW9nUk9qaFpHT0k/view?usp=sharing

Another user in the same discussion also seems to have some success as well:

Ive been running on android 6 loading the .so libraries just fine for months. The new problem is we need to compile new versions of the openssl libraries. Cygwin is not working correctly to compile for me so im switching to a linux install to create them (if possible) https://wiki.openssl.org/index.php/Android#Build_the_OpenSSL_Library_2

heres a repository you can grab some current prebuilt ones https://github.com/emileb/OpenSSL-for-Android-Prebuilt.git


Update: The following (German) forum discussion provides OpenSSL 1.0.2g binaries for Android (and iOS Simulator) to registered users. They do not display the security warning in the Google Play store:

http://www.delphipraxis.net/188736-kompilierte-openssl-bibliotheken-fuer-android.html

OpenSSL 1.0.2g Android.zip

OpenSSL 1.0.2g iOS Simulator.zip


Update: the Android binaries for OpenSSL 1.0.2g are now available in the Embarcadero Attachments forum:

https://forums.embarcadero.com/thread.jspa?threadID=211147

Then, to load OpenSSL instead of BoringSSL, follow these steps:

  1. Add the 2 .so files to your project deployment and set them to deploy to the .assetsinternal folder

  2. add the System.StartupCopy unit as the first unit in your DPR's uses clause.

  3. call IdOpenSSLSetLibPath(TPath.GetDocumentsPath) at app startup.


Update: OpenSSL 1.0.1t and 1.0.2h binaries are now in the Embarcadero Attachments forum:

https://forums.embarcadero.com/thread.jspa?threadID=211147


Update: the binaries have now been posted on Indy's Fulgan mirror:

http://indy.fulgan.com/SSL/


Update: Indy is no longer using the Fulgan mirror for hosting OpenSSL binaries. They are now in their own GitHub repo:

https://www.indyproject.org/2020/06/16/openssl-binaries-moved-to-github/

https://github.com/IndySockets/OpenSSL-Binaries


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...