sábado 28 de marzo de 2009

Cómo usar el DNI electrónico (1/2)

Aunque esto no tiene que ver totalmente con la temática del blog considero que es interesante igualmente, así que vamos a hablar del relativamente reciente DNIe, cómo prepararnos para usarlo y ver qué ventajas nos aporta. Lo dividiré en dos entradas para que no me ocupen mucho. Esta será teórica, para comprender grosso modo qué es el DNIe y cómo funciona. La segunda entrada cubre la instalación y configuración de un lector y los navegadores para poder usar el DNIe, y está disponible aquí.


Introducción

El DNIe tiene la misma función que el DNI tradicional, servir como documento acreditativo de la identidad del titular. La novedad es que ahora lo podremos utilizar para acreditar nuestra identidad en el mundo digital, por medio de un certificado digital.

Esto nos permitirá, entre otras cosas, acceder a servicios o realizar trámites con la Administración pública desde casa, evitando desplazamientos y esperas, o la firma digital de documentos, emails, etc, que adquieren la misma validez legal que una firma manuscrita.

Toda la información del DNIe está disponible en su portal oficial.


Características del DNIe


El nuevo DNI tiene el tamaño de cualquier tarjeta de crédito actual, y contiene los datos identificativos de siempre. La novedad es el nuevo chip que incorpora que contiene la siguiente información, copiada vilmente del portal oficial:


  1. Un certificado digital para autenticar la identidad del ciudadano.
  2. Un certificado digital para firmar digitalmente, con la misma validez jurídica que la firma manuscrita.
  3. Certificado de la Autoridad de Certificación emisora.
  4. Claves –pública y privada- para la firma digital.
  5. La plantilla biométrica de la impresión dactilar.
  6. La fotografía digitalizada del ciudadano.
  7. La imagen digitalizada de la firma manuscrita.
  8. Datos de la filiación del ciudadano, correspondientes con el contenido personalizado en la tarjeta.

Funcionamiento del DNIe


Para conocer mejor el funcionamiento del DNIe, hay que dejar claros algunos conceptos. (Los números en paréntesis referencian las características enumeradas anteriormente)

  • Autoridad Certificadora (AC)

Es la autoridad encargada de emitir certificados digitales.

En el caso de los certificados de Autenticación(1) y Firma(2) incluidos en el DNIe, sólo la Dirección General de la Policía y la Guardia Civil tiene la potestad de emitirlos. Es decir, que son los únicos que pueden crear un DNIe.

No hay que olvidar que existen otras entidades que también pueden emitir otros certificados al margen de los incluidos en el DNIe que también son válidos para trámites telemáticos en España, como la Fábrica de Moneda y Timbre, por ejemplo.

Los certificados son únicos para cada individuo y se generan en el momento en que te entregan el DNIe, un proceso largo por cierto. Si no te gustan los silencios incómodos, tus habilidades de hablar de temas triviales se pondrán al límite cuando estés enfrente del funcionario y tengas que esperar a que estos se creen...

Los certificados se encuentran guardados en el chip del DNIe y sólo se puede acceder a ellos por medio de un PIN (que debería llamarse password) ya que no es un número sino una secuencia de caracteres. Éste se entrega junto al DNIe en un sobre cerrado y es necesario para realizar cualquier consulta de la información que contiene el DNIe, desde los personales (8), hasta los certificados. Dicho de otro modo, cada vez que quieras consultar los datos de tu DNIe o realizar algún tipo de operación con él, deberás introducir el PIN.

Por cierto, si introduces tres veces consecutivas el PIN, el DNIe se bloquea, y deberás ir a un Punto de Actualización del DNIe -que debería estar disponible donde te lo entregaron- para poder desbloquearlo usando la huella dactilar. Cabe destacar que la plantilla biométrica de la huella dactilar (8) no puede ser consultada, sino que es el propio DNIe el encargado de validar una plantilla que se le proporcione de forma externa (es decir, la plantilla leída desde el lector del puesto) con la que el propio DNIe guarda, y aceptarla como válida o no.


  • Autoridad Validadora (AV)

Estas entidades validan que un certificados emitido es vigente, por ejemplo, que realmente está generado por la Autoridad Certificadora indicada, o que bien este certificado no ha expirado.

Para nuestro caso las autoridades validadoras más importantes serán la Fábrica Nacional de Moneda y Timbre, que presta servicios de validación de forma universal (ciudadanos, empresas y Admon. Pública), el Ministerio de Administraciones Públicas, que presta los servicios de validación a la Administración, y el Ministerio de Industria, Turismo y Comercio, que los presta a empresas, por ejemplo para generar facturas electrónicas firmadas digitalmente.


  • Firma electrónica

La firma electrónica se realiza utilizando criptografía de clave asimétrica. Resumiendo mucho el procedimiento, esta técnica se basa en el uso de de dos claves relacionadas, de forma que están vinculadas entre si de forma única.

    • Clave privada: como su nombre indica es personal e intransferible, Con ella efectuaremos la firma de un documento y en ese momento será como si hubiéramos firmado éste de forma manuscrita. Por eso es importante que esta clave privada permanezca en secreto, ya que si alguien más la tuviera podría firmar documentos con nuestra identidad.
    • Clave pública: esta clave ha de distribuirse a los destinatarios de los documentos y servirá para comprobar que el documento pertenece realmente a la persona que lo firmó con su clave privada. Cada clave pública está vinculada a una, y sólo a una, clave privada.

