其他分享
首页 > 其他分享> > 如何使用由未知CA自签名的证书使Android Volley执行HTTPS请求?

如何使用由未知CA自签名的证书使Android Volley执行HTTPS请求?

作者:互联网

在提出问题之前,我找到了一些链接,我逐一检查了这些链接,但没有一个链接给我一个解决方案:

>久远的CA
HTTPS request using volley
>接受所有SSL证书
No peer certificate Exception – Volley and Android with self signed certificate
> Node.js(Socket.io)
Socket.io + SSL + self-signed CA certificate gives error when connecting
>自签名证书“​​MANUALLY”进口:
Android SSL HTTP Request using self signed cert and CA

到目前为止,我发现的唯一链接是这个,它提供了两种方法:Making a HTTPS request using Android Volley

>1º指示将某些类导入到您的应用程序中,确实存在必须导入的另一个类,并且这些类使用来自“apache.org”的弃用库
>2ºNUKE所有SSL ceriticates的一个例子(非常糟糕的主意……)

我也找到了这个博客,其中有很多解释,但最后,我意识到这些例子都使用了来自“apache.org”的弃用库,而博客本身也没有Android Volley的内容.
https://nelenkov.blogspot.mx/2011/12/using-custom-certificate-trust-store-on.html

还有来自Android的链接和“未知证书颁发机构”部分的代码,它给出了解决方案的一个好主意,但代码本身在其结构中缺少一些东西(Android Studio抱怨…):https://developer.android.com/training/articles/security-ssl.html

但是这个链接的引用似乎是解决问题的核心概念.

“TrustManager是系统用于验证来自服务器的证书的方法,并且通过从具有一个或多个CA的KeyStore创建一个 – 这些将是该TrustManager信任的唯一CA.
给定新的TrustManager,该示例初始化一个新的SSLContext,它提供了一个SSLSocketFactory,可用于覆盖HttpsURLConnection的默认SSLSocketFactory.这样连接将使用您的CA进行证书验证.“

现在,这是我的问题:我有一个使用自签名证书的网络服务器,我根据其证书创建了一个“BKS信任库”.我已将de BKS信任库导入我的Android APP,现在,我的应用程序上有以下代码(我刚刚在这里发布了MainActivity,这是迄今为止唯一与此主题相关的类,我想):

package com.domain.myapp;


import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;

import android.widget.EditText;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import java.io.InputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;


public class LoginScreen extends AppCompatActivity {

Context ctx          = null;
InputStream inStream = null;
HurlStack hurlStack  = null;

EditText username    = null;
EditText password    = null;
String loginStatus   = null;

public LoginScreen() {

    try {
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        KeyStore ks = KeyStore.getInstance("BKS");
        inStream = ctx.getApplicationContext().getResources().openRawResource(R.raw.mytruststore);
        ks.load(inStream, null);
        inStream.close();
        tmf.init(ks);
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);
        final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        hurlStack = new HurlStack(null, sslSocketFactory);
    } catch (Exception e){
        Log.d("Exception:",e.toString());
    }
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_login_screen);
    username = (EditText) findViewById(R.id.user);
    password = (EditText) findViewById(R.id.passwd);
}

public void login(View view) {

    RequestQueue queue = Volley.newRequestQueue(this, hurlStack);
    final String url = "https://myserver.domain.com/app/login";

    StringRequest postRequest = new StringRequest(Request.Method.POST, url,
            new Response.Listener<String>()
            {
                @Override
                public void onResponse(String response) {
                    Log.d("Response", response);
                    loginStatus = "OK";
                }
            },
            new Response.ErrorListener()
            {
                @Override
                public void one rrorResponse(VolleyError error) {
                    Log.d("Error.Response", String.valueOf(error));
                    loginStatus = "NOK";
                }
            }
    ) {
        @Override
        protected Map<String, String> getParams()
        {
            Map<String, String>  params = new HashMap<String, String>();
            params.put("username", String.valueOf(user));
            params.put("domain", String.valueOf(passwd));

            return params;
        }
    };
    queue.add(postRequest);

    if (loginStatus == "OK") {
        Intent intent = new Intent(LoginScreen.this, OptionScreen.class);
        startActivity(intent);
    } else {
        Toast.makeText(getApplicationContext(), "Login failed",Toast.LENGTH_SHORT).show();
    }
}

}

