另外,SDK 文档里有两句话:
These extras may be combined with EXTRA_NAME to provide a default alias name for credentials being installed.
When used with startActivityForResult(Intent, int), RESULT_OK will be returned if a credential was successfully installed, otherwise RESULT_CANCELED will be returned.
看起来很美,实测之后却不完全是那么回事,你就当他没说吧。
很多程序员编写的 https、SSL/TLS 相关代码,测试过程中总遇到些坑,其实90%是没安装合适的证书导致的,网上一些文章给出误人子弟的“解决办法”是忽略所有 SSL 错误,这样 SSL 握手倒是成功了,通信也似乎是“正常”了,然而这是一种外行的做法,为钓鱼网站和 MITM (中间人攻击)打开了方便之门。本人曾在某项目里采用了一个著名的 WebSocket 包,测试中间人攻击居然成功了,仔细检查其代码发现作者在 SSL 方面竟是个外行。
由于 Android 有了这个系统级的凭证库,只要安装了合适的 CA 证书(也可能包括用户证书),浏览器或者内嵌 WebView 的 App 就可以正常访问 https://...... 这类网站了,如果要编写 Socket 通信的代码,也是极简单的事:
SSLSocket sslSocket = (SSLSocket) SSLContext.getDefault().getSocketFactory().createSocket(new Socket(), "my.ip.addr", 4430, true);
也许有人说,SSLSocketFactory.getDefault()不是也可以吗?本人测试过,大部分的 Android 版本可以,但某些版本不行,所以还是用上面的办法为妥。
如果编写 SSL/TLS 服务端代码(SSLServerSocket),则不建议使用默认的 SSLContext,也不要把服务端证书安装到系统凭证库里,理由将在后文讨论。
除了前文所述的,KeyChain 包还提供读取系统凭证库的方法,应用 App 可以读出已安装的证书(包括 CA 信任链)及其匹配的私钥:
public static X509Certificate[] mCerts;
public static PrivateKey mKey;
public static String mAlias = null; //如果此变量在调用之前不是null,则与此同名的证书在UI中成为默认首选项。
private static final boolean mEnd[];
private static Activity mActivity = ....; //此变量需要初始化为当前运行的 Activity。