accepter les connexions HTTPS avec des certificats auto-signés

j'essaie de faire des connexions HTTPS, en utilisant HttpClient lib, mais le problème est que, puisque le certificat n'est pas signé par une autorité de Certification (AC) reconnue comme Verisign , GlobalSIgn , etc., listé sur le jeu de certificats de confiance Android, je continue d'obtenir javax.net.ssl.SSLException: Not trusted server certificate .

j'ai vu des solutions où vous acceptez simplement tous les certificats, mais que faire si je veux demander à l'utilisateur?

je veux obtenir un dialogue similaire à celui du navigateur, laissant l'utilisateur décider de continuer ou non. De préférence, j'aimerais utiliser le même certificatestore que le navigateur. Des idées?

142
demandé sur ivanleoncz 2010-01-06 14:20:21

12 réponses

la première chose à faire est de définir le niveau de vérification. De tels niveaux ne sont pas tellement:

  • ALLOW_ALL_HOSTNAME_VERIFIER
  • BROWSER_COMPATIBLE_HOSTNAME_VERIFIER
  • STRICT_HOSTNAME_VERIFIER

bien que la méthode setHostnameVerifier() soit obsolète pour la nouvelle bibliothèque apache, mais pour la version sous Android SDK est normal. Et donc, nous prendre ALLOW_ALL_HOSTNAME_VERIFIER et le régler dans l'usine de méthode SSLSocketFactory.setHostnameVerifier() .

ensuite, vous devez configurer notre usine pour le protocole de https. Pour ce faire, il suffit d'appeler la méthode SchemeRegistry.register() .

ensuite, vous devez créer un DefaultHttpClient avec SingleClientConnManager . Aussi dans le code ci-dessous vous pouvez voir que sur la valeur par défaut utilisera également notre drapeau ( ALLOW_ALL_HOSTNAME_VERIFIER ) par la méthode HttpsURLConnection.setDefaultHostnameVerifier()

ci-dessous le code fonctionne pour moi:

HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

DefaultHttpClient client = new DefaultHttpClient();

SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());

// Set verifier     
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

// Example send http request
final String url = "https://encrypted.google.com/";
HttpPost httpPost = new HttpPost(url);
HttpResponse response = httpClient.execute(httpPost);
166
répondu Nikolay Moskvin 2012-12-11 08:57:42

les principales étapes suivantes sont nécessaires pour obtenir une connexion sécurisée des Autorités de Certification qui ne sont pas considérées comme fiables par la plate-forme android.

