2014-10-16 20 views
6

Sto provando a far comunicare la mia app con il mio server tramite https. Poiché non desidero pagare per ottenere il certificato del mio server firmato da una CA attendibile, la soluzione è utilizzare un certificato autofirmato.Nessun certificato peer Eccezione - Volley e Android con certificato autofirmato

Così, ho creato il mio caconfig.cnf come segue:

[ ca ] 
default_ca    = CA_default     # The default ca section 

[ CA_default ] 
dir      = ./demoCA      # top dir 
database    = $dir/index.txt    # index file. 
new_certs_dir   = $dir/newcerts     # new certs dir 

certificate    = $dir/cacert.pem    # The CA cert 
serial     = $dir/serial     # serial no file 
private_key    = $dir/private/cakey.pem  # CA private key 
RANDFILE    = $dir/private/.rand   # random number file 

default_days   = 365       # how long to certify for 
default_crl_days  = 30       # how long before next CRL 
default_md    = md5       # md to use 
policy     = policy_any     # default policy 
email_in_dn    = no       # Don't add the email into cert DN 
name_opt    = ca_default     # Subject name display option 
cert_opt    = ca_default     # Certificate display option 
copy_extensions   = none       # Don't copy extensions from request 

[ policy_any ] 
countryName    = optional 
stateOrProvinceName  = optional 
organizationName  = optional 
organizationalUnitName = optional 
commonName    = supplied 
emailAddress   = optional 

Poi, ho creato e firmato il mio certificato utilizzando i seguenti comandi:

$ mkdir myCA myCA/private myCA/newcerts 
$ echo "01" > myCA/serial 
$ touch demoCA/index.txt 

$ openssl genrsa -des3 -out myCA/private/cakey.pem 1024 
$ openssl req -new -x509 -days 3650 -key myCA/private/cakey.pem -out myCA/cacert.pem 

$ openssl req -sha1 -newkey rsa:2048 -keyout server-key.pem -out server-cert-req.pem -subj '/CN=myhost/' -nodes 
$ openssl ca -config caconfig.cnf -in server-cert-req.pem -out server-cert.pem 
$ openssl x509 -inform PEM -in cacert.pem -outform DER -out certificate.cer 
$ rm server-cert-req.pem 

Nel mio server nodejs codice, sto creando il server https in questo modo:

var express = require('express'); 
var https = require('https'); 

var PORT = 443; 
var app = express(); 

app.get('/', function (req, res) { 
    res.send("Server is working"); 
}); 

var httpsOptions = { 
    key: fs.readFileSync('server-key.pem'), 
    cert: fs.readFileSync('server-cert.pem') 
}; 

https.createServer(httpsOptions, app).listen(PORT, function() { 
    console.log('%s: Node server started on port %d ...', Date(Date.now()), PORT); 
}); 

Per verificare se tutto è corretto, I Ho anche creato uno script client nodo, che effettua una richiesta al mio server. Ecco il codice per il mio client di nodo:

var https = require('https'); 
var fs = require('fs'); 

var request = https.request({ 
    host: 'myhost', 
    port: 443, 
    path: '/', 
    method: 'GET', 
    rejectUnauthorized: true, 

    // Once it is self signed, I'm using my server certificate (public key). 
    ca: [fs.readFileSync('cacert.pem').toString()] 
}, function(response) { 
    response.on('data', function(data) { 
     console.log(data.toString()); 
    }); 
}); 

request.on('error', function(err) { 
    console.log(err); 
}) 

request.end(); 

Quando eseguo il mio script client nodo, funziona perfettamente. D'altra parte, l'app Android Volley Examples, che sto usando per verificare come funziona Volley con https, non funziona. Di seguito, descrivo tutti i passaggi che ho seguito per cercare di farlo funzionare.

ho creato un file con estensione bks usando il mio file certificate.cer utilizzando il seguente comando:

keytool -importcert -v -trustcacerts -file "certificate.cer" -alias IntermediateCA -keystore "res/raw/my_keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret 

Poi, ho verificato se il certificato è stato importato correttamente nei .bks come segue:

keytool -list -keystore "res/raw/my_keystore.bks" -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath "path_to_bouncycastle/bcprov-jdk16-146.jar" -storetype BKS -storepass mysecret 

E ho avuto il seguente output, che significa che è corretto:

Keystore type: BKS 
Keystore provider: BC 

