如何为gSoap-OpenSSL Android应用程序

时间:2016-03-15 00:26:31

标签: android c++ openssl gsoap

我正在开发一个使用gSOAP和OpenSSL的C ++ Android应用程序。要使OpenSSL能够验证服务器证书,我需要为其提供cacerts.pem文件的位置,否则所有HTTPS连接都会失败。

我的问题是:在Android上存储和加载cacerts.pem的正确方法是什么?

  • 我可以将cacerts.pem复制到APK src/resourcesres/raw/assets/中。但SSL_CTX_load_verify_locations(ctx, "cacerts.pem", nullptr)无法找到该文件。如何让OpenSSL能够读取APK中的PEM文件?

  • 有没有办法将cacerts.pem存储为字符串缓冲区,从而避免在APK中携带它?

我的应用需要与sharepoint在线网站(https://*.example.com/)

交谈

2 个答案:

答案 0 :(得分:1)

  

在Android上存储和加载cacerts.pem的正确方法是什么?

必须加载验证主机证书所需的CA.

可以加载构建从主机到CA的路径所需的中间件,但是它是可选的。配置良好的服务器将发送所需的中间证书,但并非所有证书都配置良好。

没有加载// In login screen before go to home, save the username as key "userID" let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults() defaults.setObject(username, forKey: "userID") defaults.synchronize() // In your home, viewDidLoad() retrieve it back let defaults: NSUserDefaults = NSUserDefaults.standardUserDefaults() let userID = (defaults.objectForKey("userID") as? String)! 或同等信息。 cacert.pem包含数百个证书,但所有证书都是错误的。

  

我是否需要以某种方式将cacerts.pem复制到.APK(如何执行此操作?)并将文件路径提供给SSL_CTX_load_verify_locations()?

没有。您通常需要一个证书,并且该证书是证明主机证书的CA.它可以是公共CA,如Comodo,也可以是组织内部的私有CA.

您通常将其放在 cacert.pem res/ 文件夹中。另请参阅Stack Overflow上的Difference between /res and /assets directories

  

有没有办法将cacerts.pem存储为字符串缓冲区,从而避免在.APK中携带它?

是的,但您可能必须获取字符串,将其写入文件系统,然后将该文件用于assets/。最后,最好将其置于SSL_CTX_load_verify_locationsres/

  

... sharepoint在线网站(https://*.example.com/)

主机名验证的一个重要注意事项。 OpenSSL 1.0.2及更早版本 执行名称匹配。它执行其他常规检查,例如确保从最终实体证书(主机)到CA证书(信任根)的路径,并且证书未过期。但 执行主机名匹配。

OpenSSL 1.1.0 执行主机名匹配。它很快就会发布。

作为止损,您通常会从assets/这样的库中提取丢失的代码。 cURL执行主机名匹配,Daniel Stenberg很乐意分享代码。如果记忆能为我服务,我认为它位于cURL

另请参阅OpenSSL wiki上的TLS Client

答案 1 :(得分:1)

我终于让它运转了。我是一个完整的Android新手,所以在这里发布我的笔记,以防它们对像我这样的人有用。

正如@jww建议我在发货前从cacerts.pem文件中删除所有不必要的证书。

我有3个选项可以将我的cacerts.pem放在.APK中。

  1. 在root(在src \ main \ resources中放置文件(不是src \ main \ res)将导致它被放置在apk的根目录)
  2. 在res \ raw中(将文件放在src \ main \ res \ raw中)
  3. 在资产中(将文件放在src \ main \ assets中)
  4. 在我的简短研究中,我找不到使用c ++ apis从apk root或res \ raw直接读取文件的方法。所以我继续#3。

    现在资产文件也不能使用'标准'c ++函数直接读取(如果我错了,请纠正我),所以我在我的Java层使用此代码将资产文件夹的文件副本复制到外部位置。

    try
    {
        AssetManager assetManager = this.getAssets();
        File file = new File(getFilesDir(), "cacerts.pem");
        InputStream in = assetManager.open("cacerts.pem");
        OutputStream out = new FileOutputStream(file);
    
        byte[] buffer = new byte[65536 * 2];
        int read;
        while ((read = in.read(buffer)) != -1) {
            out.write(buffer, 0, read);
        }
    
        in.close();
        out.flush();
        out.close();
    }
    catch (Exception e)
    {
    }
    

    在此之后,我将此文件位置传递给我的c ++代码,并且能够进行此调用

    SSL_CTX_load_verify_locations(ctx, "/data/user/0/com.company.app/files/cacerts.pem", NULL)
    

    注意:这不是最终的生产代码。在这个阶段只是概念验证。请随时指出您看到的任何错误或建议。

    注意:有一段时间openssl仍然无法读取文件,所以我验证文件是否正确创建并使用ifstream文件(“/ data ... / cacerts.pem”)可用,并且它就在那里。那个错误后来以某种方式解决了。