在 Android 上安装备用 SSL 提供程序
Android 平台迅速成为开发者和终端用户最受欢迎的移动操作系统之一。因此,安全性是高度优先事项,但有时与最小化资源使用这一目标相冲突。默认情况下,Android 平台使用 OpenSSL 为 Java 开发者提供 SSL 功能,但通过使用 CyaSSL 代替,开发者可以获得更小的占用空间以及更快的 SSL 实现。
本文的目的是提供关于如何在 Android 平台上安装备用 SSL 提供程序的见解和指导,特别是以 CyaSSL 为例。这样做之后,开发者可以选择使用 CyaSSL 来实现 SSL 功能,并获得嵌入式 SSL 库在大小和速度方面的优势。有兴趣替换 Android 上其他预装库的用户或将 C 库从其他系统移植到 Android 的开发者也可能会发现这些信息作为他们自己开发工作的指南非常有用。
TLS(传输层安全)及其前身 SSL(安全套接层)是为网络通信提供安全性的加密协议。这些协议最初由 Netscape 创建,允许客户端/服务器应用程序创建加密链接,并确保所有发送和接收的流量都是私密和安全的。
TLS 和 SSL 通过使用公钥/私钥加密、对称加密、哈希和可信证书来提供此安全层。使用公钥加密的消息(SSL/TLS 的预主密钥)只能使用关联的私钥解密。公钥通常是公开可用的,允许任何拥有此密钥的人加密消息。只有该公钥的所有者才能解密使用关联私钥加密的消息。TLS 和 SSL 可以使用多种密码套件来创建安全套接字。
Java 平台包含一组安全 API(公钥基础设施、身份验证、安全通信和访问控制),所有这些 API 都只是定义提供程序实现需要满足的“契约”的接口。这使 Java 程序员能够使用单个 API,同时允许插入任何所需的底层实现。
在这种架构下,可以并排安装同一服务的多个提供程序。在拥有同一服务的多个提供程序的情况下,每个提供程序都被赋予一个优先级顺序,Java 平台应按此顺序使用它们。默认情况下,如果 Java 提供的功能是所需的,则 Java 将首先使用优先级较高的提供程序。
javax.net.ssl Java API 包负责为 Java 平台提供 SSL 功能。图 1 中的图表概述了 SSL 提供程序(或更广泛地说,提供程序)在 Java 平台内的组织方式。由于 Android 主要基于 Java 框架并支持此提供程序设计,因此我们能够将 CyaSSL 安装为 Android 的 SSL 提供程序。
Java 安全提供程序在 OS X 和 Linux 上列出并在名为 java.security 的文件中确定优先级,或者在 Android 平台上在 java.properties 文件中确定优先级。在 Android 上,此文件位于 /libcore/security/src/main/java/java/security/security.properties。此文件是 Java 提供程序的主要配置文件,将在 CyaSSL 安装过程中发挥关键作用。
首先,您需要设置本地构建环境以适应 Android 构建系统,并下载 Android 平台源代码。
要构建 Android 源代码文件,您的开发机器上应安装 Linux 或 OS X。在撰写本文时,目前不支持 Windows。此外,由于与 Java 6 的不兼容性,不支持最新版本的 OS X Snow Leopard。本文的其余部分假设选择的操作系统是 32 位 Linux。由于 Android 平台发展的速度很快,请查看 Android 开发者网站以获取最新的主机操作系统支持。
有关设置 Android 开发的本地工作环境的说明以及获取 Android 源代码的说明,请参阅 Android 文档“获取 Android 源代码”,该文档位于 Android 开发者网站上。在继续之前,请确保您能够按照在线概述的步骤构建 Android 平台,而无需进行修改。
与 Android 平台合作和为其做出贡献是通过使用 Git 和 Repo 完成的。在 Android 中,Git 用于本地操作,例如本地分支、提交、差异和编辑。另一方面,Repo 是 Google 在 Git 之上构建的工具。根据 Google 的说法,“Repo 帮助管理许多 Git 存储库,执行到修订控制系统的上传,并自动化 Android 开发工作流程的各个部分。Repo 并非旨在取代 Git,而只是为了在 Android 上下文中更轻松地使用 Git。”
为了使测试和调试对 Android 平台的修改更加容易,Google 创建了 Android 模拟器。此模拟器是高度可定制的,允许自定义硬件配置、提供日志输出、允许 shell 访问等等。
在使用模拟器之前,您需要下载它。它与 Android SDK 捆绑在一起。下载 SDK 后,您将在 <Android-SDK>/tools 目录中找到各种工具,其中 <Android-SDK> 是 SDK 的根目录。这些工具将包括模拟器和 Android 调试桥 (adb)。
CyaSSL Java SSL 提供程序由两部分组成:CyaSSL 共享库和 Java 提供程序代码。提供程序代码使用 JNI(Java 本地接口)在 Java 和 CyaSSL C 库之间进行通信。Android 平台分为几个层,如图 2 所示。在 SSL 提供程序安装期间受影响的两个层是库层和 Android 运行时层。为了继续,请从 yaSSL 网站下载适用于 Android 的 CyaSSL Java SSL 提供程序。还提供了适用于 Linux 和 Mac 的下载,因此请确保您下载的是适用于 Android 的提供程序。