Se puede establecer una analogía simple pensado en una caja fuerte con dos tipos de llaves. Una de ellas, la llave privada, permite a su usuario abrir la caja fuerte e introducir algo, y además tiene la particularidad de que sólo existe una copia. Por el contrario de la otra llave, la llave pública, tenemos un montón de copias que repartimos entre conocidos, pero ésta sólo permite recuperar lo que hay dentro de la caja, sin posibilidad de introducir algo -supongamos que la sofisticada caja fuerte simplemente expulsa el contenido como si fuera una máquina expendedora. Sí sólo existe una llave privada y nos pertenece, cualquier persona que tenga una llave pública tendrá la certeza de que lo que se encuentre dentro de ella sólo ha podido ser introducido por el propietario de la llave privada.

 

Una vez dejado claras estos términos, se puede explicar cómo funciona todo esto para poder asegurar nuestra identidad. Bien, supongamos que tenemos un cliente (nosotros), y una entidad que proporciona un servicio que necesitamos pero que para proporcionarlo es necesario estar completamente seguros de que la persona que lo solicita es quien dice ser (*). El procedimiento sería el siguiente:

  • Utilizando una conexión segura SSL para conectarnos a la web de la entidad (la forma más fácil de identificarlo es porque la dirección de la página web comienza por https, en vez del habitual http) y solicitamos una conexión con autenticación.
  • La entidad crea un mensaje autenticado por medio de un certificado y nos lo envía. Utilizando una Autoridad Validadora nos aseguramos de que el certificado es válido.
  • El servicio nos envía un mensaje de inicio de sesión cifrado que procederemos a descifrar por medio de la clave pública incluida en el certificado.
  • Una vez validado el mensaje de inicio de sesión en el paso anterior, utilizamos nuestra clave privada del DNIe para cifrar un mensaje de establecimiento de sesión, y enviarlo junto a nuestro certificado de autenticación. Como en este momento tenemos que acceder a los datos del DNIe, este debe estar insertado en el lector y nos pedirá el PIN.
  • La entidad verifica que el mensaje de establecimiento de sesión es correcto desencriptándolo con la clave pública, y se asegura de que nuestro certificado de autenticación es válido.
  • Como hemos verificado que ambos (cliente y entidad) somos quien decimos ser, se establece la conexión segura y autenticada. A partir de este momento podemos acceder a los servicios.
  •  

Servicios Disponibles con el DNIe

Aquí no me voy a complicar de forma exagerada y sólo comentaré algunos servicios que me han parecido interesantes. Para la lista completa (y larga) os remito al listado del portal oficial.

Solicitar la prestación por desempleo, o consulta de la situación personal de prestación por desempleo.

La Agencia tributaria nos permite hacer la declaración de la renta o pagar nuestros impuestos sin esperar colas ni perder tiempo.

Correos nos proporciona una dirección de correo electrónico segura de forma gratuita

También hay una lista de entidades privadas (bancos y una aseguradoras concretamente) que utilizan el DNIe para algunos trámites.

