/* Tibisay Movil Copyright (C) 2013 Antonio Araujo (aaraujo@cenditel.gob.ve), Jose Ruiz (jruiz@cenditel.gob.ve), Fundacion Centro Nacional de Desarrollo e Investigacion en Tecnologias Libres - CENDITEL. La Fundación CENDITEL concede permiso para usar, copiar, distribuir y/o modificar este programa, reconociendo el derecho que la humanidad posee al libre acceso al conocimiento, bajo los términos de la licencia de software GPL versión 2.0 de la Free Software Foundation. Este programa se distribuye con la esperanza de que sea util, pero SIN NINGUNA GARANTIA; tampoco las implicitas garantias de MERCANTILIDAD o ADECUACION A UN PROPOSITO PARTICULAR. Para mayor información sobre los términos de la licencia ver el archivo llamado "gpl-2.0.txt" en ingles. */ package ve.gob.cenditel.tibisaymovil; import java.io.BufferedInputStream; import java.io.File; import java.io.InputStream; import android.net.Uri; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.View.OnClickListener; import android.webkit.MimeTypeMap; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.io.*; import java.lang.reflect.Field; import com.lowagie.text.pdf.*; import ee.sk.digidoc.SignedDoc; import ee.sk.utils.ConvertUtils; import java.util.Calendar; import java.util.ArrayList; import java.util.Random; import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; public class PDFVerifyResultActivity extends Activity { private LinearLayout button_share; private LinearLayout button_finish; // ruta absoluta al archivo a verificar private String pdfToVerify; @Override protected void onCreate(Bundle savedInstanceState) { //Estilando la barra de titulo final boolean customTitleSupported = requestWindowFeature(Window.FEATURE_CUSTOM_TITLE); super.onCreate(savedInstanceState); setContentView(R.layout.activity_verify_result_pdf); //Estilando Barra de titulo if(customTitleSupported) getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.title_bar); // obtener el archivo pdf a verificar //Bundle bundle = getIntent().getExtras(); //pdfToVerify = bundle.getString("pdfToVerify"); final android.net.Uri data = getIntent().getData (); if (data != null) { Toast.makeText(getApplicationContext(), "data != null", Toast.LENGTH_SHORT).show(); // verificar el tipo de scheme String scheme = data.getScheme(); // verificacion de un archivo que esta en el dispositivo if (scheme.equals("file")) { Toast.makeText(getApplicationContext(), "file: "+data.getPath(), Toast.LENGTH_SHORT).show(); pdfToVerify = data.getPath(); } }else{ // obtener el archivo pdf a verificar Bundle bundle = getIntent().getExtras(); pdfToVerify = bundle.getString("pdfToVerify"); } TextView pdfName = (TextView) this.findViewById(R.id.filename_text); pdfName.setText(pdfToVerify); // ejecutar el proceso de verificacion del pdf doVerification(pdfToVerify); LinearLayout layoutPdfFileResult = (LinearLayout) this.findViewById(R.id.layout_pdf_signed_result); OnClickListener pdfFileListener = new OnClickListener() { public void onClick(View v) { //Toast.makeText(getApplicationContext(), "**CLICK SOBRE EL archivo***", Toast.LENGTH_LONG).show(); openIt(pdfToVerify, getMimeType(pdfToVerify)); } }; layoutPdfFileResult.setOnClickListener(pdfFileListener); // habilitar opciones de botones inferiores button_share = (LinearLayout) this.findViewById(R.id.button_remove_certificate_zone); button_finish = (LinearLayout) this.findViewById(R.id.button_add_certificate_zone); // habilita el click sobre la acción de finalizar la verificacion de firma y regresar button_finish.setOnClickListener(new OnClickListener() { public void onClick(View v) { Intent oIntent = new Intent(PDFVerifyResultActivity.this, TibisayMovilActivity.class); oIntent.setAction(Intent.ACTION_VIEW); oIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(oIntent); finish(); } }); // habilita el click sobre la acción de compartir el archivo button_share.setOnClickListener(new OnClickListener() { public void onClick(View v) { shareIt(); } }); } // fin de onCreate /** * Ejecuta la verificacion de la firma del pdf utilizando la biblioteca droidtext * * */ private void doVerification(String pdfToVerify) { try { Random rnd = new Random(); PdfReader reader = new PdfReader(pdfToVerify); Log.d("VerificadorPDF", "new PdfReader"); AcroFields af = reader.getAcroFields(); Log.d("VerificadorPDF", "reader.getAcroFields()"); ArrayList names = af.getSignatureNames(); Log.d("VerificadorPDF", "af.getSignatureNames()"); //Toast.makeText(getApplicationContext(), "names.size: "+ Integer.toString(names.size()), Toast.LENGTH_SHORT).show(); Log.d("VerificadorPDF", Integer.toString(names.size())); if (names.size() == 0) { // el archivo no posee firmas TextView signatureMessage = (TextView) this.findViewById(R.id.archivo_original_a_descifrar); signatureMessage.setText("El documento PDF no está firmado electrónicamente."); TextView labelSignature = (TextView) this.findViewById(R.id.label_archivo_original); labelSignature.setText("Documento:"); TextView labelSigners = (TextView) this.findViewById(R.id.label_destinatario_cifrado); labelSigners.setVisibility(View.GONE); ListView listViewSigners = (ListView) this.findViewById(R.id.signatures_list); listViewSigners.setVisibility(View.GONE); return; }else{ // el documento si posee firmas //KeyStore kall = PdfPKCS7.loadCacertsKeyStore(); // crear certificate factory CertificateFactory cf = CertificateFactory.getInstance("X.509"); // crear un KeyStore String keyStoreType = KeyStore.getDefaultType(); KeyStore kall = KeyStore.getInstance(keyStoreType); kall.load(null, null); // obtener vector de campos de /res/raw Field[] fields = R.raw.class.getFields(); InputStream caInput = null; // iterar sobre todos los certificados incluidos en /res/raw y cargarlos // en el KeyStore for (int l=0; l < fields.length; l++) { try { //Toast.makeText(getApplicationContext(), "PDFVerifyResultActivity - reading certificate: "+Integer.toString(l)+ " "+ // Integer.toString(fields[l].getInt(null)), Toast.LENGTH_SHORT).show(); caInput = new BufferedInputStream(getResources().openRawResource(fields[l].getInt(null))); } catch (IllegalArgumentException e) { Toast.makeText(getApplicationContext(), "PDFVerifyResultActivity: IllegalArgumentException "+e.getMessage(), Toast.LENGTH_SHORT).show(); break; } catch (IllegalAccessException e) { Toast.makeText(getApplicationContext(), "PDFVerifyResultActivity: IllegalAccessException "+e.getMessage(), Toast.LENGTH_SHORT).show(); break; } Certificate ca; try { ca = cf.generateCertificate(caInput); //Log.d("**ca:", ((X509Certificate) ca).getSubjectDN()); //Log.d("*** try: ca.toString()", ca.toString()); } finally { caInput.close(); } kall.setCertificateEntry("ca"+Integer.toString(l), ca); }// fin de la iteracion sobre /res/raw // se crea el adaptador para mostrar los firmantes del contenedor ListView signerListView = (ListView) findViewById(R.id.signatures_list); final ArrayList signers = new ArrayList(); boolean invalidSignature = false; for (int i = 0; i < names.size(); i++){ String name = (String)names.get(i); PdfPKCS7 pk = af.verifySignature(name); Calendar cal = pk.getSignDate(); Certificate pkc[] = pk.getCertificates(); X509Certificate cert = (X509Certificate) pk.getSigningCertificate(); String cn = cert.getSubjectDN().toString(); String signerName = ConvertUtils.getCommonName(cn); SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS"); String date = date_format.format(pk.getSignDate().getTime()); String certificateSerial = cert.getSerialNumber().toString(); String validFrom = cert.getNotBefore().toString(); String validUntil = cert.getNotAfter().toString(); String certificateIssuer = cert.getIssuerDN().toString(); Object fails[] = PdfPKCS7.verifyCertificates(pkc, kall, null, cal); if (fails == null) { System.out.print(pk.getSignName()); Toast.makeText(getApplicationContext(), "Firma Válida", Toast.LENGTH_SHORT).show(); } else { System.out.print("Firma no válida"); Toast.makeText(getApplicationContext(), "Firma NO Válida", Toast.LENGTH_SHORT).show(); invalidSignature = true; } // agregar el nombre comun del firmante y la fecha y la hora signers.add(new SignerFromPDF(signerName, cn, date, certificateSerial, validFrom, validUntil, certificateIssuer)); TextView signatureValidation = (TextView) this.findViewById(R.id.archivo_original_a_descifrar); if (invalidSignature){ signatureValidation.setText("Firma Inválida"); }else{ signatureValidation.setText("Firma Válida"); } } SignerFromPDFAdapter signerAdapter = new SignerFromPDFAdapter(PDFVerifyResultActivity.this, signers); signerListView.setAdapter(signerAdapter); signerListView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { //Toast.makeText(getApplicationContext(), "SE DEBE MOSTRAR INFORMACIÓN DEL FIRMANTE", Toast.LENGTH_SHORT).show(); showSignatureDetails(position, signers); } }); } // fin de else: el documento posee firmas }catch(Exception e){ Toast.makeText(getApplicationContext(), "Error al verificar pdf:"+e.getMessage(), Toast.LENGTH_LONG).show(); } } // funcion para compartir el documento private void shareIt() { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_SEND); File file = new File(pdfToVerify); Uri uri = Uri.fromFile(file); Log.i("DEBUG", file.getPath()); //Log.d("******", getMimeType(file.getPath())); //shareIntent.setDataAndType(uri, getMimeType(file.getPath())); shareIntent.putExtra(Intent.EXTRA_STREAM, uri); shareIntent.setType("application/*"); startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.share_it_using))); } // class que abstrae un firmante incluido en un contenedor BDOC private class SignerFromPDF { // nombre del firmante private String mName; // nombre comun del firmante private String mCN; // fecha y hora de la firma private String mDate; // serial del certificado private String mCertificateSerial; // fecha de validez inicial private String mValidFrom; // fecha de validez final private String mValidUntil; // emisor del certificado private String mCertificateIssuer; public SignerFromPDF(String name, String cn, String date, String serial, String validFrom, String validUntil, String issuer){ mName = name; mCN = cn; mDate = date; mCertificateSerial = serial; mValidFrom = validFrom; mValidUntil = validUntil; mCertificateIssuer = issuer; } public void setName(String name) { this.mName = name; } public String getName() { return mName; } public void setCN(String cn) { this.mCN = cn; } public String getCN() { return mCN; } public void setDate(String date) { this.mDate = date; } public String getDate() { return mDate; } public void setCertificateSerial(String certSerial) { this.mCertificateSerial = certSerial; } public String getCertificateSerial() { return mCertificateSerial; } public void setValidFrom(String validFrom) { this.mValidFrom = validFrom; } public String getValidFrom() { return mValidFrom; } public void setValidUntil(String validUntil) { this.mValidUntil = validUntil; } public String getValidUntil() { return mValidUntil; } public void setCertificateIssuer(String certIssuer) { this.mCertificateIssuer = certIssuer; } public String getCertificateIssuer() { return mCertificateIssuer; } } // fin de clase SignerFromPDF // clase que abstrae el adaptador para llenar el ListView de documentos que // se encuentran dentro del contenedor BDOC private class SignerFromPDFAdapter extends BaseAdapter { private ArrayList mSignerFromPDFList; private LayoutInflater lInflater; private SignerFromPDFAdapter(Context context, ArrayList signers) { this.lInflater = LayoutInflater.from(context); this.mSignerFromPDFList = signers; } @Override public int getCount() { return mSignerFromPDFList.size(); } @Override public Object getItem(int position) { return mSignerFromPDFList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder container = null; if (convertView == null){ container = new ViewHolder(); convertView = lInflater.inflate(R.layout.signer_inside_bdoc_item, null); container.signer_text = (TextView) convertView.findViewById(R.id.signer_info); container.signer_modified = (TextView) convertView.findViewById(R.id.signature_errors); container.type_image = (ImageView) convertView.findViewById(R.id.type_image); convertView.setTag(container); }else{ container = (ViewHolder) convertView.getTag(); } SignerFromPDF doc = (SignerFromPDF) getItem(position); container.signer_text.setText(doc.getName()); container.signer_modified.setText(doc.getName()); container.type_image.setImageResource(R.drawable.ic_firmar_verde); return convertView; } class ViewHolder{ TextView signer_text; TextView signer_modified; ImageView type_image; } } /** * Lanza la actividad para mostrar detalles de un firmante * * */ private void showSignatureDetails(int position, ArrayList signers) { Log.d("**showSignatureDetails", Integer.toString(position)); Log.d("** nombre", signers.get(position).getName()); Intent intent = new Intent(this, ActivitySignerInfo.class); intent.putExtra("name", signers.get(position).getName()); intent.putExtra("cn", signers.get(position).getCN()); intent.putExtra("date", signers.get(position).getDate()); intent.putExtra("certificateSerial", signers.get(position).getCertificateSerial()); intent.putExtra("validFrom", signers.get(position).getValidFrom()); intent.putExtra("validUntil", signers.get(position).getValidUntil()); intent.putExtra("certificateIssuer", signers.get(position).getCertificateIssuer()); startActivity(intent); } // funcion para obtener el tipo mime de un archivo public static String getMimeType(String url) { String extension = url.substring(url.lastIndexOf(".")); String mimeTypeMap = MimeTypeMap.getFileExtensionFromUrl(extension); String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(mimeTypeMap); return mimeType; } // funcion para lanzar un intent que abra un archivo private void openIt(String pdfFile, String mimeType) { Intent shareIntent = new Intent(); shareIntent.setAction(Intent.ACTION_VIEW); File file = new File(pdfFile); Uri uri = Uri.fromFile(file); Log.i("DEBUG", file.getPath()); shareIntent.setDataAndType(uri, mimeType); startActivity(Intent.createChooser(shareIntent, getResources().getText(R.string.open_it_using))); } }