草庐IT

android - Android 上的两种方式 SSL 身份验证

coder 2023-12-23 原文

我正在尝试在 Python 服务器和 Android 客户端应用程序之间使用两种方式的 SSL 身份验证。我可以访问服务器和客户端,并希望使用我自己的证书实现客户端身份验证。到目前为止,我已经能够验证服务器证书并在没有客户端身份验证的情况下进行连接。

客户端需要什么样的证书,如何让它在握手过程中自动发送给服务器?这是我目前拥有的客户端和服务器端代码。我的方法错了吗?

服务器代码

while True: # Keep listening for clients
    c, fromaddr = sock.accept()

    ssl_sock = ssl.wrap_socket(c,
            keyfile = "serverPrivateKey.pem",
            certfile = "servercert.pem",
            server_side = True,
            # Require the client to provide a certificate
            cert_reqs = ssl.CERT_REQUIRED,
            ssl_version = ssl.PROTOCOL_TLSv1,
            ca_certs = "clientcert.pem", #TODO must point to a file of CA certificates??
            do_handshake_on_connect = True,
            ciphers="!NULL:!EXPORT:AES256-SHA")

    print ssl_sock.cipher()
    thrd = sock_thread(ssl_sock)
    thrd.daemon = True
    thrd.start()

我怀疑我可能为 ca_certs 使用了错误的文件...?

客户端代码

    private boolean connect() {
    try {
        KeyStore keystore = KeyStore.getInstance("BKS"); // Stores the client certificate, to be sent to server
        KeyStore truststore = KeyStore.getInstance("BKS"); // Stores the server certificate we want to trust
        // TODO: change hard coded password... THIS IS REAL BAD MKAY
        truststore.load(mSocketService.getResources().openRawResource(R.raw.truststore), "test".toCharArray());
        keystore.load(mSocketService.getResources().openRawResource(R.raw.keystore), "test".toCharArray());

        // Use the key manager for client authentication. Keys in the key manager will be sent to the host
        KeyManagerFactory keyFManager = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        keyFManager.init(keystore, "test".toCharArray());

        // Use the trust manager to determine if the host I am connecting to is a trusted host
        TrustManagerFactory trustMFactory = TrustManagerFactory.getInstance(TrustManagerFactory
                .getDefaultAlgorithm());
        trustMFactory.init(truststore);

        // Create the socket factory and add both the trust manager and key manager
        SSLCertificateSocketFactory socketFactory = (SSLCertificateSocketFactory) SSLCertificateSocketFactory
                .getDefault(5000, new SSLSessionCache(mSocketService));
        socketFactory.setTrustManagers(trustMFactory.getTrustManagers());
        socketFactory.setKeyManagers(keyFManager.getKeyManagers());

        // Open SSL socket directly to host, host name verification is NOT performed here due to
        // SSLCertificateFactory implementation
        mSSLSocket = (SSLSocket) socketFactory.createSocket(mHostname, mPort);
        mSSLSocket.setSoTimeout(TIMEOUT);

        // Most SSLSocketFactory implementations do not verify the server's identity, allowing man-in-the-middle
        // attacks. This implementation (SSLCertificateSocketFactory) does check the server's certificate hostname,
        // but only for createSocket variants that specify a hostname. When using methods that use InetAddress or
        // which return an unconnected socket, you MUST verify the server's identity yourself to ensure a secure
        // connection.
        verifyHostname();
        // Safe to proceed with socket now
...

我已经使用 openssl 生成了客户端私钥、客户端证书、服务器私钥和服务器证书。然后我将客户端证书添加到 keystore.bks(我存储在 /res/raw/keystore.bks)然后我将服务器证书添加到 truststore .bks

所以现在当客户端尝试连接时,我在服务器端收到此错误:

ssl.SSLError: [Errno 1] _ssl.c:504: error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a certificate

当我尝试在 android 客户端中执行此操作时

SSLSession s = mSSLSocket.getSession();
s.getPeerCertificates();

我收到这个错误:

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

很明显,我正在使用的 keystore 中似乎没有正确的对等证书,因此没有向服务器发送证书。

我应该在 keystore 中放入什么来防止这种异常?

另外,这种双向SSL认证方式安全有效吗?

最佳答案

服务器需要信任客户端证书。通常的做法是创建一个 CA,然后让它签署服务器证书和客户端证书。每个人都将在各自的信任库中拥有 CA 证书。然后你需要用这样的东西初始化 SSLContext:

KeyStore trustStore = loadTrustStore();
KeyStore keyStore = loadKeyStore();

TrustManagerFactory tmf = TrustManagerFactory
                    .getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);

KeyManagerFactory kmf = KeyManagerFactory
                    .getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, KEYSTORE_PASSWORD.toCharArray());

SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

然后您可以根据需要使用 SSLContext 创建套接字工厂。它们将使用适当的 key 和证书进行初始化。

关于android - Android 上的两种方式 SSL 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17348259/

有关android - Android 上的两种方式 SSL 身份验证的更多相关文章

  1. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  2. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  3. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  4. ruby-on-rails - date_field_tag,如何设置默认日期? [ rails 上的 ruby ] - 2

    我想设置一个默认日期,例如实际日期,我该如何设置?还有如何在组合框中设置默认值顺便问一下,date_field_tag和date_field之间有什么区别? 最佳答案 试试这个:将默认日期作为第二个参数传递。youcorrectlysetthedefaultvalueofcomboboxasshowninyourquestion. 关于ruby-on-rails-date_field_tag,如何设置默认日期?[rails上的ruby],我们在StackOverflow上找到一个类似的问

  5. ruby-on-rails - openshift 上的 rails 控制台 - 2

    我将我的Rails应用程序部署到OpenShift,它运行良好,但我无法在生产服务器上运行“Rails控制台”。它给了我这个错误。我该如何解决这个问题?我尝试更新ruby​​gems,但它也给出了权限被拒绝的错误,我也无法做到。railsc错误:Warning:You'reusingRubygems1.8.24withSpring.UpgradetoatleastRubygems2.1.0andrun`gempristine--all`forbetterstartupperformance./opt/rh/ruby193/root/usr/share/rubygems/rubygems

  6. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  7. ruby-on-rails - 正确的 Rails 2.1 做事方式 - 2

    question的一些答案关于redirect_to让我想到了其他一些问题。基本上,我正在使用Rails2.1编写博客应用程序。我一直在尝试自己完成大部分工作(因为我对Rails有所了解),但在需要时会引用Internet上的教程和引用资料。我设法让一个简单的博客正常运行,然后我尝试添加评论。靠我自己,我设法让它进入了可以从script/console添加评论的阶段,但我无法让表单正常工作。我遵循的其中一个教程建议在帖子Controller中创建一个“评论”操作,以添加评论。我的问题是:这是“标准”方式吗?我的另一个问题的答案之一似乎暗示应该有一个CommentsController参

  8. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  9. 安卓apk修改(Android反编译apk) - 2

    最近因为项目需要,需要将Android手机系统自带的某个系统软件反编译并更改里面某个资源,并重新打包,签名生成新的自定义的apk,下面我来介绍一下我的实现过程。APK修改,分为以下几步:反编译解包,修改,重打包,修改签名等步骤。安卓apk修改准备工作1.系统配置好JavaJDK环境变量2.需要root权限的手机(针对系统自带apk,其他软件免root)3.Auto-Sign签名工具4.apktool工具安卓apk修改开始反编译本文拿Android系统里面的Settings.apk做demo,具体如何将apk获取出来在此就不过多介绍了,直接进入主题:按键win+R输入cmd,打开命令窗口,并将路

  10. ruby-on-rails - Ruby - 如何从 ruby​​ 上的 .pfx 文件中提取公钥、rsa 私钥和 CA key - 2

    我有一个.pfx格式的证书,我需要使用ruby​​提取公共(public)、私有(private)和CA证书。使用shell我可以这样做:#ExtractPublicKey(askforpassword)opensslpkcs12-infile.pfx-outfile_public.pem-clcerts-nokeys#ExtractCertificateAuthorityKey(askforpassword)opensslpkcs12-infile.pfx-outfile_ca.pem-cacerts-nokeys#ExtractPrivateKey(askforpassword)o

随机推荐