Algunos ayuntamientos proporcionan servicios más concretos. En mi caso tengo suerte y el ayuntamiento de Gijón es uno de ellos. Aunque no he conseguido que funcione con el DNIe :(

 

En la próxima entrada veremos cómo instalar todo lo necesario para utilizar el DNIe en Windows y Mac con Firefox e Internet Explorer.

martes 24 de marzo de 2009

Nocturnal Initiative: Smart Pointer (II)

Ya ha pasado mucho tiempo desde la última entrada, y ya no te quiero ni contar desde la entrada que precede a esta. Llevo sin escribir en el blog por mezcla de mi dejadez aderezado con ciertos cambios en mi vida laboral. Así que retomo la escritura para completar esta mini-serie iniciada ya hace casi un año, algo que no tiene excusa alguna porque lo que quedaba por explicar era muy sencillo.

Recapitulemos, en nocturnal teníamos un interface IRefCount que definía tres operaciones para contar las referencias a un objeto:

  • IncrRefCount() Incrementa en uno el contador de referencias.
  • DecrRefCount() Decrementa en uno el contador de referencias.
  • GetRefCount() Devuelve el número de referencias del objeto.

A su vez teníamos disponible las clases RefCountBase y RefCountAggregator, que implementan dicho interface.

Pues ahora hablaremos de la clase SmartPtr<T> una clase que tiene como fin comportarse exactamente igual que un puntero, pero gestionando automáticamente el ciclo de vida de un objeto según el número de referencias que tenga. Esto significa que, dada una instancia de un objeto en memoria, este se borrará automáticamente cuando ningún otro SmartPtr lo referencie.

Todo esto funciona siempre que T sea un tipo que implementa IRefCount, por tanto utilizará los tres métodos definidos en dicho interface para gestionar las cuenta de las referencias. Si no es así el código ni compilará. Y aunque no es obligatorio para que el código compile, si que es necesario para que todo funcione que sólo utilizaremos un tipo de puntero SmartPtr para gestionar los objetos: si mezclamos punteros “tradicionales” con smart pointers armaremos un cisco épico con toda probabilidad.

Por supuesto que implemente IRefCount es sólo parte del trabajo, ya que un interface por si sólo no incluye el código necesario para gestionar las referencias. Por ello, y suponiendo que no queremos reinventar la rueda, lo mejor será que cualquier objeto que pretendamos utilizar con un SmartPtr derive de RefCountBase, con lo que en la práctica se convertirá en la clase base de toda nuestra jerarquía de objetos.

Pero ¿cómo funciona SmartPtr internamente? Pues haciendo uso tanto de conversiones implícitas en los constructores como de sobrecarga de operadores para simular el comportamiento de un puntero a la par que actualizas la cuenta de referencias.

El contador de referencias se inicializa a 1 al asignar por primera vez un puntero válido a un SmartPtr, y se va actualizando con cada operación de asignación –decrementando la referencia del SmartPtr sobreescrito e incrementando la del asignado, o cuando el objeto SmartPtr es destruido, momento en el que decrementamos en uno el contador de referencias.

Menudo lío, veamos algo de código:

Empezamos con una clase sencilla de prueba

//Clase simple que deriva de BaseRefCount para
//implementar el contador de referencias
class MyClass : BaseRefCount {};

Creamos un par de SmartPtr que apuntan a instancias diferentes de MyClass

//ptr2MyClass1: Contador de referencia a 1
//apunta a la instancia 1 de MyClass
SmartPtr< MyClass > ptr2MyClass1 = new MyClass();
//ptr2MyClass2: Contador de referencia a 1
//apunta a la instancia 2 de MyClass
SmartPtr< MyClass > ptr2MyClass2 = new MyClass();

Ahora mismo ptr2MyClass1 != ptr2MyClass2 ya que apuntan a instancias de objetos distintas.


Sin embargo con una "simple" asignación vamos a ver que ocurren varias cosas:

ptr2MyClass2 = ptr2MyClass1;

ptr2MyClass2 está siendo sobreescrito, con lo que decrementamos su contador de referencias. Como era 1, ahora pasa a ser 0, por tanto como ningún puntero referencia la instancia, hemos de borrar dicha instancia, y así lo hacemos, o mejor dicho, así se hace automáticamente. Por otro lado al asignarle el puntero ptr2MyClass1, lo que estamos estamos diciendo es que ptr2MyClass2 apunte a la misma instancia que ptr2MyClass1, que es la instancia 1 Eso implica que ahora tenemos DOS referencias a la misma instancia, por lo que incrementamos el contador de referencia que pasa a ser 2.

Ahora mismo ptr2MyClass1 == ptr2MyClass2: ambos apuntan a la misma instancia en memoria. Vamos a asignar un puntero nulo:

ptr2MyClass2 = 0;

Como estamos asignando una referencia nula, lo que haremos será decrementar el contador de referencias, con lo que pasa a ser 1.

Por último, imaginemos que ptr2MyClass1, que es el único SmartPtr que apunta a la instancia 1 sale del ámbito actual en el que ha sido declarado, algo como esto:

{
    SmartPtr< MyClass > ptr2MyClass1 = new MyClass();
} 
//Aquí salimos de ámbito, por lo que llamamos al 
//destructor definido para ptr2MyClass1

Pues bien, como al salir de ámbito su destructor es invocado el contador de referencias es decrementado de nuevo. Como éste era 1, pasa a ser 0, y por tanto la instancia es borrada automáticamente.


Como vemos estamos trabajando con punteros sin necesidad de gestionar la memoria y sin crear fugas de memoria.


Pero mucho ojo, ¡porque esto no es válido para semánticas de punteros como arrays!

Por ejemplo este código compila, pero genera fugas de memoria:

SmartPtr< MyClass >* myClassArray = new SmartPtr< MyClass > [2];
myClassArray[0] = new MyClass();
myClassArray[1] = new MyClass();

Eso es debido a que al destruir el puntero myClassArray, no iteramos por cada uno de sus elementos para destruir los objetos que almacena. En estos casos lo más cómodo es utilizar la clase vector de stl, que al destruir un vector si llama al destructor de cada uno de los elementos que almacena:

vector< SmartPtr > myClassArray = vector< SmartPtr< MyClass > > (2);
myClassArray[0] = new MyClass();
myClassArray[1] = new MyClass();

Y ya tenemos arrays que almacenan punteros sin fugas de memoria y auto-gestionados

Como nota final, en la última versión del NocturnalFramework, que ya salió hace algún tiempo la clases necesarias para utilizar SmartPtr se encuentran en el directorio Common/Memory. Si queréis trastear con ella tened en cuenta que hay referencias a ficheros que se encuentran dentro del directorio Common, por lo que lo más cómodo es copiar la carpeta Common completa a vuestro proyecto.