2015-09-18 21 views
7

Próbuję użyć libcurl z JNI, ale zwraca błąd CURLE_SSL_CACERT_BADFILE. To jest mój kod.Błąd libcurl CURLE_SSL_CACERT_BADFILE na Androidzie

JNI strona:

static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) 
{ 
    ((string*)userp)->append((char*)contents, size * nmemb); 
    return size * nmemb; 
} 


//jList is an array containing the certificate. 

Java_packageName_MainActivity_Test(JNIEnv *env, jobject thiz, jobject jList) 
    { 

     vector<string> certificatesPinning; 

     // Convert jobject to jobjectArray 
     // retrieve the java.util.List interface class 
     jclass cList = env->FindClass("java/util/List"); 
     // retrieve the toArray method and invoke it 
     jmethodID mToArray = env->GetMethodID(cList, "toArray", "()[Ljava/lang/Object;"); 
     jobjectArray stringArray = (jobjectArray)env->CallObjectMethod(jList, mToArray); 

     // Add each certificate to the list 
     int stringCount = (env)->GetArrayLength(stringArray); 
     for (int i=0; i < stringCount; i++) 
     { 
      jstring certificateString = (jstring)(env)-> GetObjectArrayElement(stringArray, i); 
      const char *cert = (env)->GetStringUTFChars(certificateString, 0); 
      const jsize len = env->GetStringUTFLength(certificateString); 

      string certificatePinningObj(cert,len); 

      certificatesPinning.push_back(certificatePinningObj); 
      (env)->ReleaseStringUTFChars(certificateString, cert); 
     } 

     string readBuffer; 
     CURL *curl = curl_easy_init(); 
     curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); 
     curl_easy_setopt(curl, CURLOPT_URL, "https://theapi.com"); 
     curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);// Fill the response in the readBuffer 
     curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); 
     curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 120); // 120 s connect timeout 
     curl_easy_setopt(curl, CURLOPT_ENCODING, GZIP); 
     curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"der"); 

     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER , 1); 
     curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST , 2L); 
     curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); 
     curl_easy_setopt(curl, CURLOPT_CAINFO,certificatesPinning[0].c_str());//buf 


     CURLcode res; 
     res = curl_easy_perform(curl); 
     if(!readBuffer.empty()) 
     { 
      printf("success \n"); 
     } 
     else 
     { 
      printf("error \n"); 
     int a = (int)res;// this is 77 = CURLE_SSL_CACERT_BADFILE 

     } 
    } 

strona JAVA:

// Define the function 
native void Test(ArrayList<String> certificates); 

// Prepare the certificate 
ArrayList<String> certificatesPinning = new ArrayList<String>(); 
certificatesPinning.add(saveCertPemFile()); 

// Call the function 
Test(certificatesPinning); 


// Helpers 
    private String saveCertPemFile() 
    { 
     Context context=getApplicationContext(); 
     String assetFileName="certificateName.der"; 

     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; 
    } 

"certificateName.der" jest certyfikat zapisany w folderze aktywów.

I to jest ścieżka certyfikat jest wysyłany do JNI:

/data/data/packageName/certificateName.der

Reference

Odpowiedz

1

Nie wyjaśniono w pełni czego używasz tutaj, ale jak będę odgadnąć, że masz libcurl zbudowany przeciwko OpenSSL pod spodem. Opcja CURLOPT_CAINFO powinna wówczas być nazwą pliku identyfikującą pakiet certyfikatów CA, z wykorzystaniem formatu PEM. Ten pakiet to wszystkie certyfikaty dla zaufanych urzędów certyfikacji.

Twój opis sprawia, że ​​brzmi to tak, jakbyś miał plik DER, ale nie możesz używać DER dla pakietu certyfikatów CA z OpenSSL.

Popularnym sposobem na uzyskanie przyzwoitego pakietu CA jest pobranie wersji PEM version of the bundle that Mozilla ships zawartej w przeglądarce Firefox.

+0

na podstawie mojego drugiego pytania na stronie http://pl.wikimedia.org/questions/32648577/libcurl-curle-ssl-cacert-badfile-error-on-android/34312254#34312254 jak to jest możliwe, że jestem w stanie wysłać ten sam plik z iPhone'a, ale nie z Androida? Korzystanie z tego samego kodu na obu platformach – Grace

+0

Masz na myśli http://stackoverflow.com/questions/32963148/libcurl-certificate-pinning-working-onhone-but-not-on-android? to nie jest to pytanie, więc byłoby dziwnie odpowiedzieć na to pytanie, ale wydaje się, że używa on niewłaściwego formatu pliku, jeśli korzystasz z OpenSSL. –