如何在Android设备上安装受信任的CA证书?

161
我已创建了自己的CA证书,现在我想将其安装在我的Android Froyo设备(HTC Desire Z)上,以便设备信任我的证书。
Android将CA证书存储在其Java密钥库中的/system/etc/security/cacerts.bks。我将文件复制到计算机上,使用portecle 1.5添加了我的证书,并将其推回设备。
现在,Android似乎不会自动重新加载文件。我已经在几篇博客文章中读到,需要重新启动设备。这样做会导致文件被原始文件覆盖。
我的下一个尝试是通过将证书复制到SD卡并使用相应的设置菜单选项来安装证书。设备告诉我证书已安装,但显然它不信任该证书。此外,当我尝试将密钥库复制到计算机时,仍然可以找到原始的cacerts.bks
那么,在Android 2.2设备上安装自己的根CA证书作为受信任证书的正确方法是什么?是否有编程方式实现?

你可以假设手机已经被root了。 :) - Björn Marschollek
11个回答

141

在Android KitKat之前,您需要root您的设备才能安装新证书。

从Android KitKat(4.0)到Marshmallow(6.0),这是可能且容易的。我能够在未root的设备上安装Charles Web Debbuging代理证书并成功地嗅探SSL流量。

摘自http://wiki.cacert.org/FAQ/ImportRootCert

在Android 4.0之前的版本(Gingerbread和Froyo),有一个只读文件(/system/etc/security/cacerts.bks),其中包含所有默认受信任的CA(“系统”)证书的信任存储。系统应用程序和使用Android SDK开发的所有应用程序都使用此文件。以下是在Android Gingerbread,Froyo等上安装CAcert证书的说明...
从Android 4.0开始(Android ICS /“冰淇淋三明治”,Android 4.3“果冻豆”和Android 4.4“奇巧巧克力”),系统信任的证书以单独的文件形式存在于(只读)系统分区中的“/system/etc/security/”文件夹中。但是,现在用户可以轻松添加自己的“用户”证书,这些证书将存储在“/data/misc/keychain/certs-added”中。
可以在Android设备的“设置”->“安全”->“证书”->“系统”部分中管理系统安装的证书,而用户信任的证书则在那里的“用户”部分中管理。当使用用户信任的证书时,Android会强制要求Android设备的用户实施额外的安全措施:使用PIN码、图案锁或密码解锁设备是使用用户提供的证书时强制要求的。
将CAcert证书安装为“用户信任”的证书非常容易。将新证书安装为“系统信任”的证书需要更多的工作(并需要root访问权限),但它具有避免Android锁屏要求的优点。

从Android N(7.0)开始,情况变得有点困难,请参考Charles代理网站的以下内容:

从Android N开始,您需要在应用程序中添加配置才能使其信任由Charles SSL代理生成的SSL证书。这意味着您只能与您控制的应用程序一起使用SSL代理。

为了配置您的应用程序以信任Charles,您需要将Network Security Configuration文件添加到您的应用程序中。此文件可以覆盖系统默认设置,使您的应用程序信任用户安装的CA证书(例如Charles根证书)。您可以指定仅在应用程序的调试版本中应用此设置,以便生产版本使用默认的信任配置文件。

将文件res/xml/network_security_config.xml添加到您的应用程序中:

<network-security-config>    
    <debug-overrides> 
        <trust-anchors> 
            <!-- Trust user added CAs while debuggable only -->
            <certificates src="user" /> 
        </trust-anchors>    
    </debug-overrides>  
</network-security-config>

然后在您的应用程序清单中添加对此文件的引用,如下所示:

<?xml version="1.0" encoding="utf-8"?> 
<manifest>
    <application android:networkSecurityConfig="@xml/network_security_config">
    </application> 
</manifest>