Your keystore contains 1 entry 

imeto_alias, Oct 16, 2014, trustedCertEntry, 
Certificate fingerprint (SHA1): 03:DC:A1:6A:9B:1D:AD:59:A9:9B:1F:C2:43:7E:80:07:3B:B6:BE:CB 

ho venuto a questo tutorial e, dato che sto usando Volley, ho deciso di seguirlo. Quindi, di seguito sono le seguenti modifiche che ho apportato al progetto di esempio.

Got Volley from git clone https://android.googlesource.com/platform/frameworks/volley 

Got Android Volley Examples project from git clone git://github.com/ogrebgr/android_volley_examples.git 

Copied my_keystore.bks containing the self-signed public key in res/raw; 

Opened Act_SsSslHttpClient in the examples project, found "R.raw.test" and replaced it with R.raw.my_keystore; 

Found "new SslHttpClient(" and replaced the default password "test123″ with "mysecret"; 

Replaced "44400" with the HTTPS port of my server/virtualhost ("443"). (I could also remove this parameter since "443" is the default port; 

Replaced "https://tp.bolyartech.com:44400/https_test.html" with my server URL. 

Started the app, went to "HTTPS with self-signed cert", then "Execute HTTPS request" 

Ma, quando ho premuto il pulsante, ho ottenuto la seguente eccezione:

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 

Qui di seguito, è il mio JavaCode ...

public class Act_SsSslHttpClient extends Activity { 
    private TextView mTvResult; 


    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.act__ss_ssl_http_client); 

     mTvResult = (TextView) findViewById(R.id.tv_result); 

     Button btnSimpleRequest = (Button) findViewById(R.id.btn_simple_request); 
     btnSimpleRequest.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 

       // Replace R.raw.test with your keystore 
       InputStream keyStore = getResources().openRawResource(R.raw.my_keystore); 


       // Usually getting the request queue shall be in singleton like in {@seeAct_SimpleRequest} 
       // Current approach is used just for brevity 
       RequestQueue queue = Volley.newRequestQueue(Act_SsSslHttpClient.this, 
            new ExtHttpClientStack(new SslHttpClient(keyStore, 
             "mysecret"))); 

       StringRequest myReq = new StringRequest(Method.GET, 
                "https://myServerURL/", 
                createMyReqSuccessListener(), 
                createMyReqErrorListener()); 

       queue.add(myReq); 
      } 
     }); 
    } 

... 

} 

Qualcuno sa la soluzione? Grazie.

+0

Non possiamo davvero aiutarti a eseguire il debug del tuo codice Java senza vedere il tuo codice Java. – CommonsWare

+0

@CommonsWare, ho apportato alcune modifiche alla mia domanda. Puoi aiutarmi ora? Grazie ... – arthursfreire

+0

Non posso, perché non uso Volley. Ma senza il codice, nessuno sarebbe in grado di aiutarti. Ora, se esiste un SSL personalizzato che usa l'esperto di Volley, potrebbe avere alcuni suggerimenti basati su ciò che vedono. – CommonsWare

risposta

0

Sto utilizzando un certificato autofirmato nel mio ambiente di test. Per farlo funzionare, chiamo questo metodo nella mia classe Application nel metodo onCreate. Rende tutti i certificati accettati. Non è salva, ma a scopo di test va bene.

@Override 
public void onCreate() { 
    nuke(); 
    super.onCreate(); 
} 

public static void nuke() { 
    try { 
     TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { 
      public X509Certificate[] getAcceptedIssuers() { 
       X509Certificate[] myTrustedAnchors = new X509Certificate[0]; 
       return myTrustedAnchors; 
      } 

      @Override 
      public void checkClientTrusted(X509Certificate[] certs, 
        String authType) {} 

      @Override 
      public void checkServerTrusted(X509Certificate[] certs, 
        String authType) {} 
     } }; 

     SSLContext sc = SSLContext.getInstance("SSL"); 
     sc.init(null, trustAllCerts, new SecureRandom()); 
     HttpsURLConnection 
       .setDefaultSSLSocketFactory(sc.getSocketFactory()); 
     HttpsURLConnection 
       .setDefaultHostnameVerifier(new HostnameVerifier() { 

        @Override 
        public boolean verify(String arg0, SSLSession arg1) { 
         return true; 
        } 
       }); 
    } catch (Exception e) {} 
} 
Problemi correlati