comme demandé par de nombreux utilisateurs, j'ai reproduit les parties les plus importantes de mon article de blog ici:

  1. Saisir tous les certificats nécessaires (de la racine et de toute l'autorité de certification intermédiaire)
  2. créer un keystore avec keytool et le BouncyCastle le fournisseur et l'importation de la certs
  3. chargez le keystore dans votre application android et utilisez-le pour les connexions sécurisées (je recommande d'utiliser le Apache HttpClient au lieu de la norme java.net.ssl.HttpsURLConnection (plus facile à comprendre, plus performant)

Saisir les certs

vous devez obtenir tous les certificats qui construisent une chaîne à partir du certificat endpoint tout le chemin jusqu'à la racine CA. Cela signifie, tout (si présent) CERT de CA intermédiaire et aussi le cert de CA racine. Vous n'avez pas besoin d'obtenir le certificat du point final.

Créer le fichier de clés

Téléchargez le BouncyCastle Provider et conservez-le à un endroit connu. Assurez-vous également que vous pouvez invoquer la commande keytool (habituellement située sous le dossier bin de votre installation JRE).

importe maintenant le produit obtenu certs (ne pas importer le point de terminaison cert) dans un BouncyCastle formaté fichier de clés.

je n'ai pas testé, mais je pense que l'ordre d'importation des certificats est important. Cela signifie qu'il faut importer d'abord le certificat CA Intermédiaire le plus bas et ensuite jusqu'au certificat CA racine.

avec la commande suivante un nouveau keystore (si pas déjà présent) avec le mot de passe mysecret sera créé et L'Intermédiaire Le certificat de L'AC sera importé. J'ai également défini le fournisseur de BouncyCastle, où il peut être trouvé sur mon système de fichiers et le format de keystore. Exécuter cette commande pour chaque certificat de la chaîne.

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

Vérifier si les certificats ont été correctement importés dans le fichier de stockage des clés:

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

devrait sortir la chaîne entière:

RootCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 24:77:D9:A8:91:D1:3B:FA:88:2D:C2:FF:F8:CD:33:93
IntermediateCA, 22.10.2010, trustedCertEntry, Thumbprint (MD5): 98:0F:C3:F8:39:F7:D8:05:07:02:0D:E3:14:5B:29:43

Maintenant, vous pouvez copier le keystore comme une ressource brute dans votre application android sous res/raw/

utilisez le keystore dans votre application

tout d'abord, nous devons créer un client Apache HttpClient personnalisé qui utilise notre keystore pour les connexions HTTPS:

public class MyHttpClient extends DefaultHttpClient {

  final Context context;

  public MyHttpClient(Context context) {
      this.context = context;
  }

  @Override
  protected ClientConnectionManager createClientConnectionManager() {
      SchemeRegistry registry = new SchemeRegistry();
      registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
      // Register for port 443 our SSLSocketFactory with our keystore
      // to the ConnectionManager
      registry.register(new Scheme("https", newSslSocketFactory(), 443));
      return new SingleClientConnManager(getParams(), registry);
  }

  private SSLSocketFactory newSslSocketFactory() {
      try {
          // Get an instance of the Bouncy Castle KeyStore format
          KeyStore trusted = KeyStore.getInstance("BKS");
          // Get the raw resource, which contains the keystore with
          // your trusted certificates (root and any intermediate certs)
          InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
          try {
              // Initialize the keystore with the provided trusted certificates
              // Also provide the password of the keystore
              trusted.load(in, "mysecret".toCharArray());
          } finally {
              in.close();
          }
          // Pass the keystore to the SSLSocketFactory. The factory is responsible
          // for the verification of the server certificate.
          SSLSocketFactory sf = new SSLSocketFactory(trusted);
          // Hostname verification from certificate
          // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
          sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
          return sf;
      } catch (Exception e) {
          throw new AssertionError(e);
      }
  }
}

nous avons créé notre HttpClient personnalisé, maintenant nous pouvons l'utiliser pour des connexions sécurisées. Par exemple quand nous faisons un appel GET à une ressource de repos.

// Instantiate the custom HttpClient
DefaultHttpClient client = new MyHttpClient(getApplicationContext());
HttpGet get = new HttpGet("https://www.mydomain.ch/rest/contacts/23");
// Execute the GET call and obtain the response
HttpResponse getResponse = client.execute(get);
HttpEntity responseEntity = getResponse.getEntity();

;)

118
répondu saxos 2011-11-25 09:30:33

si vous avez un certificat personnalisé/auto-signé sur le serveur qui n'est pas là sur l'appareil, vous pouvez utiliser la classe ci-dessous pour le charger et l'utiliser sur le côté client dans Android:

Placer le certificat *.crt fichier /res/raw de sorte qu'il est disponible à partir de R.raw.*

utiliser la classe ci-dessous pour obtenir un HTTPClient ou HttpsURLConnection qui aura une usine de douilles en utilisant ce certificat:

package com.example.customssl;

import android.content.Context;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;

public class CustomCAHttpsProvider {

    /**
     * Creates a {@link org.apache.http.client.HttpClient} which is configured to work with a custom authority
     * certificate.
     *
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http Client.
     * @throws Exception If there is an error initializing the client.
     */
    public static HttpClient getHttpClient(Context context, int certRawResId, boolean allowAllHosts) throws Exception {


        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // init ssl socket factory with key store
        SSLSocketFactory sslSocketFactory = new SSLSocketFactory(keyStore);

        // skip hostname security check if specified
        if (allowAllHosts) {
            sslSocketFactory.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        // basic http params for client
        HttpParams params = new BasicHttpParams();

        // normal scheme registry with our ssl socket factory for "https"
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));

        // create connection manager
        ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);

        // create http client
        return new DefaultHttpClient(cm, params);
    }

    /**
     * Creates a {@link javax.net.ssl.HttpsURLConnection} which is configured to work with a custom authority
     * certificate.
     *
     * @param urlString     remote url string.
     * @param context       Application Context
     * @param certRawResId  R.raw.id of certificate file (*.crt). Should be stored in /res/raw.
     * @param allowAllHosts If true then client will not check server against host names of certificate.
     * @return Http url connection.
     * @throws Exception If there is an error initializing the connection.
     */
    public static HttpsURLConnection getHttpsUrlConnection(String urlString, Context context, int certRawResId,
                                                           boolean allowAllHosts) throws Exception {

        // build key store with ca certificate
        KeyStore keyStore = buildKeyStore(context, certRawResId);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, tmf.getTrustManagers(), null);

        // Create a connection from url
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
        urlConnection.setSSLSocketFactory(sslContext.getSocketFactory());

        // skip hostname security check if specified
        if (allowAllHosts) {
            urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
        }

        return urlConnection;
    }

    private static KeyStore buildKeyStore(Context context, int certRawResId) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
        // init a default key store
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);

        // read and add certificate authority
        Certificate cert = readCert(context, certRawResId);
        keyStore.setCertificateEntry("ca", cert);

        return keyStore;
    }

    private static Certificate readCert(Context context, int certResourceId) throws CertificateException, IOException {

        // read certificate resource
        InputStream caInput = context.getResources().openRawResource(certResourceId);

        Certificate ca;
        try {
            // generate a certificate
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            ca = cf.generateCertificate(caInput);
        } finally {
            caInput.close();
        }

        return ca;
    }

}

