如何为 gSoap-OpenSSL Android 应用程序存储和加载 cacerts.pem
How to store and load cacerts.pem for gSoap-OpenSSL Android app
我正在开发一个使用 gSOAP 和 OpenSSL 的 C++ Android 应用程序。为了使 OpenSSL 能够验证服务器证书,我需要为其提供 cacerts.pem
文件的位置,否则所有 HTTPS 连接都会失败。
我的问题是:在 Android 上存储和加载 cacerts.pem
的正确方法是什么?
我可以通过将 cacerts.pem
放在 src/resources
或 res/raw/
或 assets/
中将其复制到 APK 根目录中。但是 SSL_CTX_load_verify_locations(ctx, "cacerts.pem", nullptr)
找不到文件。如何让 OpenSSL 能够读取 APK 中的 PEM 文件?
有没有办法将 cacerts.pem
存储为字符串缓冲区,从而避免在 APK 中携带它?
我的应用需要与 Sharepoint 在线网站对话 (https://*.example.com/)
What is the right way to store and load cacerts.pem on Android?
您必须加载验证主机证书所需的一个 CA。
您可以加载构建从主机到 CA 的路径所需的中间体,但它是可选的。配置良好的服务器将发送所需的中间证书,但并非所有服务器都配置良好。
您不加载cacert.pem
或等价物。 cacert.pem
包含数百个证书,除了一个之外,所有证书都是错误的。
Do I need to copy cacerts.pem somehow into the .APK (how to do this?) and provide path to the file to SSL_CTX_load_verify_locations()?
没有。您通常需要一个证书,即证明主机证书的 CA。它可以是 public CA,例如 Comodo,也可以是组织内部的私有 CA。
你通常把它放在res/
或assets/
文件夹。另请参阅 Stack Overflow 上的 Difference between /res and /assets directories。
Is there a way to store cacerts.pem as a string buffer and thus avoid carrying it in the .APK?
是的,但您可能需要获取字符串,将其写入文件系统,然后将文件用于 SSL_CTX_load_verify_locations
。所以最后,最好将它放在 res/
或 assets/
.
中
... sharepoint online sites (https://*.example.com/)
主机名验证的重要说明。 OpenSSL 1.0.2 及更早版本 不 执行名称匹配。它执行其他常规检查,例如确保存在从终端实体证书(主机)到 CA 证书(信任根)的路径并且证书未过期。但它不执行主机名匹配。
OpenSSL 1.1.0 执行主机名匹配。即将发布。
作为权宜之计,您通常会从 cURL
等库中提取丢失的代码。 cURL 执行主机名匹配,Daniel Stenberg 很乐意分享代码。我认为它位于 ssl.c
,如果没记错的话。
另请参阅 OpenSSL wiki 上的 TLS Client。
我终于能够让它工作了。我是一个完整的 Android 新手,所以在这里张贴我的笔记以防它们对像我这样的其他人有用。
按照@jww 的建议,我会在发货前从我的 cacerts.pem 文件中删除所有不必要的证书。
我有 3 个选项可以将我的 cacerts.pem 放在 .APK 中。
- 在根目录(将文件放在 src\main\resources(而不是 src\main\res)将导致它被放置在 apk 的根目录)
- In res\raw(将文件放入src\main\res\raw)
- 在资产中(将文件放入src\main\assets)
在我的简短研究中,我找不到使用 C++ API 直接从 apk 根目录或 res\raw 读取文件的方法。所以我继续#3。
现在资产文件也不能使用 'standard' 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 file("/data.../cacerts.pem") 验证了文件是否已正确创建并且可用并且它是那里。该错误后来以某种方式自行解决。
我正在开发一个使用 gSOAP 和 OpenSSL 的 C++ Android 应用程序。为了使 OpenSSL 能够验证服务器证书,我需要为其提供 cacerts.pem
文件的位置,否则所有 HTTPS 连接都会失败。
我的问题是:在 Android 上存储和加载 cacerts.pem
的正确方法是什么?
我可以通过将
cacerts.pem
放在src/resources
或res/raw/
或assets/
中将其复制到 APK 根目录中。但是SSL_CTX_load_verify_locations(ctx, "cacerts.pem", nullptr)
找不到文件。如何让 OpenSSL 能够读取 APK 中的 PEM 文件?有没有办法将
cacerts.pem
存储为字符串缓冲区,从而避免在 APK 中携带它?
我的应用需要与 Sharepoint 在线网站对话 (https://*.example.com/)
What is the right way to store and load cacerts.pem on Android?
您必须加载验证主机证书所需的一个 CA。
您可以加载构建从主机到 CA 的路径所需的中间体,但它是可选的。配置良好的服务器将发送所需的中间证书,但并非所有服务器都配置良好。
您不加载cacert.pem
或等价物。 cacert.pem
包含数百个证书,除了一个之外,所有证书都是错误的。
Do I need to copy cacerts.pem somehow into the .APK (how to do this?) and provide path to the file to SSL_CTX_load_verify_locations()?
没有。您通常需要一个证书,即证明主机证书的 CA。它可以是 public CA,例如 Comodo,也可以是组织内部的私有 CA。
你通常把它放在res/
或assets/
文件夹。另请参阅 Stack Overflow 上的 Difference between /res and /assets directories。
Is there a way to store cacerts.pem as a string buffer and thus avoid carrying it in the .APK?
是的,但您可能需要获取字符串,将其写入文件系统,然后将文件用于 SSL_CTX_load_verify_locations
。所以最后,最好将它放在 res/
或 assets/
.
... sharepoint online sites (https://*.example.com/)
主机名验证的重要说明。 OpenSSL 1.0.2 及更早版本 不 执行名称匹配。它执行其他常规检查,例如确保存在从终端实体证书(主机)到 CA 证书(信任根)的路径并且证书未过期。但它不执行主机名匹配。
OpenSSL 1.1.0 执行主机名匹配。即将发布。
作为权宜之计,您通常会从 cURL
等库中提取丢失的代码。 cURL 执行主机名匹配,Daniel Stenberg 很乐意分享代码。我认为它位于 ssl.c
,如果没记错的话。
另请参阅 OpenSSL wiki 上的 TLS Client。
我终于能够让它工作了。我是一个完整的 Android 新手,所以在这里张贴我的笔记以防它们对像我这样的其他人有用。
按照@jww 的建议,我会在发货前从我的 cacerts.pem 文件中删除所有不必要的证书。
我有 3 个选项可以将我的 cacerts.pem 放在 .APK 中。
- 在根目录(将文件放在 src\main\resources(而不是 src\main\res)将导致它被放置在 apk 的根目录)
- In res\raw(将文件放入src\main\res\raw)
- 在资产中(将文件放入src\main\assets)
在我的简短研究中,我找不到使用 C++ API 直接从 apk 根目录或 res\raw 读取文件的方法。所以我继续#3。
现在资产文件也不能使用 'standard' 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 file("/data.../cacerts.pem") 验证了文件是否已正确创建并且可用并且它是那里。该错误后来以某种方式自行解决。