图 2. Android 平台层组成
CyaSSL 是一种基于 C 语言的 SSL 库,目标是嵌入式和 RTOS 环境,主要是因为其体积小和速度快。它支持高达当前 TLS 1.2 级别的行业标准,功能齐全,并针对嵌入式环境进行了优化,使其成为 Android 的理想选择。CyaSSL SSL 提供程序主要有两个组件:一个用 C 编写的共享库和一个 SSL 提供程序代码,其中包含 Java 和本地代码。
CyaSSL 共享库由 Android 构建系统编译成名为 libcyassl.so 的共享库。此库包含在常规桌面安装的 CyaSSL 库中可以找到的所有函数,并且是 CyaSSL Java SSL 提供程序的基础。
共享库源文件在 CyaSSL 提供程序下载的 /external/cyassl 目录下找到。
提供程序代码使用 JNI 在 Java 和本地 C 及 C++ 代码之间进行通信。因此,需要安装两个单独的部分:Java 代码和本地 C++ 代码。这些源文件在提供程序下载的 /libcore/yassl 目录下。
在本文中,<Android-Platform> 代表开发机器上的 Android 平台源根目录。Android 平台具有单体构建系统,这意味着整个平台一次构建完成。Google 为 Android 构建了自定义构建系统,其中每个组件都需要有一个 Android.mk 文件。此文件本身不是 makefile,而是将组件绑定到整个构建系统中。
由于我们正在安装一个新的库,我们将在 Android 平台中的 /external 目录下为其创建一个新文件夹。大多数放置到 Android 平台中的第三方共享库都应安装在 /external 目录下。为此,请将 CyaSSL 提供程序下载的 src/external/cyassl 目录中的 cyassl 目录复制到 Android 平台的 /external 目录中。复制后,此文件夹应位于 <Android-Platform>/external/cyassl。
这些源文件将由 Android 构建系统使用 /external/cyassl/src/Android.mk 文件中的规则编译为 libcyassl.so。
打开 <Android-Platform>/build/core/prelink-linux-map.map,并在标题下为 libcyassl.so 添加一个新条目# 特定应用程序的库或临时库。prelink-linux-map.map 文件用于提供地址,以便可以更快地加载所有注册的库。它应该类似于以下内容(请注意,库应在 1MB 边界上对齐)
libcyassl.so 0x9C500000 # [~1M] for external/cyassl
打开文件 <Android-Platform>/dalvik/libnativehelper/Android.mk,并将 libcyassl.so 添加到 shared_libraries 列表中。
现在共享库已经安装完成,是时候安装 JNI 提供程序代码了。
Android 中现有的 SSL 提供程序(使用 OpenSSL 的 Apache Harmony)位于 /libcore 目录中。CyaSSL 提供程序也将安装在此处,以保持一致性。首先,将提供程序源的 src/libcore/yassl 目录中的 yassl 目录复制到 Android 平台的 /libcore 目录中。此文件夹现在应位于 <Android-Platform>/libcore/yassl。
CyaSSL SSL 提供程序包含一个初始化方法(在本地 C++ 代码中),需要向 Android 平台注册该方法,以便可以在运行时向 Dalvik VM 注册本地方法。Dalvik 是 Android 修改后的 Java 虚拟机版本。与桌面 Java 安装不同,Dalvik 以不同的方式处理 JNI,因为它需要编写一个函数(在 JNI 代码中)来显式注册每个需要提供给 JVM 的本地方法。此方法需要添加到 libnativehelper 的 Register.c 文件中。
打开文件 <Android-Platform>/dalvik/libnativehelper/Register.c,并添加register_com_yassl_xnet_provider_jsse_NativeCrypto方法,该方法位于现有提供程序的条目下。添加后,它应类似于以下内容(请注意现有的 Apache Harmony 安装)
if (register_org_apache_harmony_xnet_provider_jsse_ ↪NativeCrypto(env) != 0) goto bail; if (register_com_yassl_xnet_provider_jsse_ ↪NativeCrypto(env) != 0) goto bail;
Java 提供程序框架的配置文件是 security.properties 文件。这将允许您将 CyaSSL 设置为默认 SSL 提供程序。打开 security.properties 文件 (<Android-Platform>/libcore/security/src/main/java/java/security/security.properties),并进行以下更改以配置 CyaSSL 提供程序。
在默认值上方添加以下行org.apache.harmony.xnet.provider.jsse.JSSEProvider提供程序。请注意每个提供程序旁边的数字。这些数字反映了提供程序的优先级。插入新提供程序后,可能需要重新编号此列表
security.provider.3=com.yassl.xnet.provider.jsse.JSSEProvider
更改ssl.SocketFactory.provider条目以指向新的 CyaSSL 提供程序
ssl.SocketFactory.provider=com.yassl.xnet.provider.jsse. ↪SocketFactoryImpl
至此,CyaSSL 提供程序已完全安装到 Android 平台中。您可以继续构建和测试安装了新提供程序的平台。如果在平台构建期间没有出现错误,则可以将提供程序加载到模拟器中,以确保平台在新提供程序安装的情况下正确运行。
构建过程可能需要大量时间,具体取决于构建环境。所有命令都应从 Android 平台根目录运行
$ source build/envsetup.sh [Sets environment variables] $ lunch 1 [Builds the emulator] $ make [Builds the Android Platform]
请记住,可以重建单个项目(例如 CyaSSL 共享库)以测试共享库是否使用mm命令(如下所示)正确构建,但在模拟器中进行测试之前,需要进行完整的平台构建
$ cd external/cyassl $ mm
Android 平台构建过程会生成三个镜像文件:<Android-Platform>/out/target/product/generic/ramdisk.img、<Android-Platform>/out/target/product/generic/system.img 和 <Android-Platform>/out/target/product/generic/userdata.img
ramdisk.img — 一个小分区,在启动时由内核以只读方式挂载。它仅包含 /init 和一些配置文件。它用于启动 /init,这将启动其余的系统镜像并运行初始化过程。
system.img — 一个分区镜像,将作为 / 挂载,并包含所有系统二进制文件。这是包含上述所有更改的镜像文件。
userdata.img — 此镜像仅在模拟器中使用 -wipe-data 选项时使用。在正常的模拟器执行中,将使用默认的 userdata 镜像。
其中,system.img 是最受关注的。它包含系统的大部分内容以及添加 CyaSSL SSL 提供程序后所做的所有更改。
在使用 Android 模拟器之前,您必须创建一个 Android 虚拟设备。Android 虚拟设备是模拟器选项的配置,允许开发者更好地模拟物理 Android 设备。它们保存配置信息,例如硬件配置文件、到系统镜像的映射和专用存储区域。要创建 Android 虚拟设备,请使用 android 应用程序。此应用程序位于 SDK 的 tools 目录下。使用以下命令(从 SDK /tools 目录发出)创建一个新的虚拟设备
$ android create avd -n <desired-name> -t <target-version>
其中 <desired-name> 是 Android 虚拟设备的名称,<target-version> 是所需的目标平台。运行以下命令以查看可用目标
$ android list targets
创建 Android 虚拟设备后,使用构建的镜像加载模拟器
$ emulator -avd <virtual-device-name> -system <Android-Platform>/out/target/product/generic/system.img -data <Android-Platform>/out/target/product/generic/userdata.img -ramdisk <Android-Platform>/out/target/product/generic/ramdisk.img
还有其他有用的模拟器选项可以添加到上述命令中。下面列出了一些,但完整的列表请参阅官方 Android 模拟器网页
-verbose— 详细输出。
-nocache— 不使用缓存。
-show-kernel— 将内核消息打印到终端窗口。
模拟器运行后,可以在新的终端窗口中查看 logcat 输出(假设当前目录是 <Android-SDK>/tools)
$ adb logcat
在本文中,解释了使用 CyaSSL 在 Android 平台中安装备用 SSL 提供程序。通过在 Android 平台中使用 CyaSSL 而不是 OpenSSL,开发者能够利用 CyaSSL 库的速度和大小优势。利用共享库和 JNI,相同的通用过程可以应用于将其他第三方库安装到 Android 平台中,并且可以为将 C 库从其他操作环境移植到 Android 的开发者提供良好的参考。
资源
TLS 和 SSL 的深入了解: en.wikipedia.org/wiki/Transport_Layer_Security
Android 开发者网站: source.android.com/source/download.html
Android SDK 下载: developer.android.com/sdk/index.html
yaSSL 网站提供的适用于 Android 的 CyaSSL Java SSL 提供程序: www.yassl.com/yaSSL/Download_More.html
Android 模拟器网页: developer.android.com/guide/developing/tools/emulator.html
Chris Conlon 是 yaSSL 的一名开发者。Chris 在户外探险和计算机之间找到了平衡,他喜欢不断学习,并努力为技术社区带来新的和有用的东西。Chris 欢迎在 chris@yassl.com 处发表评论。