Points clés:

  1. Certificate les objets sont générés à partir des fichiers .crt .
  2. par défaut KeyStore est créé.
  3. keyStore.setCertificateEntry("ca", cert) ajoute un certificat à key store sous alias "ca". Vous modifiez le code pour ajouter d'autres certificats (CA intermédiaire, etc.).
  4. l'objectif Principal est de générer un SSLSocketFactory , qui peut ensuite être utilisé par HTTPClient ou HttpsURLConnection .
  5. SSLSocketFactory peut être configuré ultérieurement, par exemple pour sauter la vérification du nom d'hôte, etc.

pour plus d'information : http://developer.android.com/training/articles/security-ssl.html

14
répondu S.D. 2014-05-16 14:28:28

j'étais frustré d'essayer de connecter mon application Android à mon service RESTful en utilisant https. En outre, j'ai été un peu ennuyé par toutes les réponses qui ont suggéré de désactiver la vérification de certificat tout à fait. Si vous le faites, Quel est l'intérêt de https?

après avoir googlé sur le sujet pendant un certain temps, j'ai finalement trouvé cette solution où les pots externes ne sont pas nécessaires, juste des API Android. Merci à Andrew Smith, qui l'a posté le juillet, 2014

 /**
 * Set up a connection to myservice.domain using HTTPS. An entire function
 * is needed to do this because myservice.domain has a self-signed certificate.
 * 
 * The caller of the function would do something like:
 * HttpsURLConnection urlConnection = setUpHttpsConnection("https://littlesvr.ca");
 * InputStream in = urlConnection.getInputStream();
 * And read from that "in" as usual in Java
 * 
 * Based on code from:
 * https://developer.android.com/training/articles/security-ssl.html#SelfSigned
 */
