Story Transcript
RESUMEN DEL PROYECTO: Este proyecto gira alrededor de la Tarjeta Inteligente GPK y sus funcionalidades, entre las que se encuentran: Firma digital con clave RSA, cálculo de Hash (SHA1, MD5), generador de números aleatorios, base de datos protegida ante lecturas y escrituras no autorizadas... En concreto este proyecto trata de la generación de una librería de alto nivel para la utilización de la Tarjeta Inteligente GPK y de la implementación de una aplicación para probar el correcto funcionamiento de la librería. La implementación tanto de la librería como de la aplicación, se realizara en C++. INDICE Parte Teórica 1 1. Introducción 2 1.1 De qué trata este proyecto 2 1.2 Qué se va a explicar aquí 3 2. Las Tarjetas. Características generales 4 2.1. ¿Qué son? 4 2.2. Tipos de Tarjetas con Circuito Integrado 4 2.2.1. Tarjetas de memoria 5 2.2.2. Tarjetas de memoria con circuito de seguridad 5 2.2.3. Tarjetas Inteligentes 6 3. Las Tarjetas Inteligentes 8 3.1. El Sistema Operativo 8 3.1.1. ¿Qué es? 8 3.1.2. Estructura de la memoria EEPROM y RAM 9 3.1.3. El Sistema de Ficheros 10 3.1.3.1. Fichero Maestro o MF 12 3.1.3.2. Fichero Dedicado o DF 12 3.1.3.3. Fichero Elemental o EF 13 3.1.3.3.1. Estructuras de los Ficheros Elementales 13
1
• Estructura transparente 13 • Estructura lineal fija 14 • Estructura lineal variable 14 • Estructura cíclica 15 3.1.3.3.2. Tipos de Ficheros Elementales 16 • Ficheros del sistema 16 • Ficheros ejecutables 16 • Ficheros del usuario 18 • Ficheros proporcionados por la Tarjeta 18 3.1.3.3.3. Atributos de los Ficheros Elementales 18 • Atributo de lectura múltiple 18 • Atributo de escritura múltiple 19 • Atributo de corrección de errores 19 3.1.3.4. Identificación de los ficheros 19 3.1.3.5. Direccionamiento de los ficheros 20 3.1.3.5.1. Seleccionar el Fichero Maestro 20 3.1.3.5.2. Seleccionar un Fichero Dedicado 21 3.1.3.5.3. Seleccionar un Fichero Elemental 21 3.1.3.5.4. Ejemplo gráfico sobre la selección de ficheros 22 3.1.3.6. Control de acceso en los ficheros 22 3.1.4. Tipos de Tarjetas Inteligentes 23 3.2. La comunicación entre la Tarjeta y el lector 25 3.2.1. Protocolo de comunicación 26 3.2.1.1. Protocolo T = 0 28 3.2.1.2. Protocolo T = 1 29 3.3. Seguridad en la Tarjeta Inteligente 30 3.3.1. Seguridad física 30 3.3.2. Seguridad lógica 31 3.3.3. Criptografía en la Tarjeta Inteligente 32 3.4. La Tarjeta Inteligente GPK 8000 33
2
Parte Práctica 35 • Introducción 36 • Características de la librería 36 • Paquete de desarrollo 37 • Instalación de las librerías y del lector 38 • Recomendaciones 40 • Dificultades en el desarrollo 42 • Interfaz de la librería 44 • Variables Públicas 44 • C_TarIn 46 • ~C_TanIn 46 • Conectar ( 2 métodos ) 47 • Desconectar 50 • SeleccionarMF 51 • SeleccionarDF ( 2 métodos ) 52 • SeleccionarEF 55 • CrearDF 56 • CrearEFsc 58 • CargarCodigoSecreto 62 • VerificarCodigoSecreto 64 • CambiarCodigoSecreto 66 • DesbloquearCodigoSecreto 68 • CrearEFDatos 70 • ActualizarEFDatos 73 • LeerEFDatos 75 • CrearEFRSA 77 • CargarPartePublicaRSA 80 • LeerPartePublicaRSA 82 • CargarPartePrivadaRSA ( 2 métodos ) 84 • GenerarClaveRSA 91 • FirmaDelDocumento 93 • VerificarFirma 96 • CalcularHash 99 • CifrarDatosConPrivada 102 • LongitudEF 104 • BloquearGrupoDeAccesoEF 106 • GenerarNumeroAleatorio 108 • BorrarTarjeta 109 • Errores de esta librería 110 • Programas de ejemplo 112 Bibliografía 116
TEMA 1. Introducción.
3
1.1. De qué trata este proyecto. E ste proyecto gira alrededor de la Tarjeta Inteligente GPK 8000 y de las características que ofrece, tales como: una base de datos protegida contra usos desautorizados, almacén para claves DES, 3DES, RSA y códigos secretos, generación de números aleatorios, cálculos de Hash (MD5 y SHA−1) y creación y verificación de firmas digitales. Sus características son pocas, pero importantes, pero también hay que tener en cuenta, que las Tarjetas Inteligentes, no conforman ellas solas, un sistema de seguridad, sino que son una pieza más, de la maquinaria (aunque ellas internamente, tengan su propio sistema de seguridad). Podría decirse, que es la segunda pieza más importante del sistema, porque es la encargada de custodiar las claves, que el sistema usará, para proporcionar un entorno seguro. Por supuesto el usuario, sería el componente más importante, de todo el sistema. En concreto este proyecto, trata de la generación de una librería de alto nivel para la utilización de la Tarjeta Inteligente GPK 8000 y de la implementación de una aplicación para probar el correcto funcionamiento de la librería. Esta librería se llama TarIn y viene de Tarjeta Inteligente y la aplicación desarrollada, es una chat seguro, con una transferencia de archivos entre usuarios también segura. El propósito de esta librería de alto nivel, es la de: proporcionar en la medida de lo posible, una forma cómoda y sencilla de usar la Tarjeta Inteligente, reduciendo al mínimo los conocimientos necesarios para utilizarla. Esto implica, que en la fase de desarrollo de la librería, tuviera que tomar decisiones, que externamente servirían para crear una interfaz fácil, pero internamente, producirían un desperdicio de recursos. 1.2. Qué se va a explicar aquí. E l proyecto está dividido en tres partes: teoría, práctica y la bibliografía. En la parte teórica, se podrá encontrar el funcionamiento interno de las Tarjetas Inteligentes, el protocolo de comunicación y los sistemas de seguridad que incorpora. No se profundizará mucho en esta parte, pero sí que se darán datos más que suficientes, para entender y comprender la filosofía de las Tarjetas Inteligentes y por consiguiente, la comprensión de la interfaz de la librería, que es la parte más importante de este proyecto. Y en la parte práctica, se encontrará información sobre el desarrollo de la librería, su instalación y recomendaciones de uso. También se explicarán uno a uno, todos los métodos de la librería TarIn, sus códigos de error y en la medida de lo posible, su interoperatividad con otros métodos de la misma librería. Además de unos ejemplos, que facilitaran en lo posible, el uso de la interfaz.
TEMA 2. Las Tarjetas. Características generales. 2.1. ¿Qué son? L as Tarjetas son principalmente bases de datos y dependiendo del tipo de Tarjeta, se tendrá más o menos control, sobre el acceso a los datos. Básicamente existen dos tipos de Tarjetas: las Tarjetas con circuito integrado (Integrated Circuit Card o ICC) o con bandas magnéticas (también existen las híbridas que tienen ambos sistemas). Comparando, ambos sistema, quedan muy por encima, el sistema con circuito integrado, ya que, presenta las siguientes ventajas: 4
• Son capaces de almacenar mucha más información. • Pueden proteger la información que almacenan, ante accesos no autorizados. • Poseen una gran resistencia al deterioro de la información almacenada. • Incluso el coste, a medio plazo es menor. En el siguiente punto veremos las diferentes Tarjetas que existen con circuito integrado. 2.2. Tipos de Tarjetas con circuito integrado. N ormalmente, se suele tener el error de llamar Tarjeta Inteligente a toda Tarjeta que posee contactos, pero a priori no sabemos su construcción interna para poder decir tal afirmación, ya que dependiendo de ello, la Tarjeta será Inteligente, de memoria con circuito de seguridad o de memoria solo. 2.2.1. Tarjetas de memoria. Figura 2.1. Diagrama de bloques de la arquitectura de una Tarjeta de memoria. Los accesos a la EEPROM no están controlados, por lo que las acciones de escribir y leer no tienen ningún tipo de prohibición. La aplicación típica de esta Tarjeta, sería las Tarjetas de pago en cabinas de teléfonos. 2.2.2. Tarjetas de memoria con circuitos de seguridad. Figura 3.2. Diagrama de bloques de la arquitectura de una Tarjeta de memoria con circuito de seguridad. El circuito de seguridad controla los accesos a la EEPROM, por lo que el acceso a ella, sólo será permitido a los usuarios autorizados. Este sistema suele utilizar un código de acceso de 64 bits o más. 2.2.3. Tarjetas Inteligentes. Figura 3.3. Arquitectura típica de una Tarjeta con microprocesador. Estas Tarjetas, poseen en su chip un microprocesador, que tiene unos elementos adicionales: • ROM. • EEPROM. • RAM. • Puerto de entrada/salida. La ROM, contiene el Sistema Operativo (SO) de la Tarjeta y se graba durante el proceso de fabricación. Esta memoria es inaccesible desde el exterior. La EEPROM, es el disco duro de la Tarjeta. Aquí se podrán almacenar: datos de las aplicaciones del usuario, datos de las aplicaciones del sistema y datos del usuario, tales como: nombre, apellidos, teléfono, dirección, etc. 5
La RAM, es la memoria donde el microprocesador realiza sus operaciones. El puerto de entrada y salida, normalmente consisten en un simple registro. Este proyecto, se basa en la utilización de este tipo de Tarjeta, porque son las más versátiles de todas las Tarjetas (es como tener un ordenador en la palma de una mano). En el mercado se pueden encontrar muchas configuraciones para este tipo de Tarjetas. Algunos de los posibles elementos que pueden tener, son: • Servicios criptográficos: algoritmos Hash, firmas digitales, generación de claves RSA, intercambio de claves de sesión... • Servicios de autenticación: De usuario ante la Tarjeta, de la aplicación ante la Tarjeta, entre entidades remotas, interna... • Tarjetas multiaplicación, permite utilizar una misma Tarjeta para aplicaciones diferentes, almacenando los datos necesarios para cada aplicación dentro de la Tarjeta. • Almacenamiento seguro de datos sensibles, tales como claves de: aplicación, RSA, DES, 3DES, PIN... Los servicios de criptografía y de autenticación, son proporcionados añadiendo un coprocesador al microprocesador. En el siguiente tema, se profundizará mucha más en las Tarjetas Inteligentes.
Tema 3. Las Tarjetas Inteligentes. Como ya vimos en el tema anterior, las Tarjetas de este tipo, son las más versátiles, flexibles y que proporcionan mayor seguridad. En este tema, sé vera el Sistema Operativo que las controla y su sistema de ficheros. Cómo se comunica con el mundo exterior, qué mecanismos tienen para impedir su manipulación fraudulenta y qué servicios de seguridad ofrecen a los usuarios. 3.1. El Sistema Operativo (SO). 3.1.1. ¿Qué es? E s el programa que provee una interfaz entre el hardware y el usuario de la Tarjeta. El SO es grabado en la ROM en la fase de fabricación de la Tarjeta y no puede ser ni actualizado ni cambiado, por este motivo y por tener que administrar y proteger datos confidenciales, tiene que ser muy fiable y robusto. Otra característica importante del SO, es que no permite el acceso desautorizado a los datos almacenados en la Tarjeta Inteligente, utilizando puertas traseras en el sistema. Esto es: no permite ni al propio fabricante, poder acceder a los datos a los que no este autorizado. Las funciones del SO son:
6
• Control en la transmisión de datos desde y hacia la Tarjeta. • Control de la ejecución de los programas. • Administración de la base de datos (acceso, lectura, escritura...). • Manejo y administración de algoritmos criptográficos. Aunque en la especificación ISO7816−4, se describe el funcionamiento del SO, los fabricantes aun crean sus propias versiones, por eso, no se deberá tomar la siguiente documentación al pie de la letra, ya que dependiendo del fabricante y de la Tarjeta, variará el funcionamiento y la estructura del Sistema Operativo. 3.1.2. Estructura de la memoria EEPROM y RAM. L a memoria EEPROM, es el disco duro de la Tarjeta. En los Sistemas Operativos modernos, su división es la siguiente: Figura 3.1. Ejemplo de división de la EEPROM. Primero, están almacenados algunos datos de producción que pueden ser números fijos, y por lo tanto no varían, y se utilizan para funciones específicas. Esta zona suele estar protegida frente a accesos no autorizados por algún mecanismo hardware. Esta zona habitualmente es de 32 bytes. Después de esta zona, están las tablas y los punteros del sistema. Estos se graban durante la fase de fabricación y en conjunto, con el programa de la ROM, forman el Sistema Operativo. Para asegurar que el sistema funciona perfectamente, esta sección de la EEPROM está protegida con un checksum, que es calculado antes de cada acceso a esta zona. Si se encuentra algún error en la comparación, el Sistema Operativo dejará de usar esta zona de memoria. A la sección de memoria anterior, le sigue otra que contiene los códigos de las aplicaciones adicionales del sistema. En algunos casos esta zona, está protegida frente a posibles alteraciones mediante el uso de un checksum. Los datos contenidos también pueden ser algoritmos que no están almacenados en la ROM por falta de espacio. Al final de la memoria EEPROM, esta la zona que contiene la estructura de ficheros. Esta zona no está protegida por ningún mecanismo pero generalmente existen módulos hardware o software orientados a proteger ficheros. En esta zona es donde el usuario podrá grabar sus aplicaciones y sus datos. El tiempo de escritura en la EEPROM es alto y varia entre una y otra marca (dato orientativo 1msg/byte). La RAM, es la memoria donde el microprocesador realiza sus operaciones. En casos de necesidad, el SO puede utilizar parte de la EEPROM como RAM, con la desventaja de que la escritura será mucha más lenta. Figura 3.2. Ejemplo de la división de la RAM. 3.1.3. El Sistema de Ficheros. L as Tarjetas actuales, incluyen auténticos sistemas de administración de ficheros que siguen una estructura jerárquica. Estos programas están muy minimizados para reducir el uso de memoria. Los Sistemas Operativos más recientes, están orientados a trabajar con objetos, esto quiere decir, que todos los datos referentes a un fichero, están contenidos en él mismo. Los ficheros están divididos en dos secciones 7
distintas: la primera es la cabecera y contiene datos referentes a la estructura del fichero y a las condiciones de acceso del mismo. La otra sección es el cuerpo del fichero, que contiene los datos útiles. Figura 3.3. Estructura interna del sistema de ficheros de una Tarjeta Inteligente. Otra consecuencia de funcionar orientados a objetos, es que para efectuar cambios en el contenido de un fichero, éste debe ser primero seleccionado con la correspondiente instrucción. Esta estructura está especificada en el ISO/IEC 7816−4 y es similar a los sistemas DOS o UNIX. Se tiene un directorio raíz (en DOS c:\) y a partir de el cuelgan los ficheros y directorios restantes. En las Tarjetas, tanto el directorio raíz con los demás directorios, son tratados como ficheros especiales, así, el directorio raíz es llamado Fichero Maestro o MF (Master File), los directorios, Ficheros Dedicados o DFs (Dedicated Files) y los ficheros normales se llaman Ficheros Elementales o EFs (Elementary Files). De estos últimos, podemos diferenciar los EF del sistema y los del usuario. Es bastante habitual guardar todos los datos referentes a una determinada aplicación con un mismo Directorio (Fichero Dedicado). Con esto se consiguen unas estructuras más claras y organizadas, si el usuario desea aumentar el número de aplicaciones de su Tarjeta, bastará con crear un nuevo Directorio (DF) que contenga los nuevos datos. Si la Tarjeta se usa para una sola aplicación, los datos del usuario pueden estar contenidos simplemente en el Fichero Maestro (Directorio Raíz). Figura 3.4. Diferencias en la organización de los datos. El diagrama de la izquierda y el centro, corresponden a ejemplos típicos de Tarjetas de una sola aplicación y el de la derecha a Tarjetas de varias aplicaciones. 3.1.3.1. Fichero Maestro o MF (Directorio raíz). Es el directorio raíz y es seleccionado automáticamente después de iniciar la Tarjeta. En él están contenidos todos los directorios y ficheros. El Fichero Maestro representa a toda la memoria disponible de la Tarjeta para almacenar datos. Solo existe uno en la Tarjeta. 3.1.3.2. Fichero Dedicado o DF (Directorio normal). Son directorios normales, usados para tener estructuras de ficheros más claras y organizadas. Según el SO de la Tarjeta, estará permitido el anidar o no directorios. Cuando el anidamiento esta permitido, estará restringido por la capacidad de la memoria. 3.1.3.3. Fichero Elemental o EF (Ficheros normales). Hay diferentes tipos y estructuras variadas para este tipo de fichero. Algunos tipos no tendrán una estructura interpretable por la Tarjeta, otros podrán tener diferentes estructuras y otros sólo podrán tener una sola estructura. 3.1.3.3.1. Estructuras de los Ficheros Elementales. Aquí, se explicará algunas de las diferentes estructuras internas, que pueden tener los Ficheros Elementales. • Estructura transparente. Estos ficheros no poseen ningún tipo de estructura y los datos se pueden leer o escribir byte a byte, por medio de un puntero que se desplaza a través del mismo. 8
El tamaño mínimo que pueden tener es de 1 byte, mientras que el máximo no está especificado. Figura 3.5. Estructura de un fichero transparente. • Estructura lineal fija. Esta estructura está basada en una serie de celdas de igual longitud, que están unidas en forma de matriz. La unidad más pequeña a la que se tiene acceso es de una celda, y no se puede acceder a fracciones de la misma. A la primera celda se le identifica con el número 01h mientras que el número más alto permitido es FEh, estando FFh reservado para usos futuros. El tamaño de cada celda puede variar entre 1 y 254 bytes, siendo las celdas de una misma matriz del mismo tamaño. Figura 3.6. Estructura de un fichero lineal fijo. • Estructura lineal variable. Debido a las restricciones de espacio de memoria y como los datos almacenados en las celdas pueden tener una longitud variable, fue creado este nuevo tipo de estructura, que es útil para optimizar el uso de la memoria. Cada celda puede tener un tamaño variable, en función de los datos que se almacenen en ella. El tipo de numeración y el tamaño de cada celda son exactamente iguales que en el caso anterior. Figura 3.7. Estructura de un fichero lineal variable. • Estructura cíclica. Esta estructura de datos está basada en un fichero lineal fijo. En este caso existe un puntero que indica cuál fue el último conjunto de datos al que se accedió. Una vez que el puntero llega a la última celda, éste es puesto, por el Sistema Operativo de la Tarjeta en la primera celda (01h) de la matriz. Figura 3.8. Estructura de un fichero cíclico. 3.1.3.3.2. Tipos de Ficheros Elementales. Aquí, se veran los diferentes tipos de ficheros que pueden existir, según la Tarjeta habrá mas o menos tipos. • Ficheros del sistema. Estos ficheros, normalmente son usados para almacenar claves de acceso, para proteger a Directorios y Ficheros Elementales de usos desautorizados. También se usan para ejecutar determinadas aplicaciones. El acceso a estos ficheros está protegido por el SO (No confundir estos ficheros con los Ficheros proporcionados por la Tarjeta). Existen dos maneras distintas de integrar estos ficheros dentro del Sistema de Archivos, el método de ISO, consiste en ocultarlos dentro del Fichero Dedicado correspondiente a la aplicación (en el caso de que cuelguen del MF, dicho fichero estará dentro del MF). Otro método, propuesto por el ETSI (Instituto Europeo para la Estandarización de la Telecomunicaciones), consiste en dejar visible estos ficheros y asignarles un identificador con el cual puedan ser seleccionados. Como ya se ha dicho, el SO, depende de la filosofía del fabricante, por ello según la marca y tipo de la Tarjeta, usará uno de estos métodos u otro propio del fabricante.
9
• Ficheros ejecutables. En contraste con otros Sistemas Operativos, no es frecuente en la industria de las Tarjetas Inteligentes almacenar programas ejecutables. Sin embargo, esta es una de las principales funciones de cualquier sistema. Existen varias razones por las que esta función ha estado ausente en las Tarjetas durante bastante tiempo. La razón principal, es que teniendo en cuenta que el microprocesador de la Tarjeta Inteligente, no tiene protección de memoria de ningún tipo, tan pronto como el contador de programa sea cargado con la dirección del fichero ejecutable, el control de la Tarjeta pasará automáticamente al fichero ejecutable y este podrá acceder a toda la memoria, saltándose los mecanismos de seguridad y acceder a cualquier dato almacenado. La creación de este tipo de ficheros, se puede realizar de dos maneras: la primera consiste, en almacenar el código del programa en un fichero ejecutable. Para activar el programa basta con seleccionar dicho fichero y enviar la orden EXECUTE, en algunos casos también deben satisfacerse las condiciones de acceso. La respuesta generada por el programa se devuelve como parte de la respuesta a la orden de ejecución. El otro método de creación de ficheros ejecutables, está descrito en el estándar EN 726−3. De acuerdo con esta norma, los Ficheros Dedicados contienen todos los datos referentes a una determinada aplicación y también pueden incluir instrucciones específicas para esa aplicación. El DF posee un área donde almacena el fichero ejecutable que es administrado por el Sistema Operativo. Una vez seleccionado el DF y enviado la orden de EXECUTE, el SO comprobará antes de ejecutar cada instrucción, si dicha instrucción pertenece al conjunto de instrucciones específicas para esa aplicación, en caso afirmativo se ejecuta la instrucción pedida. En el caso de que la instrucción no pertenezca a la aplicación actual, el Sistema Operativo ignora la orden. Este tipo de fichero también se puede usar para ampliar el Sistema Operativo de las Tarjetas. Por ejemplo, para añadir algoritmos criptográficos. • Fichero del usuario. A este tipo de fichero, acudirá el usuario para guardar los datos que necesite su aplicación, por ejemplo, los datos personales del usuario, el número de veces que realizó una operación, etc. Puede tener cualquier tipo de estructura de las antes mencionadas. • Ficheros proporcionados por la Tarjeta. Son ficheros que la Tarjeta ofrece al usuario para una utilidad determinada, como puede ser: almacenar claves 3DES, claves públicas, códigos secretos... También hay ficheros para utilizar la Tarjeta como monedero o para realizar transacciones. La estructura de cada fichero dependerá del SO. 3.1.3.3.3. Atributos de los Ficheros Elementales. Los atributos se definen a la vez que se crea el fichero y generalmente no se pueden modificar con posterioridad. • Atributo de lectura múltiple. También se le conoce como W.O.R.M. (Write Once, Read Many), escribe una vez, lee muchas veces. Cuando un fichero posee este atributo, sólo se podrá escribir en él una vez, pero podrá ser leído cuantas veces como se deseé. Esta característica de escribir una sola vez, debe ser soportada por el hardware de la EEPROM o también se puede incorporar a través de una función software. El propósito de este atributo es proteger los datos importantes contenidos en la Tarjeta frente a posibles sobreescrituras. • Atributo de escritura múltiple. 10
Permite que el contenido del fichero pueda ser alterado muchas veces. El número máximo de alteraciones, depende de los ciclos de lectura y escritura de la EEPROM. Se utiliza en los ficheros que se usan mucho. • Atributo de corrección de errores. Este atributo se usa para datos que son particularmente importantes (por ejemplo las claves) y que requieren algún tipo de código para la detección de errores. Este atributo permite corregir errores producidos en la memoria EEPROM. 3.1.3.4. Identificación de los ficheros (File Identifier o FID). Todos los ficheros (DF y MF también son ficheros) poseen un identificador o FID de 2 bytes de longitud, que se usa para poder seleccionarlos. Por razones históricas el MF tiene el FID 3F00h. El valor FFFFh está reservado para aplicaciones futuras. Los valores del FID de cada fichero deben escogerse de tal manera, que dos EFs que estén dentro del mismo DF (o MF) no deben tener el mismo FID y tampoco está permitido que un DF posea un FID, igual al de un EF o DF que estén colgado de él, o en el nivel inferior en la jerarquía de ficheros. Los FID son asignados por el propio usuario, y se ha de seguir algún tipo de norma para su asignación, para evitar posibles problemas. Por ejemplo, se puede seguir la siguiente norma: • Los DFs tendrán un FID xx 00, siendo xx el valor que el usuario quiera poner (no vale el valor 3F). • Los EFs tendrán un FID zz yy, siendo zz el valor xx del DF (o MF) sobre el que cuelgue el EF y yy el valor que el usuario quiera poner (no vale el valor 00). Figura 3.9. Ejemplo de asignación de FIDs Los DFs tienen otro identificador adicional, el nombre del DF, por ejemplo DatosUsuario. 3.1.3.5. Direccionamiento de los ficheros. Debido a la estructuración en objeto del Sistema Operativo, es necesario seleccionar los ficheros antes de acceder a ellos. Esto sirve para indicar al sistema con qué fichero se desea trabajar. Esto presenta el inconveniente de que no es posible seleccionar dos ficheros a la vez. 3.1.3.5.1. Seleccionar el Fichero Maestro. El Fichero Maestro, se puede seleccionar desde cualquier lugar de la jerarquía de ficheros, usando el identificador 3F00h. 3.1.3.5.2. Seleccionar un Fichero Dedicado. Sólo se pueden seleccionar los Ficheros Dedicados, que estén dentro del directorio de trabajo actual, esto es, si por ejemplo se tiene seleccionado el MF, solo se podrán seleccionar los DFs que cuelguen de él. También se pueden seleccionar DFs que se encuentren en el mismo nivel jerárquico del sistema de ficheros. Por ejemplo, seleccionar un DF que cuelgue del MF, desde otro DF que también cuelgue del MF. La selección puede ser, usando su FID o su nombre de directorio. 3.1.3.5.3. Seleccionar un Fichero Elemental. Sólo se pueden seleccionar los Ficheros Elementales, que estén dentro del directorio de trabajo actual, por ejemplo, si se tiene seleccionado el MF, sólo se podrán seleccionar los EFs que cuelguen de él. Esta selección 11
puede ser explícita, usando el FID del Fichero Elemental. O implícita, usando sólo los 5 bits menos significativos del FID. Este último método, permite seleccionar un fichero y al mismo tiempo acceder a él, usando sólo una instrucción. Este método sólo sería efectivo, si se ha seguido una estrategia de asignación de los FID, compatible con este método de selección. 3.1.3.5.4. Ejemplo gráfico sobre la selección de ficheros. Figura 3.9. Ejemplos de selecciones posibles de ficheros (izquierda) y selecciones no autorizadas (derecha). 3.1.3.6. Control de acceso en los ficheros. Todos los ficheros, en su cabecera, tienen unas condiciones de acceso, que deben ser cumplidas antes de realizar cualquier operación sobre el fichero. Estas condiciones, son puestas cuando se crea el fichero y como norma general, no se pueden modificar más tarde. Por ejemplo, los EFs pueden estar protegidos por dos condiciones de acceso, una que bloquea la operación de leer en el EF y otro la operación de escribir. El MF o los DFs, pueden estar protegidos por una sola condición de acceso, que bloquea el poder crear EFs sobre ellos. El encargado de controlar este acceso, es el administrador de ficheros. Estas condiciones de acceso, son normalmente códigos secretos, que el usuario que intente usar dicho fichero, debe de conocer. El ejemplo más claro de este tipo de condición de acceso es el PIN. A este tipo de ficheros se le conoce como EFsc (EF Secret Code). 3.1.4. Tipos de Tarjetas Inteligentes. E n contraste con el funcionamiento de cualquier ordenador, la memoria de una Tarjeta esta bastante restringida en capacidad, por esto, en algunos casos es imposible incluir en una sola Tarjeta todas las instrucciones y estructuras de ficheros existentes. Por esa razón, se han creado varios perfiles de Tarjetas Inteligentes, que están recogidos en la especificación ISO/IEC 7816−4 y EN 726−3. Cada perfil define un subconjunto de instrucciones y estructuras de ficheros. Por tanto las Tarjetas realizarán distintas funciones de acuerdo al perfil al que pertenecen. Perfil
Descripción Estructura de datos
Características −Ficheros Transparentes −Ficheros Lineales fijo −Lectura y actualización para los anteriores tipos de ficheros
Perfil M
Comandos más relevantes
−Selección de un fichero usando el FID −Verificación de las condiciones de acceso a los ficheros −Autenticación Interna 12
Perfil igual al Perfil M, pero posibilita la selección de un DF usando su nombre −Ficheros Transparentes
Perfil N
Perfil O
Estructura de datos
−Ficheros Lineales fijo −Ficheros Lineales variables −Ficheros Cíclicos −Lectura y actualización para los anteriores tipos de ficheros −Redimensión de las estructuras de los ficheros, basados en registros −Selección de un fichero usando el FID Comandos más relevantes
−Selección de un DF usando su nombre −Verificación de las condiciones de acceso a los ficheros −Autenticación Interna −Autenticación Externa −Generación de números aleatorios, para sistemas criptográficos basados en DES o en clave pública
Estructura de datos
−Ficheros Transparentes Comandos más
−Lectura y actualización para Ficheros Transparentes
relevantes −Selección de un fichero usando el FID −Selección de un DF usando su nombre Perfil P
−Verificación de las condiciones de acceso a los ficheros
13
Perfil Q
Transferencia de datos
−Autenticación Interna −Intercambio seguro de datos −Obtener y poner datos −Selección de un fichero usando el FID −Selección de un DF usando su nombre
Comandos más relevantes
−Verificación de las condiciones de acceso a los ficheros −Autenticación Interna −Generación de números aleatorios, para sistemas criptográficos basados en DES o en clave publica
3.2. La comunicación entre la Tarjeta y el lector. D ebido a la existencia de un único canal de comunicaciones entre la Tarjeta y el lector de Tarjetas, ambos deben turnarse para llevar a cabo la transmisión de datos. Toda comunicación que se realice con una Tarjeta es iniciada siempre por el exterior, esto quiere decir, que la Tarjeta nunca transmite información sin que se haya producido antes una petición externa. Esto equivale a una relación maestro−esclavo, siendo el lector el maestro y la Tarjeta el esclavo. Cada vez que se inserta una Tarjeta en el lector, la Tarjeta inicia un reset de encendido y envía una PDU de respuesta del reset, llamada ATR (Answer To Reset) hacia el lector. Esta respuesta, contiene información referente a cómo ha de ser la comunicación Tarjeta−lector: estructura de los datos intercambiados, protocolo de transmisión, etc. La transmisión de datos entre ambos dispositivos es asíncrona, esto significa, que cada byte enviado debe estar provisto de algún mecanismo de sincronización. Toda comunicación comienza siempre con un bit de inicio, después el byte de datos, luego un bit de paridad, para detectar errores en el byte de datos y por ultimo 1 o 2 bits de parada. El tiempo que ha de esperarse para poder enviar otro carácter vendrá indicado en la PDU ATR. Siempre que no se esté transmitiendo información por la línea, ésta debe estar a 5 voltios. Figura 3.10. Estructura del paquete de datos transmitido. La duración nominal de un bit, se define como unidad elemental de tiempo o ETU. Esta medida posee un valor inicial, que depende de si la Tarjeta posee reloj interno o por lo contrario necesita de uno externo (que es aplicado a través del contacto CLK). Si la Tarjeta posee su propio reloj, el valor del ETU es 1/9600sg. Esto produce una tasa de transmisión de datos de 9600 bps. Cuando la Tarjeta necesita un reloj externo, el valor del ETU = 372 / fi [sg]. Donde la varible fi, es la frecuencia del reloj externo y su valor está entre 1 y 5 Mhz. 3.2.1. Protocolos de comunicación. 14
E ntre la respuesta ATR y la primera orden enviada, el terminal puede transmitir una instrucción de selección del tipo de protocolo o PTS (Protocol Type Selection). Esto sucede cuando la Tarjeta especifica más de un protocolo en la respuesta al reset y el terminal no sabe cuál ha de usar. Figura 3.11. Secuencia de inicio y transferencia de datos entre una Tarjeta y el terminal lector. Los protocolos de comunicación, especifican con precisión, el formato de las instrucciones, las respuestas a las mismas y el procedimiento a seguir en caso de que se produzcan errores durante la transmisión. La siguiente tabla describe los rasgos más importantes de los distintos tipos de protocolos especificados por ISO: Protocolo T=0 T=1 T=2 T=3 T=4 T=5 ... T=13 T=14 T=15
Significado Transmisión byte a byte de manera asíncrona y half duplex Transmisión por bloques de manera asíncrona y half duplex Transmisión por bloques de manera asíncrona y full duplex Transmisión full duplex aún sin especificar Expansión del protocolo T = 0 Aún sin especificar Para funciones nacionales, no está especificado por ISO Aún sin especificar
Los protocolos más utilizados son: el T=0 que fue diseñado en 1989, y el T=1 que fue creado en 1992. 3.2.1.1. Protocolo T = 0. Fue usado en Francia, durante la fase inicial del desarrollo de las Tarjetas Inteligentes y fue el primero en incluirse dentro de un estándar internacional. Es un protocolo orientado al uso del byte, esto quiere decir que la unidad mínima de información procesada es un byte. Las PDUs consisten en una cabecera, que incluye un byte para especificar la clase de la instrucción (CLA), otro para indicar la instrucción (INS) y tres bytes opcionales, que actúan como referencias (P1, P2 y P3). A la cabecera le sigue opcionalmente una sección de datos. Figura 3.12. Formato de la instrucción del protocolo T=0. El byte CLA es la clase de la instrucción (GPS, ISO...). El valor FFh está reservado para la selección del tipo de protocolo. El byte INS especifica el código de la instrucción. Este campo sólo es válido si el bit menos significativo es igual a cero, y el más significativo tiene cualquier valor distinto a 6 y 9. P1 y P2 son referencias, por ejemplo, una dirección que completa el código de la instrucción. El byte P3 especifica el número de bytes que serán transmitidos en la sección de datos (instrucción de escritura) o los bytes que serán leídos (instrucción de lectura). Cuando P3 es igual a cero y la orden es de lectura, la Tarjeta enviará una cabecera de 256 bytes. En caso de que se detecte un error en la transmisión de algún byte, se debe proceder al reenvío del byte dañado. El único mecanismo de detección de errores es el bit de paridad. Cuando el receptor detecta un error después de recibir el byte de paridad, debe poner la línea de comunicaciones a nivel bajo (0 voltios) al menos 15
durante un ETU y como máximo dos. Esto sirve para que el dispositivo transmisor, compruebe si los datos se recibieron correctamente. Si la línea, después de transmitir los datos, está a nivel alto, quiere decir que la recepción fue correcta, en caso contrario, se procede al reenvío del byte erróneo después de finalizar la señal de error. 3.2.1.2. Protocolo T = 1. Este protocolo es orientado a la transmisión de bloques de manera asíncrona half duplex. Tomando como referencia el modelo OSI, este protocolo opera en el nivel dos o capa de enlace. La característica principal es que permite formar paquetes con los bytes de datos. Con esto se consigue: • Control de flujo. • Corrección de errores. • Encadenamiento de paquetes. Otra ventaja importante de este protocolo es la posibilidad de administrar en ambos sentidos el flujo de datos. El T=0, no permite que la Tarjeta tome el control de las comunicaciones y sólo puede enviar información por la línea de datos, cuando el terminal los haya solicitado. El T=1 elimina esta barrera y permite que la Tarjeta envíe comandos de igual manera que el terminal lector. Las desventajas que presenta este tipo de protocolo son: • Mayor complejidad del Sistema Operativo. • Incremento en el uso de la memoria de la Tarjeta. 3.3. Seguridad en las Tarjetas Inteligentes. E n este punto, veremos qué mecanismos de seguridad tienen las Tarjetas Inteligentes, para protegerse de ataques físicos y lógicos y qué servicios criptográficos, ofrecen a los usuarios. 3.3.1. Seguridad Física. L os ataques físicos, son aquellos que intentan explotar las vulnerabilidades físicas, que presenta todo circuito electrónico, tales como: • El Consumo de energía: Las instrucciones, pueden ser rastreadas midiendo el consumo de energía mientras el código está siendo ejecutado, el microprocesador de la Tarjeta Inteligente puede evitar este ataque, generando consumos erráticos o realizando operaciones fingidas entretanto. Esto incluye almacenar bits en celdas fingidas, para evitar la detección de localizaciones físicas de memoria. • Voltaje Alto/Bajo: Un cambio repentino en la tensión de alimentación, puede provocar un mal funcionamiento del micro de la Tarjeta, produciendo tal vez, una validación de un PIN no válido. Para evitar esto, el micro posee una referencia del voltaje para compararlo con el de alimentación, si es demasiado alto o bajo, la Tarjeta no debe funcionar. • La Extracción del chip: Los circuitos integrados de las Tarjetas Inteligentes no deben funcionar al ser extraídos, esto evita ataques mediante microscopios electrónicos; cuando el chip se introduce en la Tarjeta, se somete a una fuerza mecánica permanente, detectando esta fuerza el chip, puede 16
comprobar si ha sido o no extraído de la Tarjeta. • Borrado parcial: Aunque están protegidas contra la luz ultravioleta y los Rayos X, teóricamente es posible borrar celdas de memoria; por ello, hay bits centinela situados en la memoria aleatoriamente, que serán comprobados por el microprocesador cada cierto tiempo y que en caso de haber sido borrados, indicarán al micro que la Tarjeta debe dejar de funcionar. 3.3.2. Seguridad Lógica. L os ataques lógicos, son aquello que intentan explotar las vulnerabilidades del Software. Para evitar este tipo de ataques, se dispone de: • Un Sistema Operativo muy robusto (personalmente diría impenetrable, aunque esto, en seguridad es una utopía). • Autenticación Interna. El terminal, envía un número aleatorio a la Tarjeta, esta lo cifra, usando una clave que sólo conocen la Tarjeta y el terminal. El resultado de esta operación es enviado al terminal, que realiza la misma operación con el número aleatorio y compara el resultado con el obtenido por la Tarjeta y si ambos son iguales la Tarjeta queda validada, frente al mundo exterior. • Autenticación Externa. El terminal, solicita a la Tarjeta un número aleatorio, lo cifra con una clave secreta que sólo conocen la Tarjeta y el terminal. El resultado es enviado hacia la Tarjeta, esta realiza la misma operación y compara ambos resultados, si son iguales, el terminal queda validado frente a la Tarjeta. • Claves de acceso, para realizar operaciones sobre ficheros, como pueden ser: crear un DF, escribir en un EF, leer un EF, etc. • Todos los códigos secretos, enviados a la Tarjeta, pueden ser encriptados. • Todas la PDU enviadas a la Tarjeta, pueden ser enviadas con un checksum encriptado, asegurando así la integridad de la PDU. 3.3.3. Criptografía en las Tarjetas Inteligentes. D ependiendo del tipo de Tarjeta y del fabricante, el número de operaciones criptográficas, que la Tarjeta puede realizar variará. Aquí expondré las diferentes operaciones posibles, que pueden tener o llegar a tener las Tarjetas Inteligentes: • Generación de claves DES o 3DES. • Cifrado DES o 3DES. • Generación de claves RSA de distintas longitudes. • Encriptación con clave pública o privada. • Funciones Hash (MD5, SHA, SSL...). • Firma digital y su verificación. • Cifrado y descifrado de envoltorios digitales (cifrar los datos con DES y encriptar la clave DES con RSA).
17
Como norma general, las Tarjetas sólo ofrecen: generar claves RSA, firma digital y su verificación. 3.4. La Tarjeta Inteligente GPK 8000. La Tarjeta Gemplus Public Key 8000, tiene las siguientes características: • Una estructura de datos, comandos y códigos de error, compatibles con la norma ISO 7816−4. • Protocolo de comunicación T = 0. • Multiaplicación. • Protección de EFs y DFs con códigos secretos. • Un juego de comandos administrativos propiedad de Gemplus, más completo que el especificado en la norma ISO 7816−4. Estos nuevos comandos han sido sacados de la norma MPCONS−EMV. • Funciones de pago, estructura de datos y comandos, sacados de la norma MPCONS−EMV, incluyendo las funciones de monedero electrónico (no usadas en la librería TarIn). • Características compatibles con las normas EMV (no usadas en la librería TarIn). • Autenticación interna y externa (no incluidas en la librería TarIn). • Posibilidad de encriptar datos sensibles, como códigos secretos, cuando estos son enviados a la Tarjeta o recibidos, usando 3DES, conforme a la norma ISO 7816−4 (posibilidad no incluida en la librería TarIn). • Posibilidad de integridad en la comunicación Lector−Tarjeta, usando 3DES, conforme a la norma ISO 7816−4 (posibilidad no incluida en la librería TarIn). • Cálculo y verificación de firmas digitales usando RSA. • Cifrar con la clave Privada de una RSA. • Aproximadamente, 8 Kbytes de memoria EEPROM disponibles. • Algoritmos de hash MD5 y SHA−1. • Generación interna de claves RSA de 512 o 1024 bits. • Carga de claves RSA en la Tarjeta (de 512, 768 o 1024 bits). • Generación de números aleatorios de 8 o 32 bytes. • Relleno con PKCS#1 versión 1.5, ISO9796−2 o ANSI X9.31. • Desempaquetado de la clave 3DES, de los sobres digitales (no incluido en la librería TarIn).
La librería TarIn, ha sido desarrollada sobre el sistema operativo Windows 98, y utiliza librerías dinámicas proporcionadas por Gemplus, para el manejo de la Tarjeta Inteligente GPK 8000. Dichas librerías, permiten abrir varias comunicaciones con la Tarjeta Inteligente a la vez y desde programas diferentes. El lenguaje de programación utilizado para la construcción de la librería, ha sido C++, para aprovechar las múltiples ventajas que ofrece. El código, puede ser fácilmente portable a otras plataformas, ya que las funciones utilizas son ANSI. Esta portabilidad sería posible siempre, que Gemplus ofreciera las librerías para dichas plataformas. El entorno de desarrollo utilizado ha sido, Visual C++, versión 6.0 de Microsoft. La librería TarIn, ha sido creada como una librería estática, para poder ser incrustada en el programa que la utilice. Esta librería ha sido desarrollada para poder usar las características de las Tarjetas Inteligentes, de una forma cómoda y sin muchos conocimientos sobre ellas. Pero no se ha incluido toda la seguridad que ofrecen, como puede ser la autenticación interna y externa, esto es, porque esta librería esta orientada al entorno educativo y no al empresarial.
18
El paquete de desarrollo consta de los siguientes ficheros: • \TarIn\scr\TarIn.cpp Código fuente de la librería TarIn. Librería de alto nivel, para el manejo de la Tarjeta Inteligente GPK 8000 de Gemplus. • \TarIn\scr\TarIn_Privado.h Datos privados de la librería TarIn. • \TarIn\include\TarIn.h Interfaz de la librería TarIn. • \TarIn\include\TarIn_Cons.h Constantes para el uso de la librería TarIn. • \TarIn\include\TarIn_Tipos.h Tipos para el uso de la librería TarIn. • \TarIn\lib\TarIn.lib La librería en cuestión. • \TarIn\TarIn.dsp Proyecto para generar la librería TarIn, en Visual C++ v6.0. • \TarIn\TarIn.dsw Área de trabajo para Visual C++ v6.0. • \TarIn\Leeme.txt Contiene las últimas actualizaciones de ésta documentación. • \TarIn\Docu\Documentacion.doc Este proyecto, en formato Word 97. • \GPK Contiene los ficheros necesarios proporcionados por Gemplus, para generar TarIn. • \LectorTarjetas Contienen los ficheros, para la instalación del Lector de Tarjetas y las librerías para el manejo de la Tarjeta Inteligente, proporcionadas por Gemplus.
19
Aquí se explicarán los pasos a seguir, para instalar las librerías, que manejan a la Tarjeta Inteligente, proporcionadas por Gemplus y el Lector de Tarjetas, también de Gemplus. Ambas cosas se instalarán a la vez. Pasos a seguir para la instalación: • Apagar el ordenador. • Conectar el cable del puerto serie y el de alimentación (PS 2). • Encender el ordenador. • Se abrirá una ventana, indicando que se ha detectado un nuevo Hardware nuevo: GEMPLUS GCR410P Serial Smart Card Reader. • Se pulsa el botón de: Siguiente. • Se elige la opción: Mostrar una lista de todos los controladores... • Se pulsa el botón de: Siguiente. • Se pulsa el botón de: Utilizar disco. • Se busca la carpeta: LectorTarjetas. • Se elige el fichero: Gcr400.inf. • Se pulsa el botón de: Aceptar. • Se pulsa el botón de: Siguiente. • Aparecerá una ventana, informando: El controlado, que ha elegido... • Se pulsa el botón de: Si. • Se pulsa el botón de: Siguiente. • Se pulsa el botón de: Finalizar. • El ordenador termina de arrancar. Esta instalación copia los archivos: W32gchan.dll, W32gcr40.dll, W32gpkv2.dll, W32gr09.dll, W32gtser.dll y W32gtser.exe. En el directorio del sistema System. Gemplus no ofrece (o por lo menos yo he sido incapaz de encontrarlo) una instalación correcta para el Lector de Tarjetas GEMPC410, teniendo que instalar un programa llamado Pilot que ofrece Gemplus, para el aprendizaje y gestión de la Tarjeta Inteligente, para poder conseguir la instalación correcta del Lector. Para solucionar este problema, he tenido que sacar el archivo de configuración del Lector GEMPC410 (Gcr400.inf) que se encuentra en la instalación del programa Pilot, para poder instalar solo el Lector. Luego he añadido a las dll propias del Lector, las necesarias para el manejo de la Tarjeta Inteligente y las he incorporado al fichero Gcr400.inf, para así, en una sólo instalación, matar dos pájaros de un tiro. Por eso, esta instalación no se puede encontrar en Gemplus. En la fase de desarrollo de la aplicación, es mejor tener el libro Interface Library, capítulo Appendix A (Status Codes), proporcionado por Gemplus, a mano, para poder ver los errores que yo no haya convertido, porque cuando genere esta librería, no fui buscando traducir todos los errores que generaba las dll de Gemplus, a mis propios errores. Sólo realice la correspondencia de los errores más importantes y que me surgieron a mí. Con la documentación que hay en este libro, debería de valer para poder usar la Tarjeta Inteligente sin muchos problemas. Si algo da duda o se quiere profundizar, se tendrá que usar la documentación proporcionada por Gemplus. Buscar primero en el libro Reference Manual, si lo que se quiere obtener es información del Sistema Operativo. En el caso de querer saber más sobre alguna función de la librería que suministra Gemplus, primero buscarla en Interface Library y luego buscar la PDU que se ha usada para implementar dicha función en el capítulo GPK Commands del libro Reference Manual (esta búsqueda debe ser algo intuitiva). Si aún no se ha resuelto la duda, buscar en el tipo de fichero que usa dicha PDU (GPK Files) y en el apartado dedicado a dicho fichero. Hay que aclarar que la interfaz de esta librería, la he realizado ocultando muchas cosas de las Tarjetas Inteligentes, para que resultará más fácil su uso, por eso, en la documentación de 20
Gemplus, se encontrará una explicación más técnica y posiblemente más complicada de entender, que la expuesta aquí. Existe una aplicación suministrada por Gemplus, llamada Pilot, que permite aprender y gestionar la Tarjeta Inteligente de una forma mas cómoda, ya que tiene una interfaz gráfica. Pero para poder utilizar este programa con profundidad, se necesitan tener unos conocimientos más profundos sobre el Sistema Operativo de la Tarjeta Inteligente y sobre los comandos que esta tiene y su utilización, que los contenidos en este libro. Pero hay una función muy fácil de utilizar y útil, es el visualizador del Sistema de Ficheros, que permite ver todos los ficheros que hay creados dentro de la Tarjeta y su tipo. Unas recomendaciones sobre la programación: En el caso de que no se entienda como funciona una función, lo mejor es probarla, sin tener miedo de crear ficheros inservibles dentro de la Tarjeta. Y en el caso de crear archivos, solo para saber como funcionan, no tengas miedo de borrar la memoria de la Tarjeta Inteligente, tantas veces como quieras, aunque tampoco borres cada vez que crees un fichero de prueba. Tened mucho cuidado, cuando se este trabajando con la Tarjeta con varias comunicaciones a la vez, porque puede ocurrir que una comunicación cierre todas las restantes, aunque dichas comunicaciones se estén realizado desde programas diferentes, esto es porque todos usan las mismas dll para la comunicación con la Tarjeta. Para empezar, es la primera vez que me enfrentaba a un proyecto de este tamaño y sólo. Programar la Tarjeta Inteligente era un mundo totalmente nuevo para mí. El primer problema surgió, al intentar instalar el Lector de Tarjetas, ya que Gemplus sólo proporcionaba controladores PS−SC de los lectores, y no encontraba ningún controlador, para trabajar con el lector desde un nivel más bajo de desarrollo. Este problema lo solucione gracias, a que el programa Pilot de Gemplus incorporaba la instalación de controladores de bajo nivel. Y con esta instalación empecé a tirar líneas de código. A la hora de programar, los comienzos fueron muy lentos y con todas las funciones cogidas con pinzas, menos mal que tenía unos ejemplos básicos de cómo utilizar la Tarjeta, que me ayudaron a empezar a comprender el funcionamiento de ésta. En la creación de la interfaz, el único problema que había, era desarrollar una interfaz fácil de entender, de usar y robusta. Esta última característica, me obligó a introducir mucho código de comprobación. Ya, en el uso de las funciones proporcionadas por la librería de alto nivel de Gemplus, encontré varios problemas. El primero era que la función que borraba la memoria de la Tarjeta no funcionaba (G_EraseMen), para solucionarlo, tuve que crear la PDU, que mandaba a la Tarjeta que ejecutará esta orden (Erase Card), teniendo que buscar la función que enviaba PDUs a la Tarjeta, sin ningún tipo de referencia a ella en la documentación de Gemplus. Otro problema era: que algunos parámetros de entrada, eran también de salida, cosa que no se reflejaba en la documentación, más exactamente dicho problema estaba en las funciones: G_SetCode y G_SerCodeSecure. Resumiendo: al final tuve que pelearme de una u otro formar, con todas las funciones de Gemplus antes de hacerlas funcionar. Pero el peor problema de todos, fue la documentación proporcionada por Gemplus para el desarrollo, en los libros Reference Manual y Interface Library. Esta documentación es escueta, confusa y sin una buena organización, no permitiendo un buen aprendizaje del funcionamiento interno de la Tarjeta. Empezando por las explicaciones de los errores retornados por las funciones: dichas explicaciones son breves y muy desorientativas. Continuando con las explicaciones de las funciones, que seguían la tónica de toda la 21
documentación proporcionada, provocando tener que probar diferentes valores para los parámetros de las funciones, hasta dar con una combinación, que hacía funcionar a la función. Pero todo esto se podría haber suplido con una buena documentación sobre el funcionamiento interno de la Tarjeta, pero no hubo tal suerte. Para aprender dicho funcionamiento, tuve que ir recopilando datos de uno y otro sitio hasta que encajaban algunas piezas. Una de las cosas que más me ayudo a comprender el funcionamiento de la Tarjeta, fue usar el programa Pilot, que lo usé para ver el efecto que causaban las funciones sobre el sistema y sobre los ficheros, deduciendo de los efectos, el comportamiento de la Tarjeta. Resumiendo: o la documentación de Gemplus es muy mala o yo no he sabido leerla bien.
UltimoError
Código del último error producido por la librería de GPK. Con este código se puede determinar (a veces), con mayor precisión la causa del error. Para mayor información sobre el significado de estos códigos de error, ver la documentación que proporciona Gemplus en el libro Interface Library, capítulo APPENDIX A (Status Codes ).
Grupo1
Contiene las Condiciones de Acceso del Grupo uno, del último fichero (MF, DF o EF) seleccionado.
Grupo2
Contiene las Condiciones de Acceso del Grupo dos, del último fichero (MF, DF o EF) seleccionado.
Contiene las Condiciones de Acceso del Grupo tres, del último fichero (MF, DF o EF) seleccionado. Las variables Grupo1, Grupo2 y Grupo3, están compuestas por los siguientes elementos: Grupo3
Indica el nivel de protección para este Grupo de Acceso. Puede tener uno de estos valores:
Proteccion
• Sin_Proteccion. Acceso libre. • Codigo_1. Para poder realizar las operaciones que protege este Grupo de Acceso, tiene que estar verificado el Código Secreto C1. • Codigo_1y2. Para poder realizar las operaciones que protege este Grupo de Acceso, tienen que estar verificados los Códigos Secretos C1 y C2. • Bloqueado. Acceso bloqueado. Indica el nivel jerárquico donde se encuentra el EFsc que contiene el Código Secreto C1. Puede tener uno de estos valores:
NivelEFscC1
NumeroCodigoC1
• En_MF. El EFsc ésta en el MF. • En_Local. El EFsc ésta en el directorio actual. Número del Código Secreto del EFsc anterior, que se debe de introducir para cumplir la Condición de Acceso. Indica el nivel jerárquico donde se encuentra el EFsc que contiene el Código Secreto C2. Puede tener uno de estos valores:
NivelEFscC2
• En_MF. El EFsc esta en el MF. • En_Local. El EFsc esta en el directorio actual. 22
NumeroCodigoC2
Número del Código Secreto del EFsc anterior, que se debe de introducir para cumplir la Condición de Acceso.
Constructor de la clase. Inicializa las variables privadas y públicas de la clase. Formato: C_TarIn ( void ); Destructor de la Clase. Desconecta la Tarjeta Inteligente. Internamente llama al método Desconectar. Formato: ~C_TarIn ( void ); Este método, conecta con la Tarjeta Inteligente insertada en el lector. Formato: TarIn_Error Conectar ( TipoPuerto Puerto = DEF_PUERTO, UINT Velocidad = DEF_VELOCIDAD, UINT TipoLector = DEF_TIPO_LECTOR, UINT Interrupcion = DEF_INTERRUPCION, UINT TipoTarjeta = DEF_TIPO_TARJETA ); Parámetros de entrada:
Puerto
Puerto donde ésta conectado el lector de Tarjetas Inteligentes. Puede tener uno de estos valores: COM1, COM2, COM3, COM4, LPT1, LPT2, LPT3 o LPT4. Valor por defecto: DEF_PUERTO, que equivale al puerto COM2.
Velocidad
Indica la velocidad de trabajo del puerto. En el caso de que el puerto usado sea LPTx, este parámetro no será tomado en cuenta. Si se esta trabajando con el lector GCR410, sólo se puede usar uno de estos valores: 9600, 19200 o 38400 bps. Valor por defecto: DEF_VELOCIDAD, que equivale a una velocidad de 38400 bps. Tipo del terminal lector usado. Ver el fichero TarIn_Cons.h para ver todos los tipos de lectores disponibles.
TipoLector Valor por defecto: DEF_TIPO_LECTOR, que equivale a un lector de tarjetas GCR410. 23
Interrupción del puerto. En el caso de que el puerto usado sea LPTx, este parámetro no será tomado en cuenta. Interrupcion
Valor por defecto: DEF_INTERRUPCION, que equivale al valor 0xFF, que significa que se usará la interrupción por defecto del sistema. Tipo de Tarjeta Inteligente a usar. Ver el fichero TarIn_Cons.h para ver todos los tipos de Tarjetas Inteligentes disponibles.
TipoTarjeta Valor por defecto: DEF_TIPO_TARJETA, que equivale a una Tarjeta Inteligente ISO. Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, conecta con la Tarjeta Inteligente insertada en el lector. Internamente este método llama a la anterior función Conectar, pasándole los valores por defecto. Formato: TarIn_Error Conectar ( UINT TipoTarjeta = DEF_TIPO_TARJETA ); Parámetro de entrada: Tipo de Tarjeta Inteligente a usar. Ver el fichero TarIn_Cons.h para ver todos los tipos de Tarjetas Inteligentes disponibles. TipoTarjeta Valor por defecto: DEF_TIPO_TARJETA, que equivale a una Tarjeta Inteligente ISO. Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, cierra la comunicación con la Tarjeta Inteligente. Formato: TarIn_Error Desconectar ( void ); Valor retornado:
24
Siempre retorna TarIn_NO_ERROR. Este método selecciona el MF. Puede ser llamado desde cualquier punto de la jerarquía de ficheros. Si todo fue bien, al salir de este método, se tendrá seleccionado el MF y se modificarán las siguientes variables públicas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contienen el error producido. Formato: TarIn_Error SeleccionarMF ( void ); Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método selecciona un DF, usando su identificador. Puede ser llamado desde cualquier punto de la jerarquía de ficheros, porque antes de seleccionar el DF, se llama al método SeleccionarMF y luego se selecciona el DF pedido. Si todo fue bien, al salir de este método, se tendrá seleccionado el DF y se modificarán las siguientes variables públicas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, se llamará al método SeleccionarMF y se modificarán las variables: MiError y UltimoError, que contienen el error producido al seleccionar el DF y no el que pueda producir la llamada al método SeleccionarMF. Formato: TarIn_Error SeleccionarDF ( WORD16 Id_DF ); Parámetro de entrada: Id_DF
Identificador del DF que se quiere seleccionar.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR, si no existe el DF TarIn_NO_SE_ENCONTRO y si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método selecciona un DF, usando el nombre del directorio. Puede ser llamado desde cualquier punto de la jerarquía de ficheros, porque antes de seleccionar el DF, se llama al método SeleccionarMF y luego se 25
selecciona el DF pedido. La selección de un DF usando su nombre, es un poco particular, para ilustrar este hecho, veremos unos ejemplos. Se supondrá que tenemos los siguientes DFs creados, y el orden de creación de los mismos, es el indicado en el campo Creado: Creado 1º 2ª 3ª
Nombre Kalimocho kalimocho Kali
Identificador 0x300 0x200 0x400
• SeleccionarDF ( Kalimocho ); DF seleccionado 0x300 • SeleccionarDF ( Kalimo ); DF seleccionado 0x300 • SeleccionarDF ( Kali ); DF seleccionado 0x300 • SeleccionarDF ( K ); DF seleccionado 0x300 • SeleccionarDF ( k ); DF seleccionado 0x200 Si todo fue bien, al salir de este método, se tendrá seleccionado el DF y se modificarán las siguientes variables públicas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, se llamará al método SeleccionarMF y se modificarán las variables: MiError y UltimoError, que contienen el error producido al seleccionar el DF y no el que pueda producir la llamada al método SeleccionarMF. Formato: TarIn_Error SeleccionarDF ( BYTE *Nombre ); Parámetro de entrada:
Nombre
Nombre del DF que se quiere seleccionar, terminado en `/0'. La longitud del nombre puede tener entre 1 y 16 bytes (sin incluir el `/0').
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR, si no existe el DF TarIn_NO_SE_ENCONTRO y si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método selecciona un EF, usando su identificador. Sólo se pueden seleccionar los EFs que estén dentro del DF (o MF) de trabajo. Si todo fue bien, al salir de este método, se tendrá seleccionado el EF y se modificarán las siguientes variables públicas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contienen el error producido y se mantendrá el DF (o MF) de trabajo. Siendo el último fichero seleccionado, indeterminado. 26
Formato: TarIn_Error SeleccionarEF ( WORD16 Id_EF ); Parámetro de entrada: Id_EF
Identificador del EF que se quiere seleccionar.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR, si no existe el EF TarIn_NO_SE_ENCONTRO y si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método crea un DF sobre el MF. Puede ser llamado desde cualquier punto de la jerarquía de ficheros, porque antes de crear el DF, se llama al método SeleccionarMF. Antes de crear el DF, este método, mira si existe ya un DF o EF con el mismo identificador o algún DF, con el mismo nombre. Si no se cumplen estas condiciones, se creará el DF con las siguientes Condiciones de Acceso: Grupo 1: Protege la creación y el bloqueo de los Grupos de Acceso, de los EFs sensibles: EFRSA y EFsc. • Protección : Acceso Libre (los demás campos ya no importan). • Identificador del EF 3DES : − • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : − • Numero del Código Secreto C1 : − • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − Grupo 2: Protege la creación y el bloqueo de los Grupos de Acceso, de los EFs de Datos: EFDatos. • Protección : Acceso Libre (los demás campos ya no importan). • Identificador del EF 3DES : − • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : − • Numero del Código Secreto C1 : − • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − Antes de salir de este método, se llamará al método SeleccionarMF (aunque no se haya producido un error). En el caso de producirse un error, las variables: MiError y UltimoError, contendrán el error producido al crear el DF y no el que pueda producir la llamada al método SeleccionarMF. Formato:
27
TarIn_Error CrearDF ( WORD16 Id_DF, BYTE *NombreDF ); Parámetros de entrada: Id_DF
Identificador que se quiere para el DF a crear.
NombreDF
Nombre que se quiere poner al DF a crear, terminado en `/0'. La longitud del nombre puede tener entre 0 y 16 bytes (sin incluir el `/0').
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR, si ya existe un DF o EF con el mismo identificador, o algún DF con el mismo nombre, se devolverá TarIn_YA_EXISTE y si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, crea un EFsc (Secret Code Código Secreto) sobre el DF en el que sé esta trabajando. Antes de crear el EFsc, este método, mira si existe ya un EF con el mismo identificador. Si no se cumple esta condición, se creará un EFsc con las siguientes Condiciones de Acceso: Grupo 1: Actualizar los datos del EFsc. • Protección : Acceso Libre (los demás campos ya no importan). • Identificador del EF 3DES : − • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : − • Numero del Código Secreto C1 : − • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − Grupo 2: Escribir datos en el EFsc. • Protección : Acceso Libre (los demás campos ya no importan). • Identificador del EF 3DES : − • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : − • Numero del Código Secreto C1 : − • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − Grupo 3: Leer los datos del EFsc. • Protección : Acceso Libre (los demás campos ya no importan). 28
• Identificador del EF 3DES : − • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : − • Numero del Código Secreto C1 : − • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − El EFsc creado, puede almacenar hasta 8 Códigos Secretos. Para almacenar estos códigos, internamente se llama 8 veces al método CargarCodigoSecreto, que introduce los Códigos Secretos en el EFsc creado, con la siguiente configuración: El código 7 del EFsc, será el Código que habrá que introducir para desbloquear a los demás Códigos ( 0−6 ), por eso recomiendo no usar este Código ( 7 ) para otros usos, ya que una vez bloqueado, no se podrá desbloquear, ni el número 7 ni ningún otro Código Secreto del EFsc. El número de veces que se puede introducir incorrectamente un Código Secreto seguidas, es de 4 veces, una vez sobrepasado este número, el Código quedará bloqueado y habrá que usar el método DesbloquearCodigoSecreto y el código 7, para desbloquearlo. Recomiendo usar el método BloquearGrupoDeAccesoEF sobre el EFsc creado (bloqueando los tres Grupos de Acceso), una vez que se esté seguro de que los Códigos Secretos introducidos en el EFsc, son correctos. Con esto se evitará que los Códigos puedan ser leídos o modificados (ver CargarCodigoSecreto). Si todo fue bien, al salir de éste método, no se modificará el DF de trabajo y pasará a estar seleccionado el EFsc creado. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, se llamará al método SeleccionarMF y se modificarán las variables: MiError y UltimoError, que contendrán el error producido al crear el EFsc y no el que pueda producir la llamada al método SeleccionarMF. Advertencias: Si por ejemplo en un Código Secreto introducimos SOLO 1234, su equivalente en la memoria sería: 0x49 0x50 x51 0x52 0x00 0x?? 0x?? 0x??. Y el sistema cogerá estos 8 bytes para generar el Código Secreto. Por eso, asegúrate que el Código Secreto tiene 8 bytes. Para el Sistema Operativo de la Tarjeta Inteligente, sólo tendrá valor el primer EFsc creado que se encuentre en un DF. Siendo los restantes EFsc creados en un mismo DF ignorados por los métodos DesbloquearCodigoSecreto, VerificarCodigoSecreto y CambiarCodigoSecreto. Aclaraciones: El Código Secreto real no consta de 8 bytes, sino de 4 bytes, esto es porque la Tarjeta Inteligente sólo coge los 4 bits menos significativos de cada byte, por ejemplo, si guardamos este Código Secreto 12345678, su equivalente en la memoria sería: 0x49 0x50 0x51 0x52 0x53 0x54 0x55 0x56. Pero en la Tarjeta Inteligente se guarda 0x90 0x12 0x34 0x56. Por eso, para verificar este Código Secreto, sería válido cualquier Código Secreto que cumpla lo siguiente: 0x?9 0x?0 0x?1 0x?2 0x?3 0x?4 0x?5 0x?6. La diferencia entre escribir y actualizar un EF, es la siguiente: • Escribir datos es: hacer la OR de los datos que hay en la memoria y los datos que se introducen. • Actualizar datos es: poner en la memoria directamente los datos que se introducen, machacando los datos que había antes.
29
Formato: TarIn_Error CrearEFsc ( WORD16 Id_EF, bool *GrabadoBien, BYTE *Codigo0 = NULL, BYTE *Codigo1 = NULL, BYTE *Codigo2 = NULL, BYTE *Codigo3 = NULL, BYTE *Codigo4 = NULL, BYTE *Codigo5 = NULL, BYTE *Codigo6 = NULL, BYTE *Codigo7 = NULL ); Parámetros de entrada: Id_EF
Identificador que se quiere para el EFsc a crear. Código Secreto del EFsc número 0. Usar un array de BYTE x[8].
Codigo0 Valor por defecto: NULL, internamente se sustituye por la constantes CODIGO_SECRETO_0. Código Secreto del EFsc número X. Usar un array de BYTE y[8]. CodigoX Valor por defecto: NULL, internamente se sustituye por la constantes CODIGO_SECRETO_X. Parámetro de salida:
GrabadoBien
Indica si se ha grabado bien los Códigos Secretos. Es un array de bool x[8], donde cada elemento del array, indica si se grabó bien ese Código Secreto (true) o si no (false). En el caso de que se halla grabado mal un Código Secreto, usar el método CargarCodigoSecreto para introducir de nuevo el Código Secreto.
Valor retornado: El error retornado por este método, sólo indica si el EFsc se creó bien, dejando los errores producidos al cargar los Códigos Secretos en el EFsc, al parámetro de salida GrabadoBien. 30
Si no se produce ningún error al crear el EFsc, se devolverá TarIn_NO_ERROR. En el caso de que exista ya un EF con el mismo identificador, se devolverá TarIn_YA_EXISTE y si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, carga un Código Secreto en un EFsc específico. Se debe de estar trabajando sobre el DF donde este el EFsc. No es necesario que el EFsc este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. El Código Secreto cargado en el EFsc, tendrá la siguiente configuración: El código 7 del EFsc seleccionado, será el Código que habrá que introducir para desbloquear el Código cargado, por eso recomiendo no usar este Código ( 7 ) para otros usos, ya que una vez bloqueado, no se podrá desbloquear, ni el número 7 ni ningún otro Código Secreto del EFsc. El número de veces que se puede introducir incorrectamente el Código Secreto seguidas, es de 4 veces, una vez sobrepasado este número, el Código quedará bloqueado y habrá que usar el método DesbloquearCodigoSecreto y el código 7, para desbloquearlo. En el caso de que exista ya un Código Secreto en esa posición, machacará toda su configuración y la sustituirá por la anterior. Esto implica que si el Código Secreto estaba bloqueado, se desbloquea y el número de veces que se ha introducido consecutivamente el Código Secreto erróneamente se pondrá a cero. Este método, funcionará siempre que las Condiciones de Acceso del Grupo uno (Actualizar datos), del EFsc, sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFsc actualizado. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al cargar el Código Secreto en el EFsc y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Advertencia: Si por ejemplo en un Código Secreto introducimos SOLO 1234, su equivalente en la memoria sería: 0x49 0x50 x51 0x52 0x00 0x?? 0x?? 0x??. Y el sistema cogerá estos 8 bytes para generar el Código Secreto. Por eso, asegúrate que el Código Secreto tiene 8 bytes. Aclaración: El Código Secreto real no consta de 8 bytes, sino de 4 bytes, esto es porque la Tarjeta Inteligente sólo coge los 4 bits menos significativos de cada byte, por ejemplo, si guardamos este Código Secreto 12345678, su equivalente en la memoria sería: 0x49 0x50 0x51 0x52 0x53 0x54 0x55 0x56. Pero en la Tarjeta Inteligente se guarda 0x90 0x12 0x34 0x56. Por eso, para verificar este Código Secreto, sería válido cualquier Código Secreto que cumpla lo siguiente: 0x?9 0x?0 0x?1 0x?2 0x?3 0x?4 0x?5 0x?6. Formato: TarIn_Error CargarCodigoSecreto ( WORD16 Id_EFsc, WORD16 NumeroCodigo,
31
BYTE *Codigo = NULL ); Parámetros de entrada: Id_EFsc
Identificador del EFsc, donde se quiere cargar un Código Secreto.
NumeroCodigo
Número del Código Secreto a cargar en el EFsc seleccionado. Valor comprendido entre 0 y 7, ambos inclusive. Código Secreto a cargar en el EFsc. Usar un array de BYTE x[8].
Codigo
Valor por defecto: NULL, internamente se sustituye por la constante CODIGO_SECRETO_X, siendo X = NumeroCodigo.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método verifica un Código Secreto, en el primer EFsc creado sobre el DF de trabajo. El EFsc puede o no estar seleccionado. En el caso de que sea válido el Código Secreto suministrado, se pondrá a cero el contador, que indica el número de veces que se ha introducido incorrectamente el Código Secreto y pondrá ese Código Secreto como validado. En el caso de que el Código Secreto no sea válido, este contador se incrementará, pudiendo llegar a bloquearse este Código Secreto, en tal caso se debe de usar el método DesbloquearCodigoSecreto, para desbloquear el Código Secreto. Para este método, las Condiciones de Acceso al EFsc, no son tenidas en cuenta. Aunque el EFsc tenga bloqueados los tres Grupos de Acceso, este método seguirá funcionando igual. Para el EFsc creado sobre un DF; los Códigos Secretos validados, no perderán su validez, mientras no se seleccione el MF u otro DF (aunque sea el mismo DF). Advertencia: Si por ejemplo en un Código Secreto introducimos SOLO 1234, su equivalente en la memoria sería: 0x49 0x50 x51 0x52 0x00 0x?? 0x?? 0x??. Y el sistema cogerá estos 8 bytes para generar el Código Secreto. Por eso, asegúrate que el Código Secreto tiene 8 bytes. Aclaración: El Código Secreto real no consta de 8 bytes, sino de 4 bytes, esto es porque la Tarjeta Inteligente sólo coge los 4 bits menos significativos de cada byte, por ejemplo, si guardamos este Código Secreto 12345678, su equivalente en la memoria sería: 0x49 0x50 0x51 0x52 0x53 0x54 0x55 0x56. Pero en la Tarjeta Inteligente se guarda 0x90 0x12 0x34 0x56. Por eso, para verificar este Código Secreto, sería válido cualquier Código Secreto que cumpla lo siguiente: 0x?9 0x?0 0x?1 0x?2 0x?3 0x?4 0x?5 0x?6. Formato: 32
TarIn_Error VerificarCodigoSecreto ( WORD16 NumeroCodigo, BYTE *Codigo ); Parámetros de entrada: NumeroCodigo
Número del Código Secreto a verificar en el EFsc. Valor comprendido entre 0 y 7, ambos inclusive.
Codigo
Código Secreto a verificar en el EFsc. Usar un array de BYTE x[8].
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de que el Código Secreto a validar sea erróneo, se devolverá, el siguiente error: TarIn_CODIGO_ERRONEO_QUEDAN_X, donde X, es un número, que indica el número de intentos que quedan, antes de que se bloquee el Código Secreto. Si el Código Secreto ha pasado al estado bloqueado, se devolverá TarIn_BLOQUEADO. Si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método cambia el valor de un Código Secreto, en el primer EFsc creado sobre el DF de trabajo. El EFsc puede o no estar seleccionado. Para cambiar el Código Secreto, esté no puede estar bloqueado, en tal caso se debe de usar el método DesbloquearCodigoSecreto, para cambiar el Código Secreto. Este método, no modifica ninguna de las opciones que tenga el Código Secreto antes, sólo y siempre, que sea correcto el CodigoAntiguo, se cambiará el antiguo Código Secreto por el CodigoNuevo y se pondrá a cero el contador que indica el número de veces que se ha introducido incorrectamente el Código Secreto. En el caso de que el CodigoAntiguo no sea válido, este contador se incrementará, pudiendo llegar a bloquearse este Código Secreto, en tal caso se debe de usar el método DesbloquearCodigoSecreto, para desbloquear el Código Secreto. Para este método, las Condiciones de Acceso al EFsc, no son tenidas en cuenta. Aunque el EFsc tenga bloqueados los tres Grupos de Acceso, este método seguirá funcionando igual. Advertencia: Si por ejemplo en un Código Secreto introducimos SOLO 1234, su equivalente en la memoria sería: 0x49 0x50 x51 0x52 0x00 0x?? 0x?? 0x??. Y el sistema cogerá estos 8 bytes para generar el Código Secreto. Por eso, asegúrate que el Código Secreto tiene 8 bytes. Aclaración: El Código Secreto real no consta de 8 bytes, sino de 4 bytes, esto es porque la Tarjeta Inteligente sólo coge los 4 bits menos significativos de cada byte, por ejemplo, si guardamos este Código Secreto 12345678, su equivalente en la memoria sería: 0x49 0x50 0x51 0x52 0x53 0x54 0x55 0x56. Pero en la Tarjeta Inteligente se guarda 0x90 0x12 0x34 0x56. Por eso, para verificar este Código Secreto, sería válido cualquier Código Secreto que cumpla lo siguiente: 0x?9 0x?0 0x?1 0x?2 0x?3 0x?4 0x?5 0x?6.
33
Formato: TarIn_Error CambiarCodigoSecreto ( WORD16 NumeroCodigo, BYTE *CodigoAntiguo, BYTE *CodigoNuevo ); Parámetros de entrada: NumeroCodigo
Número del Código Secreto a cambiar en el EFsc. Valor comprendido entre 0 y 7, ambos inclusive.
CodigoAntiguo
Código Secreto actual del EFsc. Usar un array de BYTE x[8].
CodigoNuevo
Código Secreto nuevo, que se almacenará en el EFsc, si el CodigoAntiguo es correcto. Usar un array de BYTE x[8].
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de que el Código Secreto Antiguo sea erróneo, se devolverá, el siguiente error: TarIn_CODIGO_ERRONEO_QUEDAN_X, donde X, es un número, que indica el número de intentos que quedan, antes de que se bloquee el Código Secreto. Si el Código Secreto ha pasado al estado bloqueado, se devolverá TarIn_BLOQUEADO. Si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método desbloquea y cambia el valor de un Código Secreto, en el primer EFsc creado sobre el DF de trabajo. El EFsc puede o no estar seleccionado. Este método, no modifica ninguna de las opciones que tenía antes el Código Secreto a desbloquear, sólo y siempre, que sea correcto el CodigoDesbloqueo, se cambiará el antiguo Código Secreto por el CodigoNuevo y se pondrá a cero el contador que indica el número de veces que se ha introducido incorrectamente, tanto del Código Secreto bloqueado (desbloqueando dicho Código Secreto) como del Código Secreto de desbloqueo. Este método también se puede usar sobre Códigos Secretos no bloqueados. Para este método, las Condiciones de Acceso al EFsc, no son tenidas en cuenta. Aunque el EFsc tenga bloqueados los tres Grupos de Acceso, este método seguirá funcionando igual. Advertencias: Si por ejemplo en un Código Secreto introducimos SOLO 1234, su equivalente en la memoria sería: 0x49 0x50 x51 0x52 0x00 0x?? 0x?? 0x??. Y el sistema cogerá estos 8 bytes para generar el Código Secreto. Por eso, asegúrate que el Código Secreto tiene 8 bytes. El CodigoDesbloqueo es el Código Secreto número siete del EFsc. En el caso de que este Código Secreto no sea válido, el contador se incrementará, pudiendo llegar a bloquearse este Código Secreto. Si se llegara a bloquear, ya no se podrá ni desbloquear este Código Secreto ni ningún otro (ver método CrearEFsc para mayor información). Aclaración: 34
El Código Secreto real no consta de 8 bytes, sino de 4 bytes, esto es porque la Tarjeta Inteligente sólo coge los 4 bits menos significativos de cada byte, por ejemplo, si guardamos este Código Secreto 12345678, su equivalente en la memoria sería: 0x49 0x50 0x51 0x52 0x53 0x54 0x55 0x56. Pero en la Tarjeta Inteligente se guarda 0x90 0x12 0x34 0x56. Por eso, para verificar este Código Secreto, sería válido cualquier Código Secreto que cumpla lo siguiente: 0x?9 0x?0 0x?1 0x?2 0x?3 0x?4 0x?5 0x?6. Formato: TarIn_Error DesbloquearCodigoSecreto ( WORD16 NumeroCodigo, BYTE *CodigoDesbloqueo, BYTE *CodigoNuevo ); Parámetros de entrada: NumeroCodigo
Número del Código Secreto a cambiar y desbloquear, en el EFsc. Valor comprendido entre 0 y 7, ambos inclusive.
CodigoDesbloqueo
Código Secreto de desbloqueo para el Código Secreto bloqueado. Usar un array de BYTE x[8].
CodigoNuevo
Código Secreto nuevo, que se almacenará en el EFsc, si el CodigoDesbloqueo es correcto. Usar un array de BYTE x[8].
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de que el Código Secreto de desbloqueo sea erróneo, se devolverá, el siguiente error: TarIn_CODIGO_ERRONEO_QUEDAN_X, donde X, es un número, que indica el número de intentos que quedan, antes de que se bloquee el Código Secreto. Si el Código Secreto ha pasado al estado bloqueado, se devolverá TarIn_BLOQUEADO. Si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método crea un EFDatos, sobre el DF en el que se esta trabajando. Antes de crear el EFDatos, este método, mira si existe ya un EF con el mismo identificador. Si no se cumple esta condición, se creará un EFDatos con las siguientes Condiciones de Acceso: Grupo 1: Actualizar los datos del EFDatos. • Protección : Protegido con el Código de Acceso C1. • Identificador del EF 3DES : No es necesario, generar una Clave de Sesión para cumplir las Condiciones de Acceso. • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : Local • Numero del Código Secreto C1 : 0 • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : −
35
Grupo 2: Escribir datos en el EFDatos. • Protección : Protegido con los Códigos de Acceso C1 y C2. • Identificador del EF 3DES : No es necesario, generar una Clave de Sesión para cumplir las Condiciones de Acceso. • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : Local • Numero del Código Secreto C1 : 1 • Nivel del EFsc para el Código 2 : Local • Numero del Código Secreto C2 : 2 Grupo 3: Leer los datos del EFDatos. • Protección : Protegido con el Código de Acceso C1. • Identificador del EF 3DES : No es necesario, generar una Clave de Sesión para cumplir las Condiciones de Acceso. • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : Local • Numero del Código Secreto C1 : 3 • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − El EFDatos creado, se usa para guardar cualquier tipo de información que el usuario quiera guardar en la Tarjeta Inteligente. Si todo fue bien, al salir de este método, no se modificará el DF de trabajo y pasará a estar seleccionado el EFDatos creado. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, se llamará al método SeleccionarMF y se modificarán las variables: MiError y UltimoError, que contendrán el error producido al crear el EFDatos y no el que pueda producir la llamada al método SeleccionarMF. Advertencia: Para poder usar el EFDatos creado, a través de los métodos: ActualizarEFDatos y LeerEFDatos, debe de existir un EFsc sobre el mismo DF de trabajo, ya que sino, nunca se podrán cumplir las Condiciones de Acceso impuestas para este EFDatos. Aclaración: La diferencia entre escribir y actualizar un EF, es la siguiente: • Escribir datos es: hacer la OR de los datos que hay en la memoria y los datos que se introducen. • Actualizar datos es: poner en la memoria directamente los datos que se introducen, machacando los datos que había antes. Formato: TarIn_Error 36
CrearEFDatos ( WORD16 Id_EF, WORD16 Tamanyo ); Parámetros de entrada: Id_EF
Identificador que se quiere para el EFDatos a crear.
Tamanyo
Tamaño del EFDatos en bytes. El tamaño estará comprendido entre 1 y 255 bytes. Una vez creado el EFDatos, no se podrá modificar su tamaño.
Valor retornado: Si no se produce ningún error al crear el EFDatos, se devolverá TarIn_NO_ERROR. En el caso de que exista ya un EF con el mismo identificador, se devolverá TarIn_YA_EXISTE y si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, actualiza los datos que hay en un EFDatos específico. Se debe de estar trabajando sobre el DF donde este el EFDatos. No es necesario que el EFDatos este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Este método, funcionará siempre que las Condiciones de Acceso del Grupo uno (Actualizar datos), del EFDatos, sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFDatos actualizado. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al actualizar el EFDatos y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Aclaración: La diferencia entre escribir y actualizar un EF, es la siguiente: • Escribir datos es: hacer la OR de los datos que hay en la memoria y los datos que se introducen. • Actualizar datos es: poner en la memoria directamente los datos que se introducen, machacando los datos que había antes. Formato: TarIn_Error ActualizarEFDatos ( WORD16 Id_EF, BYTE *Datos, WORD16 Tamanyo ); Parámetros de entrada: 37
Id_EF
Identificador del EFDatos a actualizar.
Datos
Contiene los datos que se quieren guardar en el EFDatos.
Tamanyo
Número de bytes que se cogerán de Datos y se guardarán en el EFDatos, este número estará comprendido entre 1 y 255 bytes.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En el caso de que el número de bytes a guardar, superen a los que puede almacenar el EFDatos, se devolverá TarIn_LONGITUD_NO_VALIDA, si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, lee los datos que hay en un EFDatos específico. Se debe de estar trabajando sobre el DF donde este el EFDatos. No es necesario que el EFDatos este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Este método, funcionará siempre que las Condiciones de Acceso del Grupo tres (Leer datos), del EFDatos, sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFDatos leído. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al leer el EFDatos y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Formato: TarIn_Error LeerEFDatos ( WORD16 Id_EF, BYTE *Datos, WORD16 *Tamanyo ); Parámetros de entrada: Id_EF
Identificador del EFDatos del que se quiere leer.
Tamanyo
Número de bytes que se quieren leer del EFDatos, valor comprendido entre 0 y 255 bytes. El valor de 0 significa que se leerán todo los datos del EFDatos.
Parámetros de salida: Datos
Contiene los datos que se han leído del EFDatos. Usar un array de BYTE x[255] (valor máximo que se puede recibir).
Tamanyo
Número de bytes leídos del EFDatos, valor comprendido entre 1 y 255. 38
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método crea un EFRSA, sobre el DF en el que se esta trabajando. Antes de crear el EFRSA, este método, mira si existe ya un EF con el mismo identificador. Si no se cumple esta condición, se creará un EFRSA con las siguientes Condiciones de Acceso: Grupo 1: Actualizar los datos de un registro del EFRSA. • Protección : Acceso Libre (los demás campos ya no importan). • Identificador del EF 3DES : − • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : − • Numero del Código Secreto C1 : − • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − Grupo 2: Añadir un registro en el EFRSA. • Protección : Acceso Libre (los demás campos ya no importan). • Identificador del EF 3DES : − • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : − • Numero del Código Secreto C1 : − • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − Grupo 3: Leer los datos de un registro del EFRSA. • Protección : Protegido con el Código de Acceso C1. • Identificador del EF 3DES : No es necesario, generar una Clave de Sesión para cumplir las Condiciones de Acceso. • Nivel del EF 3DES : − • Nivel del EFsc para el Código 1 : Local • Numero del Código Secreto C1 : 4 • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − El EFRSA creado, sólo tendrá la siguiente información almacenada en su interior, dejando para otros métodos (CargarPartePublicaRSA y CargarPartePrivadaRSA) la carga de la clave RSA: • Protección contra el uso : Protegido con el Código de Acceso C1.
39
• Nivel del EFsc para el Código 1 : Local • Numero del Código Secreto C1 : 5 • Nivel del EFsc para el Código 2 : − • Numero del Código Secreto C2 : − • Tipo de clave : RSA. • Uso de la clave RSA : Firmar y desempaquetar envoltorios digitales. • Clave Certificada : Si. • Longitud de la Clave RSA : La indica por Tipo_RSA. Si todo fue bien, al salir de este método, no se modificará el DF de trabajo y pasará a estar seleccionado el EFRSA creado. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, se llamará al método SeleccionarMF y se modificarán las variables: MiError y UltimoError, que contendrán el error producido al crear el EFRSA y no el que pueda producir la llamada al método SeleccionarMF. Si se produce un error, puede ocurrir que el EFRSA haya sido ya creado. En tal caso, no estará totalmente inicializado y por lo tanto será inservible, por lo que internamente se llamará al método BloquearGrupoDeAccesoEF y se bloquearán los tres Grupos de Acceso del EFRSA, no permitiendo que los métodos: CargarPartePublicaRSA y CargarPartePrivadaRSA puedan cargar la clave RSA en el EFRSA. Y por consiguiente, los métodos: LeerPartePublicaRSA, FirmaDelDocumento, VerificarFirma, CalcularHash y CifrarDatosConPrivada produzcan un error. Advertencia: Para poder usar el EFRSA creado, a través de los métodos: CargarPartePublicaRSA, CargarPartePrivadaRSA, LeerPartePublicaRSA, FirmaDelDocumento, VerificarFirma, CifrarDatosConPrivada y CalcularHash, debe de existir un EFsc sobre el mismo DF de trabajo, ya que sino, nunca se podrán cumplir las Condiciones de Acceso impuestas para este EFRSA. Aclaración: La protección contra el uso, significa: que para poder usar este EFRSA, con los métodos: FirmaDelDocumento, VerificarFirma, CifrarDatosConPrivada y CalcularHash, se debe de cumplir con las Condiciones de Uso indicadas. Formato: TarIn_Error CrearEFRSA ( WORD16 Id_EF, t_Clave_RSA Tipo_RSA ); Parámetros de entrada: Id_EF
Identificador que se quiere para el EFRSA a crear.
Tipo_RSA
Tipo de la clave RSA que se quiere almacenar en este EFRSA. Puede tener uno de estos valores:
40
• RSA_1024. El EFRSA se usará para guardar una clave RSA de 1024 bits. • RSA_768. El EFRSA se usará para guardar una clave RSA de 768 bits. • RSA_512. El EFRSA se usará para guardar una clave RSA de 512 bits. Valor retornado: Si no se produce ningún error al crear el EFRSA, se devolverá TarIn_NO_ERROR. En caso de que exista ya un EF con el mismo identificador, se devolverá TarIn_YA_EXISTE y si se produce algún otro error, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, carga la parte Pública de una clave RSA, en un EFRSA indicado. Esta parte Pública esta compuesta por el Módulo (P Q) y el Exponente Público (V) de la clave RSA. Se debe de estar trabajando sobre el DF donde este el EFRSA. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Antes de cargar la parte Pública de la clave RSA en el EFRSA, se comprueba que la clave RSA que se quiere cargar y el EFRSA elegido (ver en CrearEFRSA, el parámetro de entrada Tipo_RSA), tienen el mismo tipo de clave RSA. Este método, funcionará siempre que las Condiciones de Acceso del Grupo uno (Actualizar los datos de un registro) y Grupo tres (Leer datos de un registro), del EFRSA, sean cumplidas. Se puede usar tantas veces como se quiera este método, sobre un mismo EFRSA, incluso con diferentes tamaños para el Exponente Público, siempre que se cumplan las Condiciones de Acceso anteriores.
Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA sobre el que se ha cargado la parte Pública de la clave RSA. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al cargar la parte Pública de la clave RSA en el EFRSA y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Formato: TarIn_Error CargarPartePublicaRSA ( WORD16 Id_EF_RSA, t_Clave_RSA Tipo_RSA, BYTE *Modulo, BYTE *ExponentePublico WORD16 LongitudExponente ); 41
Parámetros de entrada: Id_EF_RSA
Identificador del EFRSA donde se guardara la parte Pública de la clave RSA. Tipo de la clave RSA que se quiere guardar en el EFRSA. Puede tener uno de estos valores:
Tipo_RSA
• RSA_1024. La parte Pública de la clave RSA a cargar, pertenece a una clave RSA de 1024 bits. • RSA_768. La parte Pública de la clave RSA a cargar, pertenece a una clave RSA de 768 bits. • RSA_512. La parte Pública de la clave RSA a cargar, pertenece a una clave RSA de 512 bits.
Modulo
Contiene el Módulo (P Q) de la parte Pública de la clave RSA a cargar. Usar un array de BYTE x[128] si la clave RSA es de 1024 bits, de BYTE x[96] si la clave RSA es de 768 bits o de BYTE x[64] si la clave RSA es de 512 bits.
ExponentePublico
Contiene el Exponente Público (V) de la clave RSA a cargar.
LongitudExponente
Longitud en bytes de ExponentePublico. El valor para este parámetro estará comprendido entre 3 y 128 (ambos inclusive).
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, lee la parte Pública de una clave RSA, de un EFRSA indicado. Esta parte Pública esta compuesta por el Módulo (P Q) y el Exponente Público (V) de la clave RSA. Se debe de estar trabajando sobre el DF donde este el EFRSA. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Este método, funcionará siempre que las Condiciones de Acceso del Grupo tres (Leer datos de un registro) del EFRSA sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA donde se leyó la parte Pública de la clave RSA. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al leer la parte Pública de la clave RSA en el EFRSA y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Formato: TarIn_Error LeerPartePublicaRSA ( WORD16 Id_EF_RSA, 42
BYTE *Modulo, WORD16 *LongitudModulo, BYTE *ExponentePublico, WORD16 *LongitudExponente ); Parámetro de entrada: Id_EF_RSA
Identificador del EFRSA del que se quiere leer la parte Pública de la clave RSA, almacenada en él.
Parámetros de salida:
Modulo
Módulo (P Q) de la parte Pública de la clave RSA leída. Usar un array de BYTE x[128] (valor máximo que se puede recibir). Longitud en bytes de Modulo. Sólo podrá tomar uno de estos valores:
LongitudModulo
• 128. Indicando que la parte Pública de la clave RSA leída, pertenece a una clave RSA de 1024 bits. • 96. Indicando que la parte Pública de la clave RSA leída, pertenece a una clave RSA de 768 bits. • 64. Indicando que la parte Pública de la clave RSA leída, pertenece a una clave RSA de 512 bits.
ExponentePublico
Exponente Público (V) de la clave RSA leída. Usar un array de BYTE x[128] (valor máximo que se puede recibir).
LongitudExponente
Longitud en bytes de ExponentePublico. El valor para este parámetro estará comprendido entre 3 y 128 (ambos inclusive).
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, carga la parte Privada de una clave RSA, en un EFRSA indicado. Esta parte Privada está compuesta por el Exponente Privado (S) de la clave RSA. Se debe de estar trabajando sobre el DF donde este el EFRSA. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Con el formato de Exponente Privado, los métodos FirmaDelDocumento, CifrarDatosConPrivada y CalcularHash, se ejecutarán más despacio, que si tuviera el formato CRT (apenas se nota la diferencia), pero ocupa un 60% menos de memoria. Antes de cargar la parte Privada de la clave RSA en el EFRSA, se comprueba que la clave RSA que se quiere cargar y el EFRSA elegido (ver en CrearEFRSA, el parámetro de entrada Tipo_RSA), tienen el mismo tipo de clave RSA.
43
Este método, funcionará siempre que las Condiciones de Acceso del Grupo uno (Actualizar los datos de un registro), Grupo dos (Añadir un registro) y Grupo tres (Leer datos de un registro), del EFRSA, sean cumplidas. Una vez, guardada la parte Privada de la clave RSA en el EFRSA, internamente se llamará al método BloquearGrupoDeAccesoEF, para bloquear el Grupo de Acceso uno: prohibiendo modificar la clave RSA. Y el Grupo de Acceso dos: prohibiendo añadir nuevos registros. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA sobre el que se ha cargado la parte Privada de la clave RSA. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al cargar la parte Privada de la clave RSA en el EFRSA y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Si se produce un error, el EFRSA no tendrá totalmente creada la parte Privada de la clave RSA y por lo tanto será inservible, por lo que internamente se llamará al método BloquearGrupoDeAccesoEF y se bloquearán los tres Grupos de Acceso del EFRSA, produciendo que los métodos: LeerPartePublicaRSA, FirmaDelDocumento, VerificarFirma, CalcularHash y CifrarDatosConPrivada produzcan un error. Advertencia: Una vez ejecutado este método, no se podrá cargar la parte Pública de la clave RSA (ver el método CargarPartePublicaRSA), por eso, si se quiere almacenar tanto la parte Pública como la Privada, se debe de cargar primero la parte Pública de la clave RSA y luego la Privada. Formato: TarIn_Error CargarPartePrivadaRSA ( WORD16 Id_EF_RSA, t_Clave_RSA Tipo_RSA, BYTE *ExponentePrivado ); Parámetros de entrada: Id_EF_RSA
Identificador del EFRSA donde se guardará la parte Privada de la clave RSA. Tipo de la clave RSA que se quiere guardar en el EFRSA. Puede tener uno de estos valores:
Tipo_RSA
ExponentePrivado
• RSA_1024. La parte Privada de la clave RSA a cargar, pertenece a una clave RSA de 1024 bits. • RSA_768. La parte Privada de la clave RSA a cargar, pertenece a una clave RSA de 768 bits. • RSA_512. La parte Privada de la clave RSA a cargar, pertenece a una clave RSA de 512 bits. Contiene el Exponente Privado (S) de la clave RSA a cargar. 44
Usar un array de BYTE x[128] si la clave RSA es de 1024 bits, de BYTE x[96] si la clave RSA es de 768 bits o de BYTE x[64] si la clave RSA es de 512 bits. Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, carga la parte Privada de una clave RSA, en un EFRSA indicado. Esta parte Privada esta compuesta por el CRT de la clave RSA. Se debe de estar trabajando sobre el DF donde este el EFRSA. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Con el formato CRT, los métodos FirmaDelDocumento, CifrarDatosConPrivada y CalcularHash, se ejecutarán más rápido, que si tuviera el formato de Exponente Privado (apenas se nota la diferencia), pero ocupa un 60% más memoria. Antes de cargar la parte Privada de la clave RSA en el EFRSA, se comprueba que la clave RSA que se quiere cargar y el EFRSA elegido (ver en CrearEFRSA, el parámetro de entrada Tipo_RSA), tienen el mismo tipo de clave RSA. Este método, funcionará siempre que las Condiciones de Acceso del Grupo uno (Actualizar los datos de un registro), Grupo dos (Añadir un registro) y Grupo tres (Leer datos de un registro), del EFRSA, sean cumplidas. Una vez guardá la parte Privada de la clave RSA en el EFRSA, internamente se llamará al método BloquearGrupoDeAccesoEF, para bloquear el Grupo de Acceso uno: prohibiendo modificar la clave RSA. Y el Grupo de Acceso dos: prohibiendo añadir nuevos registros. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA sobre el que se ha cargado la parte Privada de la clave RSA. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al cargar la parte Privada de la clave RSA en el EFRSA y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Si se produce un error, el EFRSA no tendrá totalmente creada la parte Privada de la clave RSA y por lo tanto será inservible, por lo que internamente se llamará al método BloquearGrupoDeAccesoEF y se bloquearán los tres Grupos de Acceso del EFRSA, produciendo que los métodos: LeerPartePublicaRSA, FirmaDelDocumento, VerificarFirma, CalcularHash y CifrarDatosConPrivada produzcan un error. Advertencia: Una vez ejecutado este método, no se podrá cargar la parte Pública de la clave RSA (ver el método CargarPartePublicaRSA), por eso, si se quiere almacenar tanto la parte Pública como la Privada, se debe de cargar primero la parte Pública de la clave RSA y luego la Privada. Aclaración: El formato CRT, consiste en cinco parámetros (S es el Exponente Privado): 45
• Primer número Primo ( P ). • Segundo número Primo ( Q ). • Coeficiente ( Q mod P ). • Primer Exponente ( S mod (P−1) ). • Segundo Exponente ( S mod (Q−1) ). Formato: TarIn_Error CargarPartePrivadaRSA ( WORD16 Id_EF_RSA, t_Clave_RSA Tipo_RSA, BYTE *PrimerPrimo, BYTE *SegundoPrimo, BYTE *Coeficiente, BYTE *PrimerExponente, BYTE *SegundoExponente ); Parámetros de entrada: Id_EF_RSA
Identificador del EFRSA donde se guardará la parte Privada de la clave RSA. Tipo de la clave RSA que se quiere guardar en el EFRSA. Puede tener uno de estos valores:
Tipo_RSA
• RSA_1024. La parte Privada de la clave RSA a cargar, pertenece a una clave RSA de 1024 bits. • RSA_768. La parte Privada de la clave RSA a cargar, pertenece a una clave RSA de 768 bits. • RSA_512. La parte Privada de la clave RSA a cargar, pertenece a una clave RSA de 512 bits.
PrimerPrimo
Contiene el Primer número Primo ( P ) de la clave RSA a cargar. Usar un array de BYTE x[64] si la clave RSA es de 1024 bits, de BYTE x[48] si la clave RSA es de 768 bits o de BYTE x[32] si la clave RSA es de 512 bits.
SegundoPrimo
Contiene el Segundo número Primo ( Q ) de la clave RSA a cargar. Usar un array de BYTE x[64] si la clave RSA es de 1024 bits, de BYTE x[48] si la clave RSA es de 768 bits o de BYTE x[32] si la clave RSA es de 512 bits.
Coeficiente
Contiene el Coeficiente ( Q mod P ) de la clave RSA a cargar. Usar un array de BYTE x[64] si la clave RSA es de 1024 bits, de BYTE x[48] si la clave RSA es de 768 bits o de BYTE x[32] si la clave RSA es de 512 bits. 46
PrimerExponente
Contiene el Primer Exponente ( S mod (P−1) ) de la clave RSA a cargar. Usar un array de BYTE x[64] si la clave RSA es de 1024 bits, de BYTE x[48] si la clave RSA es de 768 bits o de BYTE x[32] si la clave RSA es de 512 bits.
SegundoExponente
Contiene el Segundo Exponente ( S mod (Q−1) ) de la clave RSA a cargar. Usar un array de BYTE x[64] si la clave RSA es de 1024 bits, de BYTE x[48] si la clave RSA es de 768 bits o de BYTE x[32] si la clave RSA es de 512 bits.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método crea un EFRSA y almacena en él una clave RSA. Dicha clave RSA (tanto parte Privada, como Pública) se genera dentro de la Tarjeta Inteligente y sólo se podrá obtener de la clave RSA generada, la parte Pública, usando el método LeerPartePublicaRSA. Para la creación del EFRSA, se llamará internamente al método CrearEFRSA (ver este método para saber la configuración que tendrá el EFRSA creado). Una vez creado el EFRSA, se pasará a la generación de la clave RSA. Esta operación, tardará aproximadamente unos 12 segundos en generar una clave RSA de 1024 bits y 7 en una de 512 bits. Todas las claves generadas por este método, tendrán como Exponente Público el siguiente valor: 0x01 0x00 0x01 y en la parte Privada tendrá el formato CRT. Una vez generada y guarda la clave RSA en el EFRSA, internamente se llamará al método BloquearGrupoDeAccesoEF, para bloquear el Grupo de Acceso uno: prohibiendo modificar la clave RSA. Y el Grupo de Acceso dos: prohibiendo añadir nuevos registros. Si todo fue bien, al salir de este método, no se modificará el DF de trabajo y pasará a estar seleccionado el EFRSA sobre el que se ha generado la clave RSA. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, se llamará al método SeleccionarMF y se modificarán las variables: MiError y UltimoError, que contendrán el error producido al generar o cargar la clave RSA en el EFRSA y no el que pueda producir la llamada al método SeleccionarMF. Si se produce un error, puede ocurrir que el EFRSA haya sido ya creado. En tal caso, no estará totalmente inicializado y por lo tanto será inservible, por lo que internamente se llamará al método BloquearGrupoDeAccesoEF y se bloquearán los tres Grupos de Acceso del EFRSA, produciendo que los métodos: LeerPartePublicaRSA, FirmaDelDocumento, VerificarFirma, CalcularHash y CifrarDatosConPrivada produzcan un error. Advertencia: Este método no genera claves RSA de 768 bits. Formato: TarIn_Error 47
GenerarClaveRSA ( WORD16 Id_EF, t_Clave_RSA Tipo_RSA ); Parámetros de entrada: Identificador que se quiere para el EFRSA a crear y donde se almacenará la clave RSA generada.
Id_EF
Tipo de la clave RSA que se quiere generar y almacenar en el EFRSA. Puede tener uno de estos valores: • RSA_1024. Se creará un EFRSA para contener una clave RSA de 1024 bits y se generará y guardará en él, una clave RSA de 1024 bits. • RSA_512. Se creará un EFRSA para contener una clave RSA de 512 bits y se generará y guardará en él, una clave RSA de 512 bits.
Tipo_RSA
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, calcula la firma digital de unos datos dados. Primero se realiza el hash de los datos y luego se cifra el resultado obtenido, con la parte Privada de la clave RSA que hay en un EFRSA indicado. Se debe de estar trabajando sobre el DF donde este el EFRSA. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. El tamaño máximo de los datos a firmar, debe ser de 2 Mb (2.097.152 bytes). La siguiente tabla, muestra el tiempo aproximado, que tardará este método en devolver el control al usuario. Estas pruebas han sido realizadas usando el algoritmo hash MD5 y un relleno PKCS#1 v1.5. El tipo de clave RSA usada, no modifica casi nada el tiempo de espera. Velocidad
Tiempo
del puerto 38.400 bps 9.600 bps 38.400 bps 9.600 bps 38.400 bps 9.600 bps
de espera 44 sg 58 sg 19 sg 32 sg 7 sg 10 sg
Tamaño 16.384 bytes 16.384 bytes 8.192 bytes 8.192 bytes 4.096 bytes 4.096 bytes
Este método, funcionará siempre que las Condiciones de Acceso del Grupo tres (leer datos de un registro) y las Condiciones de Uso, del EFRSA, sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA usado para generar la firma. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. 48
Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al generar la firma y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Advertencia: La siguiente combinación no es valida: HASH_MD5 y RELLENO_ISO_9976_2. Formato: TarIn_Error FirmaDelDocumento ( WORD16 Id_EF_RSA, BYTE *Datos, WORD32 LongitudDatos, BYTE *Firma, WORD16 *LongitudFirma, t_TipoHash TipoHash = HASH_MD5, t_TipoRelleno TipoRelleno = RELLENO_PKCS_1 ); Parámetros de entrada: Id_EF_RSA,
Identificador del EFRSA que tiene la parte Privada de la clave RSA, con la que se firmara el Hash.
Datos
Contiene los datos, sobre los que se quiere obtener la firma digital.
LongitudDatos
Número de bytes de Datos, sobre los que se quiere obtener la firma. El rango de valores, para este parámetro es de: 1 − 2 Mb (2.097.152 bytes). Indica el tipo de algoritmo hash a usar. Puede tener uno de estos valores:
TipoHash
• HASH_MD5. El algoritmo que se usará para obtener el hash será el MD5. • HASH_SHA_1. El algoritmo que se usará para obtener el hash será el SHA−1. Valor por defecto: HASH_MD5.
TipoRelleno
Indica el tipo de relleno a usar. Puede tener uno de estos valores: • RELLENO_PKCS_1. El relleno que se usará para obtener la firma será el PKCS#1 versión 1.5. • RELLENO_ANSI_9_31. El relleno que se usará para obtener la firma será el ANSI X9.31.
49
• RELLENO_ISO_9976_2. El relleno que se usará para obtener la firma será el ISO9792−2. Valor por defecto: RELLENO_PKCS_1. Parámetros de salida: Contiene la firma de Datos. Usar un array de BYTE x[128] (valor máximo que se puede recibir).
Firma
Longitud en byte de Firma. Solo podrá tomar uno de estos valores: • 128. Indica que la clave RSA usada para generar Firma, era de 1024 bits. • 96. Indica que la clave RSA usada para generar la Firma, era de 768 bits. • 64. Indica que la clave RSA usada para generar la Firma, era de 512 bits.
LongitudFirma
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, verifica que la firma digital dada, pertenece a unos datos también dados. Primero se realiza el hash de los datos, luego se descifra la firma digital, con la parte Pública de la clave RSA que hay en un EFRSA indicado y por último, se comparan ambos resultados, si son iguales, la firma digital quedara verificada. Se debe de estar trabajando sobre el DF donde este el EFRSA. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. El tamaño máximo de los datos sobre los que se supone se obtuvo la firma digital, debe ser de 2 Mb (2.097.152 bytes). La siguiente tabla, muestra el tiempo aproximado, que tardará este método en devolver el control al usuario. Estas pruebas han sido realizadas usando el algoritmo hash MD5 y un relleno PKCS#1 v1.5. El tipo de clave RSA usada, no modifica casi nada el tiempo de espera. Velocidad
Tiempo
del puerto 38.400 bps 9.600 bps 38.400 bps 9.600 bps 38.400 bps 9.600 bps
de espera 44 sg 58 sg 19 sg 32 sg 7 sg 10 sg
Tamaño 16.384 bytes 16.384 bytes 8.192 bytes 8.192 bytes 4.096 bytes 4.096 bytes
Antes de verificar la firma digital, se comprueba que la longitud de la firma digital, coincide con el tipo de clave RSA almacenada en el EFRSA elegido (ver en CrearEFRSA, el parámetro de entrada Tipo_RSA).
50
Este método, funcionará siempre que las Condiciones de Acceso del Grupo tres (leer datos de un registro) y las Condiciones de Uso, del EFRSA, sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA usado para verificar la firma. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al verificar la firma y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Advertencia: La siguiente combinación no es válida: HASH_MD5 y RELLENO_ISO_9976_2. Formato: TarIn_Error VerificarFirma ( WORD16 Id_EF_RSA, BYTE *Datos, WORD32 LongitudDatos, BYTE *Firma, WORD16 LongitudFirma, t_TipoHash TipoHash = HASH_MD5, t_TipoRelleno TipoRelleno = RELLENO_PKCS_1 ); Parámetros de entrada: Id_EF_RSA,
Identificador del EFRSA que tiene la parte Pública de la clave RSA, con la que se verificará Firma.
Datos
Contiene los datos, sobre los que se supone se obtuvo Firma.
LongitudDatos
Número de bytes de Datos, sobre los que se supone se obtuvo Firma. El rango de valores, para este parámetro es de: 1 − 2 Mb (2.097.152 bytes).
Firma
Contiene la firma digital que se quiere verificar. Usar un array de BYTE x[128] si la clave RSA usada para obtener Firma era de 1024 bits, de BYTE x[96] si la clave RSA es de 768 bits o de BYTE x[64] si la clave RSA es de 512 bits.
LongitudFirma
Longitud en byte de Firma. Puede tener uno de estos valores: • 128. Indica que la clave RSA usada para obtener Firma era de 1024 bits. • 96. Indica que la clave RSA usada para obtener Firma era de 768 bits.
51
• 64. Indica que la clave RSA usada para obtener Firma era de 512 bits. Indica el tipo de algoritmo hash usado para obtener Firma. Puede tener uno de estos valores: • HASH_MD5. El algoritmo usado era el MD5. • HASH_SHA_1. El algoritmo usado era el SHA−1.
TipoHash
Valor por defecto: HASH_MD5. Indica el tipo de relleno usado para obtener Firma. Puede tener uno de estos valores: • RELLENO_PKCS_1. El relleno usado era el PKCS#1 versión 1.5. • RELLENO_ANSI_9_31. El relleno usado era el ANSI X9.31. • RELLENO_ISO_9976_2. El relleno usado era el ISO9792−2.
TipoRelleno
Valor por defecto: RELLENO_PKCS_1. Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de que falle la verificación, se devolverá TarIn_VERIFICACION_ERRONEA, si sé produce algún otro error, se devolverá el tipo de error producido, si esté no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, calcula el hash de unos datos dados. La Tarjeta Inteligente GPK 8000, no incorpora ninguna función para calcular ningún tipo de hash directamente, sólo se puede conseguir un hash, engañándola. Dicho engaño se basa en que la Tarjeta Inteligente, al verificar una firma digital, devuelve el hash de los datos, siempre que la verificación fuera correcta (ver VerificarFirma para entender mejor esta operación). El calculo del hash se realiza de la siguiente forma: se calcular la firma digital (internamente se llama al método FirmaDeDocumento) y se manda a la Tarjeta Inteligente para que verifique dicha firma, como la firma será correcta, devolverá el hash de los datos. Esta forma de calcular un hash, tiene un inconveniente y un problema. El inconveniente es que se necesita una clave RSA para poder calcular un hash, cosa que no debería ser necesaria y el problema es el tiempo que se tarda en ejecutarse este método (ver tabla). Antes de llamar a este método, se debe de estar trabajando sobre el DF donde este el EFRSA, que usaremos para realizar la trampa. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. El tamaño máximo de los datos para realizar el hash, debe ser de 2 Mb (2.097.152 bytes). La siguiente tabla, muestra el tiempo aproximado, que tardara este método en devolver el control al usuario. Estas pruebas han sido realizadas usando el algoritmo hash MD5. El tipo de clave RSA usada, no modifica casi nada el tiempo de espera. Velocidad
Tiempo
del puerto 38.400 bps
de espera 88 sg
Tamaño 16.384 bytes
52
16.384 bytes 8.192 bytes 8.192 bytes 4.096 bytes 4.096 bytes
9.600 bps 38.400 bps 9.600 bps 38.400 bps 9.600 bps
116 sg 38 sg 64 sg 14 sg 20 sg
Este método, funcionará siempre que las Condiciones de Acceso del Grupo tres (leer datos de un registro) y las Condiciones de Uso, del EFRSA, sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA usado para hacer la trampa. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al realizar el hash y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Formato: TarIn_Error CalcularHash ( WORD16 Id_EF_RSA, BYTE *Datos, WORD32 LongitudDatos, BYTE *Hash, WORD16 *LongitudHash, t_TipoHash TipoHash = HASH_MD5 ); Parámetros de entrada:
Id_EF_RSA,
Identificador del EFRSA para realizar la trampa. Este EFRSA tiene que tener tanto la parte Pública como la Privada de una clave RSA. El tamaño de la clave RSA no tendrá importancia.
Datos
Contiene los datos, sobre los que se quiere obtener el hash.
LongitudDatos
Número de bytes de Datos, sobre los que se quiere obtener el hash. El rango de valores, para este parámetro es de: 1 − 2 Mb (2.097.152 bytes). Indica el tipo de algoritmo hash a usar. Puede tener uno de estos valores:
TipoHash
• HASH_MD5. El algoritmo que se usará para obtener la hash será el MD5. • HASH_SHA_1. El algoritmo que se usará para obtener la hash será el SHA−1. Valor por defecto: HASH_MD5. 53
Parámetros de salida: Hash
Contiene el hash de Datos. Usar un array de BYTE x[20] (valor máximo que se puede recibir) Longitud en byte de Hash. Sólo podrá tomar uno de estos valores:
LongitudHash
• 20. Indica que el algoritmo hash usado era el SHA−1. • 16. Indica que el algoritmo hash usado era el MD5.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, cifra unos datos dados, con la parte Privada de la clave RSA que hay en un EFRSA indicado. Se debe de estar trabajando sobre el DF donde este el EFRSA. No es necesario que el EFRSA este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Esta función tiene un inconveniente y es que sólo se podrán cifrar datos con unas longitudes determinadas (36, 20 o 16 bytes). Otra pega, es que la Tarjeta Inteligente GPK 8000 no incorpora ninguna función para desencriptar, teniendo que recurrir para realizar esta operación, a un código externo a este. Este método, funcionará siempre que las Condiciones de Acceso del Grupo tres (leer datos de un registro) y las Condiciones de Uso, del EFRSA, sean cumplidas. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EFRSA usado para cifrar los datos. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al cifrar los datos y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Advertencia: Este método no acepta el uso del relleno ISO9792−2 (RELLENO_ISO_9976_2). Formato: TarIn_Error CifrarDatosConPrivada ( WORD16 Id_EF_RSA, BYTE *Datos, WORD32 LongitudDatos, BYTE *DatosCifrados, WORD16 *LongitudDatosCifrados,
54
t_TipoRelleno TipoRelleno = RELLENO_PKCS_1 ); Parámetros de entrada: Id_EF_RSA,
Identificador del EFRSA que tiene la parte Privada de la clave RSA, con la que se cifraran los datos.
Datos
Contiene los datos que se quieren cifrar.
LongitudDatos
Numero de bytes de Datos que se quieren cifrar. Solo podrá tener uno de estos valores: 36, 20 o 16. Indica el tipo de relleno a usar. Puede tener uno de estos valores:
TipoRelleno
• RELLENO_PKCS_1. El relleno que se usará para obtener la firma será el PKCS#1 versión 1.5. • RELLENO_ANSI_9_31. El relleno que se usará para obtener la firma será el ANSI X9.31. Valor por defecto: RELLENO_PKCS_1.
Parámetros de salida: DatosCifrados
Contiene los datos cifrados de Datos. Usar un array de BYTE x[128] (valor máximo que se puede recibir) Longitud en byte de DatosCifrados. Solo podrá tomar uno de estos valores:
LongitudDatosCifrados
• 128. Indica que la clave RSA usada era de 1024 bits. • 96. Indica que la clave RSA usada era de 768 bits. • 64. Indica que la clave RSA usada era de 512 bits.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método mide el tamaño en bytes de un EF. Se debe de estar trabajando sobre el DF donde este el EF. No es necesario que el EF este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Para este método las Condiciones de Acceso al EF, no son tenidas en cuenta. Aunque el EF tenga bloqueados los tres Grupos de Acceso, este método seguirá funcionando igual. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EF medido. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al medir el EF y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Aclaración:
55
Este método puede ser usado sobre cualquier tipo de EF (EFsc, EFDatos o EFRSA). Formato: TarIn_Error LongitudEF ( WORD16 Id_EF, WORD16 *Tamanyo ); Parámetro de entrada: Id_EF
Identificador del EF, del que se quiere saber su tamaño.
Parámetro de salida: Tamaño del EF en bytes. En la siguiente lista se tiene la correspondencia entre tipo de EF y su tamaño:
Tamanyo
• EFsc: El tamaño será siempre de 64 bytes. • EFDatos: El tamaño será con el que fue creado el EFDatos y estará entre 1 y 255 bytes. • EFRSA: Dependerá del tipo de la clave RSA con el que fue creado el EFRSA: • RSA_1024: el tamaño será siempre de 268 bytes (Este tamaño sólo es de la parte Pública de la clave RSA). • RSA_768: el tamaño será siempre de 204 bytes (Este tamaño sólo es de la parte Pública de la clave RSA) • RSA_512: el tamaño será siempre de 140 bytes (Este tamaño sólo es de la parte Pública de la clave RSA).
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, bloquea uno o varios Grupos de Acceso de un EF determinado. Se debe de estar trabajando sobre el DF donde esté el EF. No es necesario que el EF a bloquear este previamente seleccionado, tampoco pasará nada si hay otro EF seleccionado. Si todo fue bien, al salir de este método, pasará a estar seleccionado el EF bloqueado. En tal caso las siguientes variables públicas serán modificadas: UltimoError indicando que no se ha producido ningún error y Grupo1, Grupo2 y Grupo3, que contienen las Condiciones de Acceso al fichero seleccionado. Y las variables privadas: Nivel y MiError. Si se produce algún error, las variables modificadas serán: MiError y UltimoError, que contendrán el error producido al intentar bloquear el EF y se mantendrá el DF de trabajo. Siendo el último fichero seleccionado, indeterminado. Aclaración: Este método puede ser usado sobre cualquier tipo de EF (EFsc, EFDatos o EFRSA). 56
Advertencia: Una vez bloqueado un Grupo de Acceso, no se podrá desbloquear. Formato: TarIn_Error BloquearGrupoDeAccesoEF ( WORD16 Id_EF, bool BloquearGrupo1 = false, bool BloquearGrupo2 = false, bool BloquearGrupo3 = false ); Parámetros de entrada: Id_EF
BloquearGrupo1
Identificador del EF, del que se quiere bloquear uno o varios Grupos de Acceso. Indica si se quiere bloquear el Grupo de Acceso uno del EF (true) o por lo contrario se dejará como estaba (false). Valor por defecto: false.
BloquearGrupo2
Indica si se quiere bloquear el Grupo de Acceso dos del EF (true) o por lo contrario se dejará como estaba (false). Valor por defecto: false.
BloquearGrupo3
Indica si se quiere bloquear el Grupo de Acceso tres del EF (true) o por lo contrario se dejará como estaba (false). Valor por defecto: false.
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, manda generar un número aleatorio a la Tarjeta Inteligente. Formato: TarIn_Error GenerarNumeroAleatorio ( bool TipoNumero, BYTE *Numero ); Parámetro de entrada:
57
Indica el tipo de número aleatorio a generar. Puede tener uno de estos valores: • false. Generará un número aleatorio de 8 bytes, siguiendo la norma ISO 7816−4/EMV. • true. Generará un número aleatorio de 32 bytes, siguiendo una norma interna de Gemplus.
TipoNumero
Parámetro de salida:
Numero
Contiene el número aleatorio generado por la Tarjeta Inteligente. Usar un array de BYTE x[32] (valor máximo que se puede recibir).
Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. Este método, borra toda la memoria de la Tarjeta Inteligente, dejando sólo los ficheros del sistema. Puede ser llamado desde cualquier punto de la jerarquía de ficheros. Antes de salir de este método, se llamará al método SeleccionarMF (aunque no se haya producido un error). En el caso de producirse un error, las variables: MiError y UltimoError, contendrán el error producido al intentar borrar la memoria de la Tarjeta Inteligente y no el que pueda producir la llamada al método SeleccionarMF. Advertencias: Una vez borrada la memoria, no se podrán recuperar los datos. Formato: TarIn_Error BorrarTarjeta ( void ); Valor retornado: Si no se produce ningún error, se devolverá TarIn_NO_ERROR. En caso de producirse, se devolverá el tipo de error producido. Si el error no ha sido definido en esta librería, se devolverá un error genérico (TarIn_ERROR). Para mayor información sobre el error producido, ver la variable UltimoError. TarIn_NO_ERROR
Todo ha ido como la seda.
TarIn_ERROR
Error genérico.
TarIn_NO_HAY_TARJETA
No hay una Tarjeta en el Lector.
TarIn_SESION_NO_INICIADA
No se ha iniciado una comunicación.
TarIn_CANAL_NO_CERRADO
El canal no ha sido cerrado correctamente antes. Llama al método Desconectar y vuelve a 58
conectar. TarIn_NO_SE_ENCONTRO
El DF o EF no se ha encontrado.
TarIn_FICHERO_NO_SELECCIONADO
El EF no existe o no ha sido seleccionado.
TarIn_YA_EXISTE
Existe un DF o EF con el mismo identificador, o algún DF con el mismo nombre.
TarIn_EF_NO_TIPO_EFDatos
El EF no es un EFDatos.
TarIn_EF_NO_TIPO_EFsc
El EF no es un EFsc.
TarIn_EF_NO_TIPO_EFRSA
El EF no es un EFRSA.
TarIn_ERROR_EN_EFRSA
Error interno en el EFRSA.
TarIn_HASH_Y_RELLENO_NO_VALIDOS
No es compatible el relleno ISO 9976−2 con el hash MD5.
TarIn_VERIFICACION_ERRONEA
La firma digital no corresponde con los datos dados (o viceversa).
TarIn_LONGITUD_NO_VALIDA
Longitud no valida.
TarIn_CODIGO_ERRONEO_QUEDAN_6
Código Secreto erróneo, quedan 6 intentos más, antes de que se bloquee.
TarIn_CODIGO_ERRONEO_QUEDAN_5
Código Secreto erróneo, quedan 5 intentos más, antes de que se bloquee.
TarIn_CODIGO_ERRONEO_QUEDAN_4
Código Secreto erróneo, quedan 4 intentos más, antes de que se bloquee.
TarIn_CODIGO_ERRONEO_QUEDAN_3
Código Secreto erróneo, quedan 3 intentos más, antes de que se bloquee.
TarIn_CODIGO_ERRONEO_QUEDAN_2
Código Secreto erróneo, quedan 2 intentos más, antes de que se bloquee.
TarIn_CODIGO_ERRONEO_QUEDAN_1
Código Secreto erróneo, sólo queda 1 intento más, antes de que se bloquee.
TarIn_BLOQUEADO
Código Secreto bloqueado o clave RSA bloqueada.
TarIn_CONDI_ACCE_NO_SATISFECHAS
Las Condiciones de Acceso no han sido satisfechas.
Vamos a ver, a través de una serie de ejemplos, como se usa la librería TarIn. En estos ejemplos, se dejará a un lado el tratamiento de los errores, pensando siempre que el método fue ejecutado correctamente. • Creación de una estructura de ficheros básica, para poder empezar a trabajar con la Tarjeta Inteligente. ... C_TarIn Tarjeta; Tarjeta.Conectar ( COM2 ); 59
Tarjeta.CrearDF ( 0x300, (BYTE*) Prueba1); Tarjeta.SeleccionarDF ( 0x300 ); bool GrabadoBien[8]; Tarjeta.CrearEFsc ( 0x301, &GrabadoBien, (BYTE*) 12345678, (BYTE*) HolaHola, (BYTE*) CODIGO_SECRETO_2, (BYTE*) Prueba22 ); // Vemos si todos los Códigos Secretos han sido grabados bien for ( int i = 0; i < 8; i++ ) { if (GrabadoBien[i] == false) { // Se supondrá que todos los Códigos han sido grabados bien Tarjeta.CargarCodigoSecreto ( 0x301, i , ... ); } } // Bloqueamos el EFsc para prohibir cargar nuevos Códigos Secretos o poder verlos Tarjeta.BloquearGrupoDeAccesoEF ( 0x301, true, true, true ); ... • Cambio, bloqueo y desbloqueo de un Código Secreto. ... // Se supondrá que se tiene creado la estructura de ficheros del ejemplo anterior C_TarIn Tarjeta; Tarjeta.Conectar ( ); Tarjeta.SeleccionarDF ( (BYTE*) Prueba1); Tarjeta.CambiarCodigoSecreto ( 0, (BYTE*) 12345678, (BYTE*) 87654321 );
60
// Bloqueamos el Código Secreto for (int i = 0; i < 5; i++) Tarjeta.VerificarCodigoSecreto ( 0, (BYTE*) 12345678); Tarjeta.DesbloquearCodigoSecreto (0, (BYTE*) CODIGO_SECRETO_7, (BYTE*) 12345678 ); ... • Creación y utilización de un EFDatos. ... // Se supondrá que se tiene creado la estructura de ficheros anterior C_TarIn Tarjeta; Tarjeta.Conectar ( COM2 ); Tarjeta.SeleccionarDF ( (BYTE*) Prue); Tarjeta.CrearEFDatos ( 0x302, 25 ); // Cumplimos la Condición de Acceso del Grupo 1, para poder actualizar el valor del EFDatos Tarjeta.VerificarCodigoSecreto ( 0, (BYTE*) 12345678 ); Tarjeta.ActualizarEFDatos ( 0x302, (BYTE*) Hola soy Javi, 14); //Cumplimos la Condición de Acceso del Grupo 3, para poder leer el EFDatos Tarjeta.VerificarCodigoSecreto ( 3, (BYTE*) Prueba22 ); BYTE Datos [ 255 ]; WORD16 Tamanyo = 0; Tarjeta.LeerEFDatos ( 0x302, Datos, &Tamanyo); printf (%s, Datos); // Imprimirar: Hola soy Javi Tarjeta.ActualizarEFDatos ( 0x302, (BYTE*) Como estas?, 12); Tarjeta.SeleccionarDF (0x300); // Error, Condiciones de Acceso no cumplidas Tarjeta.ActualizarEFDatos ( 0x302, (BYTE*) Hola soy Javi?, 12);
61
... • Creación de dos EFRSA, uno de forma manual y otra de forma automática. ... // Se supondrá que se tiene creado la estructura de ficheros del ejemplo anterior C_TarIn Tarjeta; Tarjeta.Conectar ( ); Tarjeta.SeleccionarDF ( 0x300 ); Tarjeta.GenerarClaveRSA ( 0x303, RSA_1024 ); Tarjeta.CrearEFRSA ( 0x304, RS_1024 ); //Cumplimos la Condición de Acceso del Grupo 3, para poder leer los EFRSA Tarjeta.VerificarCodigoSecreto ( 4, (BYTE*) CODIGO_SECRETO_4 ); BYTE Modulo [ 128 ]; WORD16 LongitudModulo; BYTE ExponentePublico [ 128 ]; WORD16 LongitudExponente; Tarjeta.LeerPartePublicaRSA ( 0x303, Modulo, &LongitudModulo, ExponentePublico, &LongitudExponente ); Tarjeta.CargarPartePublicaRSA ( 0x304, RSA_1024, Modulo, ExponentePublico, LongitudExponente); // El EFRSA 0x304 solo podrá ser usado para verificar la firma del EFRSA 0x303 Tarjeta.BloquearGrupoDeAccesoEF ( 0x304, true, true, false ); ...
62
• Utilizar EFRSA. ... // Se supondrá que se tiene creado la estructura de ficheros del ejemplo anterior. C_TarIn Tarjeta; Tarjeta.Conectar ( COM1 ); Tarjeta.SeleccionarDF ( 0x300 ); //Cumplimos la Condición de Acceso del Grupo 3, para poder leer los EFRSA Tarjeta.VerificarCodigoSecreto ( 4, (BYTE*) CODIGO_SECRETO_4 ); //Cumplimos la Condición de Uso para los EFRSA Tarjeta.VerificarCodigoSecreto ( 5, (BYTE*) CODIGO_SECRETO_5 ); BYTE Datos [ ] = Firma esto; WORD32 LongitudDatos; BYTE Firma [ 128 ]; WORD16 LongitudFirma; LongitudDatos = sizeof ( Datos ); Tarjeta.FirmaDelDocumento ( 0x303, Datos, LongitudDatos, Firma, &LongitudFirma ); Tarjeta.VerificarFirma ( 0x304, Datos, LongitudDatos, Firma, LongitudFirma ); BYTE Hash [128]; WORD16 LongitudHash; Tarjeta.CalcularHash ( 0x303, Datos,
63
LongitudDatos, Hash, &LongitudHash ); // Creamos una firma digital Tarjeta.CifrarDatosConPrivada ( 0x303, Hash, LongitudHash, Firma, &LongitudFirma ); Tarjeta.VerificarFirma ( 0x303, Datos, LongitudDatos, Firma, LongitudFirma ); Bibliografía: • Tarjetas Inteligentes. Juan Domingo Sandoval. Ed. Paraninfo. • Gemplus Public Key Reference Manual (Versión 2.2) • Gemplus Public Key Interface Library (Versión 2.0) Páginas Web: • http://www.gemplus.com • http://www.gemplus.fr/developers • http://www.pcscworkgroup.com/ 1 1 Parte teórica Tema 1. Introducción Parte teórica Tema 2. Las Tarjetas. Características generales v 35 Parte práctica Introducción Parte práctica Interfaz de la librería
64
ROM (Datos de identificación) Entrada/Salida Canal de Control EEPROM (Datos de la Aplicación) Reloj Alimentación Masa Entrada/Salida Canal de Control ROM (Datos de identificación) EEPROM (Datos de la Aplicación) Reloj Alimentación Masa Circuito de Seguridad Entrada/Salida Canal de Control ROM Reloj Alimentación Masa CPU
65
RAM EEPROM Puerto Área de ficheros Programas de aplicación Tablas y punteros del sistema Datos de producción Buffer de entrada/salida Espacio de trabajo para algoritmos criptográficos Variables generales Pila Registro Datos de administración Cabecera Cuerpo Datos Fichero DF EF EF EF EF EF EF EF MF
66
DF MF DF MF Posición 1 2 3 ................... n Posición 1 2 3 ...................... n Número de celda 01h 02h 03h m ... Posición 1 2 3 ................... n Número de celda 01h 02h 03h m ... Posición 1 2 3 .................... n
67
Número de celda 01h 02h 03h m ... 0101 EF EF 3F01 EF 3F02 EF 0102 EF 0200 DF 0100 DF 3F00 MF EF EF EF EF
68
EF EF EF EF EF EF EF EF EF EF EF EF Bit de inicio Bit de paridad Bit de parada Tiempo de espera Bit de inicio 8 bits de datos t 5v 0 La Tarjeta es insertada La Tarjeta especifica mas de un protocolo de comunicación Tarjeta Inteligente Lector Fin de la selección del protocolo
69
CLA INS P1 P2 P3 Zona de datos Características de la librería Paquete de desarrollo Instalación de las librerías y del Lector de Tarjetas Recomendaciones Dificultades en el desarrollo Variables Públicas C_TarIn ~C_TarIn Conectar Conectar Desconectar SeleccionarMF SeleccionarDF SeleccionarDF SeleccionarEF CrearDF CrearEFsc CargarCodigoSecreto VerificarCodigoSecreto CambiarCodigoSecreto
70
DesbloquearCodigoSecreto CrearEFDatos ActualizarEFDatos LeerEFDatos CrearEFRSA CargarPartePublicaRSA LeerPartePublicaRSA CargarPartePrivadaRSA CargarPartePrivadaRSA GenerarClaveRSA FirmaDelDocumento VerificarFirma CalcularHash CifrarDatosConPrivada LongitudEF BloquearGrupoDeAccesoEF GenerarNumeroAleatorio BorrarTarjeta Errores de esta Librería Programas de ejemplo
71