2
我的自定义证书文件 (/system/etc/security/cacerts/*.0) 在重启 AVD 后不会被保留,因此这个解决方案并不成功。 - fikr4n
@BornToCode 很有趣 - 我很少使用 AVD,所以我不知道这个限制。 - Dean Wild
1
@Isaac 这意味着它将适用于任何 debuggable=true 的变体。 - Dean Wild
1
@DeanWild - 非常感谢你!我一直在努力让这个工作起来,但在调试我的应用程序时一直出现“无效的SSL证书”。这个解决方案对于我在三星Note 8上运行的Android 9的Android应用程序非常有效。 - Dave Black
似乎 Chrome for Android 已启用了此选项,因此您将能够通过在用户证书配置文件中安装它们来访问使用自定义证书的站点。 - Jordi
显示剩余4条评论

45

我花了很多时间寻找答案(我需要Android来查看StartSSL证书)。结论是:Android 2.1和2.2允许您导入证书,但仅适用于WiFi和VPN。没有用户界面来更新受信任的根证书列表,但有关于添加该功能的讨论。目前还不清楚是否有可靠的解决办法手动更新并替换cacerts.bks文件。

详细信息和链接:http://www.mcbsys.com/techblog/2010/12/android-certificates/。在那篇文章中,请参阅与Android bug 11231相关的链接 -- 你可能想要为该问题添加你的投票和查询。


3
一位安卓开发者回答了我的有关更新cacerts.bks的问题:“在所有版本中,包括2.3,在非Root的手机上更新cacerts.bks需要OTA。” http://code.google.com/p/android/issues/detail?id=11231#c25. OTA是指空中下载,对吗?这可能是为什么您的手机会不断恢复出厂cacerts.bks的原因吗?但是,如果您有Root权限,似乎可以下载源代码,添加您的证书,然后使用certimport.sh脚本构建cacerts.bks。http://android.git.kernel.org/?p=platform/libcore.git;a=tree;f=luni/src/main/files。 - Mark Berry
谢谢。显然这不是我想听到的答案,但似乎是正确的答案。我希望有一种方法可以安装证书而无需更新整个系统。当然,我可以构建新的cacerts.bks,有了root访问权限,我甚至可以替换旧的文件,但每次重新启动后它都会恢复到原始版本。在没有重新启动的情况下,Android似乎拒绝重新加载受信任的证书文件。 - Björn Marschollek
27
在 3.X 和 4.X 平台上安装 CA 证书怎么样? - Alok Kulkarni
1
4.X及以上版本:https://dev59.com/pG855IYBdhLWcg3wPBpx#22040887 - Dean Wild

17

如果您需要在HTTPS连接中使用证书,则可以将.bks文件作为原始资源添加到您的应用程序中,并扩展DefaultHttpConnection,以便在HTTPS连接中使用您的证书。

public class MyHttpClient extends DefaultHttpClient {

    private Resources _resources;

    public MyHttpClient(Resources resources) {
        _resources = resources;
    }

    @Override
    protected ClientConnectionManager createClientConnectionManager() {
        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory
            .getSocketFactory(), 80));
        if (_resources != null) {
            registry.register(new Scheme("https", newSslSocketFactory(), 443));
        } else {
            registry.register(new Scheme("https", SSLSocketFactory
                .getSocketFactory(), 443));
        }
        return new SingleClientConnManager(getParams(), registry);
    }

    private SSLSocketFactory newSslSocketFactory() {
        try {
            KeyStore trusted = KeyStore.getInstance("BKS");
            InputStream in = _resources.openRawResource(R.raw.mystore);
            try {
                trusted.load(in, "pwd".toCharArray());
            } finally {
                in.close();
            }
            return new SSLSocketFactory(trusted);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

感谢您的回复。实际上,我需要以一种方式安装证书,使设备上的每个应用程序都信任该证书。对于一些较小的CA(如CAcert),其证书默认情况下不受信任,同样存在这个问题。他们如何安装他们的证书? - Björn Marschollek
1
你尝试过了吗:设置 -> 安全 -> 从SD卡安装? - Alexander Egger
这也许会很有趣:http://android.git.kernel.org/?p=platform/packages/apps/CertInstaller.git;a=blob;f=src/com/android/certinstaller/CertFile.java;h=8e6379491fc342632e85396ccbc8ba75192d2133;hb=HEAD - Alexander Egger
2
我有同样的问题,我需要在Android 2.3.3应用程序中加载一个.PDX X509证书,然后创建SSL连接。有人可以帮我提供有注释的代码吗? - Salman

11

这里链接的指南here可能会回答原始问题,而无需编程自定义SSL连接器。

发现了一份非常详细的操作指南,可以逐步指导在不同版本的Android设备(以及其他设备)上安装受信任的CA证书。

基本上,您需要:

  1. 下载:从手机下载cacerts.bks文件。

    adb pull /system/etc/security/cacerts.bks cacerts.bks

  2. 从认证机构下载.crt文件以允许其。

  3. 使用BouncyCastle Provider修改计算机上的cacerts.bks文件。

  4. 将cacerts.bks文件上传回您的手机并重新启动。

以下是更新早期安卓手机HTTPS安全证书授权密钥库的详细步骤:

如何在Android 4.0之前的设备上更新HTTPS安全证书授权密钥库

7

这个问题有一个比在此处或相关帖子中发布的方法更简单的解决方案。如果您正在使用Webview(就像我一样),则可以通过在其中执行JavaScript函数来实现。如果您没有使用Webview,则可能需要为此目的创建一个隐藏的Webview。这是一个功能,几乎在任何浏览器(或Webview)中都可以启动ca安装(通常通过共享操作系统证书库,包括在Android上)。它使用了iFrames的一个小技巧。只需将.crt文件的URL传递给此函数:

function installTrustedRootCert( rootCertUrl ){
    id = "rootCertInstaller";
    iframe = document.getElementById( id );
    if( iframe != null ) document.body.removeChild( iframe );
    iframe = document.createElement( "iframe" );
    iframe.id = id;
    iframe.style.display = "none";
    document.body.appendChild( iframe );
    iframe.src = rootCertUrl;
}

更新:

使用iframe的方法适用于API版本在19及以上的Droids,但旧版本的webview不能像这样工作。然而,总体思路仍然有效 - 只需使用webview下载/打开文件,然后让操作系统接管即可。这可能是一种更简单、更普遍的解决方案(现在实际的Java代码如下):

 public static void installTrustedRootCert( final String certAddress ){
     WebView certWebView = new WebView( instance_ );
     certWebView.loadUrl( certAddress );
 }

请注意,instance_是对Activity的引用。如果您知道证书的url,则此方法非常有效。然而,在我的情况下,我需要使用服务器端软件来动态解析它。我不得不添加大量额外的代码来拦截重定向URL,并以不会导致线程问题崩溃的方式调用它,但我不会在这里添加所有这些混乱...


7

你能否详细解释一下如何操作呢?网站本身没有关于安装和使用的说明。谢谢!顺便说一句,Magisk模块现在在https://github.com/Magisk-Modules-Repo/movecert上。 - xpt
1
您需要拥有已root的设备并安装了Magisk,然后打开Magisk,点击模块图标,该图标位于底部导航图标的最右侧,然后搜索移动证书,点击安装>>重新启动。 - Nightcap79

3
你试过这个吗:设置 -> 安全 -> 从SD卡安装?- Alexander Egger于2010年12月20日20:11提供了此建议。我不确定为什么这不是一个答案,但我刚刚按照这个建议操作了一下,它起作用了。

2
我为了能够使用startssl证书所做的事情非常简单。(在我的root手机上)
我将/system/etc/security/cacerts.bks复制到了我的sd卡中。
下载http://www.startssl.com/certs/ca.crthttp://www.startssl.com/certs/sub.class1.server.ca.crt
去portecle.sourceforge.net并直接从网页运行portecle。
从我的sd卡中打开了我的cacerts.bks文件(当要求输入密码时,什么都没输入)。
在portacle中选择导入并打开sub.class1.server.ca.crt,在我的情况下已经有了ca.crt,但也许您也需要安装它。
保存密钥库并将其复制回/system/etc/security/cacerts.bks(我首先备份了该文件以防万一)。
重新启动我的手机,现在我可以访问使用startssl证书的站点而不会出错。

Mozilla最新消息:不信任新的WoSign和StartCom证书 - jww
有没有想法如何将cacert.bks放回非root设备上? - Bob

2
这些步骤对我有效:
  1. 在您的移动设备上安装Dory证书Android应用程序:https://play.google.com/store/apps/details?id=io.tempage.dorycert&hl=en_US
  2. 使用USB电缆将移动设备连接到笔记本电脑。
  3. 在内部电话存储器上创建根文件夹,将证书文件复制到该文件夹中并断开电缆。
  4. 打开Dory证书Android应用程序,单击圆形[+]按钮,然后选择正确的导入文件证书选项。
  5. 选择格式,提供名称(我输入与文件名相同的内容),浏览证书文件并单击[确定]。
  6. 将列出三张卡。我忽略了只有[签署CSR]按钮的卡,并继续单击另外两张卡上的[安装]按钮。
  7. 我刷新了PWA Web应用程序(它托管在本地IIS Web服务器上)并且没有Chrome警告消息。绿色锁定在那里。它正在工作。

或者,我发现这些选项,我自己没有尝试过,但看起来很容易跟随:

最后,这可能与您无关,但是,如果您想为托管在本地IIS Web服务器上的PWA应用程序(网站)创建和设置自签名证书(使用mkcert),我遵循了此页面:

https://medium.com/@aweber01/locally-trusted-development-certificates-with-mkcert-and-iis-e09410d92031

谢谢,希望有所帮助!:)


1

这里有一个替代方案,它实际上将您的证书添加到默认证书列表中:在HTTPS上使用HttpClient信任所有证书

但是,它只适用于您的应用程序。无法以编程方式为用户设备上的所有应用程序执行此操作,因为那将是安全风险。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接