public static HttpsURLConnection setUpHttpsConnection(String urlString)
{
    try
    {
        // Load CAs from an InputStream
        // (could be from a resource or ByteArrayInputStream or ...)
        CertificateFactory cf = CertificateFactory.getInstance("X.509");

        // My CRT file that I put in the assets folder
        // I got this file by following these steps:
        // * Go to https://littlesvr.ca using Firefox
        // * Click the padlock/More/Security/View Certificate/Details/Export
        // * Saved the file as littlesvr.crt (type X.509 Certificate (PEM))
        // The MainActivity.context is declared as:
        // public static Context context;
        // And initialized in MainActivity.onCreate() as:
        // MainActivity.context = getApplicationContext();
        InputStream caInput = new BufferedInputStream(MainActivity.context.getAssets().open("littlesvr.crt"));
        Certificate ca = cf.generateCertificate(caInput);
        System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());

        // Create a KeyStore containing our trusted CAs
        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);

        // Create a TrustManager that trusts the CAs in our KeyStore
        String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
        tmf.init(keyStore);

        // Create an SSLContext that uses our TrustManager
        SSLContext context = SSLContext.getInstance("TLS");
        context.init(null, tmf.getTrustManagers(), null);

        // Tell the URLConnection to use a SocketFactory from our SSLContext
        URL url = new URL(urlString);
        HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
        urlConnection.setSSLSocketFactory(context.getSocketFactory());

        return urlConnection;
    }
    catch (Exception ex)
    {
        Log.e(TAG, "Failed to establish SSL connection to server: " + ex.toString());
        return null;
    }
}

ça a bien marché pour mon application.

6
répondu Gonzalo Fernández 2016-01-28 11:14:38

la meilleure réponse ne marchait pas pour moi. Après une enquête, j'ai trouvé les informations nécessaires sur " Android Developer": https://developer.android.com/training/articles/security-ssl.html#SelfSigned

créer une implémentation vide de X509TrustManager a fait l'affaire:

