2015-09-18 23 views
7

Quindi sto cercando di utilizzare libcurl con JNI ma restituisce errore CURLE_SSL_CACERT_BADFILE. Questo è il mio codicelibcurl Errore CURLE_SSL_CACERT_BADFILE su android

JNI lato:

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 

     } 
    } 

lato 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" è il certificato memorizzato nella cartella asset.

E questo è il percorso del certificato di essere inviato alla JNI:

/data/data/packageName/certificateName.der

Reference

risposta

1

Non hai spiegato pienamente ciò che si sta utilizzando qui, ma come lo farò indovina che hai una libcurl costruita contro OpenSSL sotto. L'opzione CURLOPT_CAINFO dovrebbe quindi essere il nome del file che identifica il gruppo di certificati CA, utilizzando il formato PEM. Quel pacchetto è tutti i certificati per le tue CA di fiducia.

La tua descrizione fa sembrare che tu abbia un file DER, ma non puoi usare DER per il pacchetto di certificati CA con OpenSSL.

Un modo comune per ottenere un pacchetto CA decente è scaricare lo PEM version of the bundle that Mozilla ships incluso in Firefox.

+0

in base alla mia altra domanda su SO http://stackoverflow.com/questions/32648577/libcurl-curle-ssl-cacert-badfile-error-on-android/34312254#34312254 come è possibile inviare lo stesso file da iPhone ma non da Android? Utilizzo dello stesso codice su entrambe le piattaforme – Grace

+0

Intendi http://stackoverflow.com/questions/32963148/libcurl-certificate-pinning-working-on-iphone-but-not-on-android? non è questa domanda, quindi sarebbe strano rispondere qui ma sembra che stia usando il formato di file sbagliato se si usa OpenSSL. –