如何让SSL peer_verify在Android上运行?

  发布于 2022-12-28 17:52

我在Android上用openssl-1.0.1h成功构建了libcurl-7.36.0.我运行了一个示例代码来测试HTTPS连接.默认情况下启用SSL_VERIFYPEER.Android上的证书路径是/ system/etc/security/cacerts,因此我将CURLOPT_CAPATH设置为/ system/etc/security/cacerts.

ls -l /system/etc/security/cacerts
-rw-r--r-- root     root         4767 2012-09-22 11:57 00673b5b.0
-rw-r--r-- root     root         4573 2012-09-22 11:57 03e16f6c.0
-rw-r--r-- root     root         5292 2012-09-22 11:57 08aef7bb.0
......

这是我的代码片段..

curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "https://www.google.com:443");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);     // default
curl_easy_setopt(curl, CURLOPT_CAPATH, "/system/etc/security/cacerts");
curl_easy_perform(curl);

Curl始终返回错误:

== Info: SSL certificate problem: unable to get local issuer certificate  
== Info: Closing connection 0  
curl_easy_perform() failed: Peer certificate cannot be authenticated with given CA certificates

它的工作,如果我请从CA包文件CA-bundle.crt http://curl.haxx.se/docs/caextract.html和curl_easy_setopt(curl, CURLOPT_CAINFO, "path:/ca-bundle.crt").

这是我的问题:有没有办法通过从/system/etc/security/cacerts手动下载CA捆绑文件并指定CURLOPT_CAINFO?来读取证书来使SSL对等验证工作?

1 个回答
  • 如果在Android应用程序中使用libcurl,CURLOPT_SSL_VERIFYPEER将失败,因此如果没有CA捆绑,则阻止CURL发送数据.解决这个问题的一种方法是关闭这个非常非常糟糕的选项.我们必须提供自己的CA捆绑包,并使用CURLOPT_CAINFO选项提供CA捆绑包文件的绝对路径.

    从"cacert.pem"文件http://curl.haxx.se/docs/caextract.html可以放在资源或资产,但我更喜欢的资源目录.

    CURL期望绝对路径,我们不能给出资产文件夹的绝对路径,因为打包的android APK文件就像一个压缩文件夹,因此我们需要将PEM文件从资产复制到内部存储或外部存储,但我更喜欢内部存储,因为它是私有的app并提供CAINFO中内部存储目录的绝对路径.例如,如果应用名称为com.example.androidtest,则CAINFO路径为"/data/data/com.example.androidtest/cacert.pem".

    CURL的示例实现使用TLS1.2,openSSL 1.01p,curl版本7.40.0,带验证对等的cacert.pem包,验证主机名选项显示在https://github.com/vyshas/CURL-Android-with-verify -peer-

    以上链接的重要部分如下所示:

    JAVA Side

    public native void setDir(String caCertDir);
    
    setDir(saveCertPemFile());
    
    
        private String saveCertPemFile()
        {
            Context context=getApplicationContext();
            String assetFileName="cacert.pem";
    
            if(context==null || !FileExistInAssets(assetFileName,context))
            {
                Log.i("TestActivity", "Context is null or asset file doesnt exist");
                return null;
            }
            //destination path is data/data/packagename
            String destPath=getApplicationContext().getApplicationInfo().dataDir;
            String CertFilePath =destPath + "/" +assetFileName;
            File file = new File(CertFilePath);
            if(file.exists())
            {
                //delete file
                file.delete();
            }
            //copy to internal storage
            if(CopyAssets(context,assetFileName,CertFilePath)==1) return CertFilePath;
    
            return CertFilePath=null;
    
        }
    
        private int CopyAssets(Context context,String assetFileName, String toPath)
        {
            AssetManager assetManager = context.getAssets();
            InputStream in = null;
            OutputStream out = null;
            try {
                in = assetManager.open(assetFileName);
                new File(toPath).createNewFile();
                out = new FileOutputStream(toPath);
                byte[] buffer = new byte[1024];
                int read;
                while ((read = in.read(buffer)) != -1)
                {
                    out.write(buffer, 0, read);
                }
                in.close();
                in = null;
                out.flush();
                out.close();
                out = null;
                return 1;
            } catch(Exception e) {
                Log.e("tag", "CopyAssets"+e.getMessage());
    
            }
            return 0;
    
        }
    
        private boolean FileExistInAssets(String fileName,Context context)
        {
            try {
                return Arrays.asList(context.getResources().getAssets().list("")).contains(fileName);
            } catch (IOException e) {
                // TODO Auto-generated catch block
    
                Log.e("tag", "FileExistInAssets"+e.getMessage());
    
            }
            return false;
        }
    

    JNI SIDE

    JNIEXPORT void JNICALL Java_com_example_androidtest_TestActivity_setDir(JNIEnv*env,jobject obj,jstring caCertDir){if(!caCertDir)return;

    JNIEXPORT void JNICALL Java_com_example_androidtest_TestActivity_setDir(JNIEnv* env, jobject obj, jstring caCertDir)
    {
        if(!caCertDir) return;
    
        const char* caCertDir_c = env->GetStringUTFChars(caCertDir, NULL);
                if (!caCertDir_c) return ;
        const jsize len = env->GetStringUTFLength(caCertDir);
                LOGI( "CaCertDir: %s", caCertDir_c );
                std::string caCert(caCertDir_c,len);
                caCertPtr=caCert;
                LOGI( "CaCertDirptr in std string: %s", caCertPtr.c_str());
                env->ReleaseStringUTFChars(caCertDir, caCertDir_c);
    }
    

    }

    CURL代码

    CURL* curl = curl_easy_init();
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
    /*  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE);
        curl_easy_setopt(curl, CURLOPT_FAILONERROR, TRUE);*/
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &curlCallback);
        curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, downloadObject);
        curl_easy_setopt(curl,CURLOPT_CAINFO,caCertPtr.c_str());
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
    
        curl_version_info_data * vinfo = curl_version_info( CURLVERSION_NOW );
        if( vinfo->features & CURL_VERSION_SSL )
            // SSL support enabled
             LOGI("SSL support enabled");
        else
        {// No SSL
             LOGI("NO SSL");
        }
    
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK){
            LOGI("CURL failed with error code %d", res);
        }
    
        LOGI("CURL download is OK, result:%d", res);
        curl_easy_cleanup(curl);
        return res == CURLE_OK;
    

    2022-12-28 17:54 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有