private static class MyTrustManager implements X509TrustManager
{

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
         throws CertificateException
    {
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException
    {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers()
    {
        return null;
    }

}

...

HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
try
{
    // Create an SSLContext that uses our TrustManager
    SSLContext context = SSLContext.getInstance("TLS");
    TrustManager[] tmlist = {new MyTrustManager()};
    context.init(null, tmlist, null);
    conn.setSSLSocketFactory(context.getSocketFactory());
}
catch (NoSuchAlgorithmException e)
{
    throw new IOException(e);
} catch (KeyManagementException e)
{
    throw new IOException(e);
}
conn.setRequestMethod("GET");
int rcode = conn.getResponseCode();

s'il vous Plaît être conscient que ce vide de la mise en œuvre de TustManager est juste un exemple et en l'utilisant dans des activités productives l'environnement serait une grave menace pour la sécurité!

5
répondu Markus Lenger 2014-08-15 17:02:15

Voici comment vous pouvez ajouter des certificats supplémentaires à votre KeyStore pour éviter ce problème: faire confiance à tous les certificats en utilisant HttpClient sur HTTPS

il ne sera pas demander à l'utilisateur comme vous le demandez, mais il sera moins probable que l'utilisateur va exécuter dans un" certificat de serveur de confiance " erreur.

4
répondu emmby 2017-05-23 12:10:08

Google recommande l'utilisation de Android Volley pour les connexions HTTP/HTTPS , depuis que HttpClient est déprécié. Donc, vous savez le bon choix :).

et aussi, jamais NUKE certificats SSL (jamais!!!).

nuke Certificats SSL, est totalement contraire à l'objectif du protocole SSL, qui est de promouvoir la sécurité . Il n'y a aucun sens D'utiliser SSL, si vous prévoyez de bombarder tous les certificats SSL qui viennent. Une meilleure solution serait, ne pas utiliser SSL, ou une meilleure solution, serait de créer un personnalisé TrustManager sur votre App + en utilisant Android Volley pour les connexions HTTP/HTTPS.

voici un Gist que j'ai créé, avec un loginapp de base, effectuant des connexions HTTPS, en utilisant un certificat auto-signé sur le côté serveur, accepté sur L'application.

voici aussi un autre Gist que peut aider, pour la création de certificats SSL auto-signés pour la mise en place sur votre serveur et aussi en utilisant le certificat sur votre application. très important: vous devez copier le .crt fichier qui a été généré par le script ci-dessus, dans le répertoire "raw" de votre projet Android.

4
répondu ivanleoncz 2018-02-20 16:26:16

j'ai écrit une petite bibliothèque ssl-utils-android de confiance certificat en particulier sur Android.

vous pouvez simplement charger n'importe quel certificat en donnant le nom du fichier du répertoire assets.

Utilisation:

OkHttpClient client = new OkHttpClient();
SSLContext sslContext = SslUtils.getSslContextForCertificateFile(context, "BPClass2RootCA-sha2.cer");
client.setSslSocketFactory(sslContext.getSocketFactory());
1
répondu klimat 2016-03-31 10:22:01

aucune de ces corrections n'a fonctionné pour ma plate-forme de développement ciblant SDK 16, Version 4.1.2, donc j'ai trouvé une solution.

mon application stocke des données sur le serveur en utilisant " http://www.example.com/page.php?data=somedata "

Récemment de la page.php a été déplacé à " https://www.secure-example.com/page.php "et je continue à recevoir" javax.net.ssl.SSLException: not trusted server certificate".

Au lieu d'accepter tous les certificats pour une seule page, à partir de ce guide j'ai résolu mon problème en écrivant ma propre page.php publié sur " http://www.example.com/page.php "

<?php

caronte ("https://www.secure-example.com/page.php");

function caronte($url) {
    // build curl request
    $ch = curl_init();
    foreach ($_POST as $a => $b) {
        $post[htmlentities($a)]=htmlentities($b);
    }
    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($post));

    // receive server response ...
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $server_output = curl_exec ($ch);
    curl_close ($ch);

    echo $server_output;
}

?>
1
répondu Rudy 2017-05-23 11:47:23

peut-être que cela vous aidera... il fonctionne sur les clients java en utilisant des certificats auto-signés (il n'y a pas de vérification du certificat). Soyez prudent et utilisez-le seulement pour les cas de développement parce que ce n'est pas sûr du tout!!

comment ignorer les erreurs de certificat SSL dans Apache HttpClient 4.0

espère que cela fonctionnera sur Android en ajoutant la bibliothèque HttpClient... bonne chance!!

0
répondu EmP 2017-05-23 12:18:02

C'est un problème résultant du manque de support SNI(Server Name Identification) inA,ndroid 2.x. J'ai été aux prises avec ce problème pendant une semaine jusqu'à ce que je tombe sur la question suivante, qui non seulement donne un bon arrière-plan du problème, mais fournit également une solution efficace et fonctionnelle sans trous de sécurité.

"pas d'erreur de certificat peer" dans Android 2.3 mais pas dans 4

0
répondu alumat 2017-05-23 11:54:46

méthode la plus simple pour créer un certificat SSL

Open Firefox (je suppose que C'est aussi possible avec Chrome, mais c'est plus facile pour moi avec FF)

visitez votre site de développement avec un certificat SSL auto-signé.

cliquez sur le certificat (à côté du nom du site)

cliquez sur" plus d'information "

cliquez sur "Voir le certificat "

Cliquez sur" Détails "

cliquez sur " Exporter..."

choisissez " X. 509 Certificate whith chain (PEM)", sélectionnez le dossier et le nom pour le sauvegarder et cliquez sur" Enregistrer "

allez à la ligne de commande, dans le répertoire où vous avez téléchargé le fichier pem et exécutez "openssl x509-inform PEM-outform DM-in .pem-out .crt"

bien reçu .le fichier crt à la racine du dossier / sdcard à l'intérieur de votre appareil Android À l'intérieur de votre appareil Android, Paramètres > Sécurité > installer à partir du stockage.

Il doit détecter le certificat et vous permettre de l'ajouter à l'appareil Accédez à votre site de développement.

La première fois, il devrait vous demander de confirmer l'exception de sécurité. C'est tout.

le certificat doit fonctionner avec n'importe quel navigateur installé sur votre Android (navigateur, Chrome, Opera, Dolphin...)

rappelez-vous que si vous servez vos fichiers statiques à partir d'un domaine différent (nous sommes tous des salopes de vitesse de page) vous devez aussi ajouter le certificat pour ce domaine.

0
répondu Mani kandan 2017-07-27 07:31:56