2014-10-16 15 views
6

Próbuję sprawić, aby moja aplikacja komunikowała się z moim serwerem za pośrednictwem https. Ponieważ nie chcę płacić za podpisanie mojego certyfikatu serwera przez zaufany urząd certyfikacji, rozwiązaniem jest użycie certyfikatu z podpisem własnym.Brak certyfikatu równorzędnego Wyjątek - Volley i Android z samopodpisanym certyfikatem

Więc stworzyłem mój caconfig.cnf następująco:

[ 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 

Potem stworzyliśmy i podpisał mój certyfikat za pomocą następujących poleceń:

$ 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 

W moim serwerze nodejs Kod, tworzę serwer https w ten sposób:

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

Aby sprawdzić, czy wszystko jest poprawne, Stworzyłem również skrypt klienta węzła, który wysyła żądanie do mojego serwera. Oto kod dla mojego klienta węzła:

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(); 

Po uruchomieniu skryptu klienta węzła działa on idealnie. Z drugiej strony, aplikacja Android Volley Examples, której używam do sprawdzania, jak Volley współpracuje z https, nie działa. Poniżej opisuję wszystkie kroki, które podjąłem, aby spróbować działać.

Utworzyłem bks plik za pomocą mój plik certificate.cer za pomocą następującego polecenia:

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 

Potem zweryfikowaniu, czy certyfikat został poprawnie importowane do .bks następująco:

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 

I mam następujący wynik, to znaczy, że jest poprawne:

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 

ja przyszedł do tego tutorial, i jak używam Volley, zdecydowałem się na to. Poniżej znajdują się następujące zmiany, które wprowadziłem do przykładowego projektu.

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" 

Ale kiedy wciśnięty przycisk, mam następujący wyjątek:

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate 

Poniżej jest mój 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); 
      } 
     }); 
    } 

... 

} 

Czy ktoś zna rozwiązanie? Dziękuję.

+0

Naprawdę nie możemy pomóc w debugowaniu kodu Java bez zobaczenia kodu Java. – CommonsWare

+0

@CommonsWare, wprowadziłem pewne zmiany w moim pytaniu. Czy możesz mi teraz pomóc? Dzięki ... – arthursfreire

+0

Nie mogę, bo nie używam Volley. Ale bez kodu nikt nie byłby w stanie ci pomóc. Teraz, jeśli istnieje specjalistyczny ekspert Volley używający SSL, mogą oni mieć pewne sugestie na podstawie tego, co widzą. – CommonsWare

Odpowiedz

0

Używam certyfikatu z podpisem własnym w środowisku testowym. Aby to zadziałało, wywołuję tę metodę w mojej klasie aplikacji w metodzie onCreate. Dzięki temu wszystkie certyfikaty są akceptowane. Nie jest to zapis, ale dla celów testowych jest w porządku.

@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) {} 
} 
Powiązane problemy