关于构造函数类,我冒昧地复制代码,对每个部分的内容进行了一些评论:

try {
// I have a TrustManagerFactory object
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
// I have a KeyStore considering BKS (BOUNCY CASTLE) KeyStore object
KeyStore ks = KeyStore.getInstance("BKS");
// I have configured a inputStream using my TrustStore file as a Raw Resource
inStream = ctx.getApplicationContext().getResources().openRawResource(R.raw.mytruststore);
// I have loaded my Raw Resource into the KeyStore object
ks.load(inStream, null);
inStream.close();
// I have initialiazed my Trust Manager Factory, using my Key Store Object
tmf.init(ks);
// I have created a new SSL Context object
SSLContext sslContext = SSLContext.getInstance("TLS");
// I have initialized my new SSL Context, with the configured Trust Managers found on my Trust Store
sslContext.init(null, tmf.getTrustManagers(), null);
// I have configured a HttpClientStack, using my brand new Socket Context
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
hurlStack = new HurlStack(null, sslSocketFactory);
} catch (Exception e){
Log.d("Exception:",e.toString());
}

在此之后,在另一个Class方法中,我有RequestQueue,使用我在Class COnstructor上配置的HttpClientStack:

RequestQueue queue = Volley.newRequestQueue(this, hurlStack);
final String url = "https://myserver.domain.com/app/login";
StringRequest postRequest = new StringRequest(Request.Method.POST, url,new Response.Listener<String>()
    {
    ...
    ...
    }

当我运行我的应用程序,提供我的WebServer预期的用户和密码时,我可以在Android Studio的Android Monitor中看到以下消息:

09-17 21:57:13.842 20617-20617/com.domain.myapp D/Error.Response:
com.android.volley.NoConnectionError:
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

经过所有这些解释,我有以下问题:

>为了让Android从我在类的构造函数中配置的自定义TrustManager的CA接受SSL证书,还必须配置什么?

原谅我,但我是Android编程的初学者,也是Java的初学者,所以也许,我犯了一个可怕的错误……

任何帮助将非常感激.

UPDATE

我已经改进了类的构造函数,对语句进行了更好的分组,并且还使用了KeyManagerFactory,这在这个过程中似乎非常重要.开始:

public class LoginScreen extends AppCompatActivity {

...
...

  public LoginScreen() {

    try {
        inStream = this.getApplicationContext().getResources().openRawResource(R.raw.mytruststore);

        KeyStore ks = KeyStore.getInstance("BKS");
        ks.load(inStream, "bks*password".toCharArray());
        inStream.close();

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
        kmf.init(ks, "bks*password".toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(ks);

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(),tmf.getTrustManagers(), null);
        SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
        hurlStack = new HurlStack(null, sslSocketFactory);
    } catch (Exception e){
        Log.d("Exception:",e.toString());
    }

  }

...
...

}

无论如何,我还有问题..

Response: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.

解决方法:

我通过以下代码在我的排球类中创建新的requestQueue来实现https

public RequestQueue getRequestQueue() {
    if (mRequestQueue == null) {
        mRequestQueue = Volley.newRequestQueue(getApplicationContext(), new HurlStack(null, newSslSocketFactory()));

    }

    return mRequestQueue;
}

private SSLSocketFactory newSslSocketFactory() {
    try {
        // Get an instance of the Bouncy Castle KeyStore format
        KeyStore trusted = KeyStore.getInstance("BKS");
        // Get the raw resource, which contains the keystore with
        // your trusted certificates (root and any intermediate certs)
        InputStream in = getApplicationContext().getResources().openRawResource(R.raw.keystore);
        try {
            // Initialize the keystore with the provided trusted certificates
            // Provide the password of the keystore
            trusted.load(in, KEYSTORE_PASSWORD);
        } finally {
            in.close();
        }

        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(trusted);

        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        SSLSocketFactory sf = context.getSocketFactory();
        return sf;
    } catch (Exception e) {
        throw new AssertionError(e);
    }
}

标签:android,ssl,https,android-volley,trustmanager
来源: https://codeday.me/bug/20190926/1821875.html