Tarjeta SIM como Módulo de Seguridad (HSM)

Fecha de publicación:
Última actualización: 2021-12-31
Autor:

 

El artículo anterior expuso que las SIMcard (o tarjetas SIM) pueden utilizarse para otorgar privilegios de operador. Estos privilegios permiten obtener los permisos más elevados y sensibles en Android, sin recurrir al rooteo del dispositivo. Por lo tanto, resulta evidente que tanto los operadores móviles como los proveedores de los dispositivos Android confían plenamente en la seguridad de la SIM.

Tarjeta SIM como Módulo de Seguridad (HSM)

Las SIM son dispositivos creados especialmente para resistir cualquier intento de hackeo. Estos dispositivos incluyen mecanismos de bloqueo automático para proteger la información sensible. Por ejemplo, los equipos de trazado y depuración para SIM pueden costar miles de euros, aunque estos equipos solamente interceptan los datos que viajan entre la SIM y el teléfono, como un «sniffer» de red. Estos equipos no permiten clonar las tarjetas o extraer las claves allí almacenadas.

 

Módulos HSM

Dado que la SIM ofrece un alto nivel de seguridad, mayor que la protección alcanzable por medio de software, existen diferentes casos de uso de SIM en calidad de HSM (en inglés, Hardware Security Module). Los módulos HSM son procesadores criptográficos, implementados en hardware, cuyo propósito es la protección de claves criptográficas. Aunque existen emuladores de HSM en software, los módulos HSM físicos pueden ofrecer mayor seguridad. Esto se debe a la imposibilidad de leer la memoria de estos procesadores de manera externa, lo cual hace prácticamente imposible la ingeniería inversa. En cambio, los módulos HSM emulados en software no pueden impedir la lectura de la memoria de manera física. El mismo razonamiento es usado por los fabricantes de SIM para argumentar que los chips físicos son más seguros que las SIM virtuales.

Mini-SIM, micro-SIM, nano-SIM, eSIM

No se debe confundir las SIM virtuales con la evolución de eSIM. Estas últimas virtualizan los datos contenidos en la SIM, pero el dispositivo de almacenamiento sigue siendo un chip físico, el cual protege el acceso a la memoria de la misma manera como la SIM tradicional. Este chip no es removible. Por eso, se dice que eSIM es la versión embebida de SIM.

Las llaves de autenticación de la suscripción móvil se almacenan dentro de la SIM. Sin embargo, la SIM puede almacenar llaves adicionales. Por ejemplo, algunos bancos utilizan esta funcionalidad para cifrar las transacciones electrónicas hechas desde el celular. Las llaves bancarias son diferentes de las llaves de autenticación en la red móvil, pero se almacenan y protegen de la misma manera.

 

Comandos APDU

La comunicación entre el teléfono y la SIM funciona por medio de comandos APDU, cuyo formato está definido en el estándar ISO/IEC 7816-4.1

Tradicionalmente la comunicación es iniciada por el teléfono y se realiza de manera síncrona. Es decir, se espera que la SIM responda antes de enviar el próximo APDU:

Comunicación con la SIM por medio de comandos APDU

El comando APDU enviado hacia la SIM incluye un encabezado obligatorio con 4 octetos: CLA, INS, P1 y P2.

CLAClase: ETSI, 3GPP, Global Platform2
INSCódigo de instrucción
P1Parámetro #1
P2Parámetro #2

 

El resto del APDU es opcional y puede incluir datos adicionales. Por ejemplo, estos datos adicionales sirven para seleccionar un archivo o un applet dentro de la SIM, enviar datos específicos para dicho applet, etc. El formato de los datos puede ser definido por el desarrollador, pero la longitud del APDU debe ser acorde al estándar ISO/IEC 7816-4.

Al procesar el APDU se produce una respuesta, cuyo formato establece que los 2 últimos octetos, conocidos como SW (en inglés, Status Word), indican el estado del resultado. Generalmente el valor 9000 en hexadecimal corresponde a un resultado exitoso. Veamos un ejemplo de APDU y su respectiva respuesta:

>> 00 A4 00 00 02 3F 00
<< 90 00

El contenido del APDU puede ser interpretado según el estándar ETSI TS 102.221,3 como sigue:

APDU: SELECT MF

El octeto CLA indica que la instrucción es de clase 3G. El octeto INS indica que se debe ejecutar la instrucción SELECT (seleccionar). Los parámetros 1 y 2 pueden indicar el modo de selección. En este caso se debe seleccionar el directorio de raíz conocido como MF (en inglés, Master File), cuyo identificador es 3F00. El octeto LC, el cual precede el identificador MF, indica la longitud de los datos adicionales. En este caso son 2 octetos adicionales, ya que el identificador MF ocupa 2 octetos. El directorio de raíz está presente en todos los sistemas de archivos en la SIM. Por lo tanto, este APDU debería funcionar correctamente en cualquier SIM compatible con 3G.

 

Applets JavaCard

Supongamos que tenemos un applet criptográfico instalado en la SIM, el cual se usa para encriptar datos sensibles. Los applets se identifican por medio de un ID único conocido como AID. Supongamos que el AID de nuestro applet criptográfico de pruebas es 01020304050607. Normalmente el AID tiene una longitud mayor, pero por simplicidad supondremos que son solamente estos 7 octetos. Entonces, el APDU para seleccionar dicho applet sería:

>> 00 A4 04 00 07 01 02 03 04 05 06 07 00
<< 90 00

Luego de seleccionar el applet podemos enviar otro APDU con los datos que deseamos encriptar.

Para mayor información acerca de los applets JavaCard y ejemplos de código se recomienda consultar el sitio oficial de Oracle JavaCard. Los applets más simples pueden ser compilados con las herramientas gratuitas, disponibles en el mismo sitio, e instalados en una SIM de pruebas. La gran mayoría de las SIMs actuales soportan esta tecnología. Nótese que JavaCard es una tecnología basada en Java. El desarrollo de applets JavaCard tiene cierta similitud con el desarrollo de aplicaciones Java, excepto que el manejo de memoria es diferente debido a la escasez de este recurso en las SIM. El formato del bytecode JavaCard también se diferencia del formato de bytecode de JVM, pero estas diferencias son transparentes para el desarrollador.

Los applets JavaCard pueden hacer uso de la tecnología SIM Application Toolkit, la cual permite ejecutar comandos proactivos en el teléfono, como enviar SMS, desplegar notificaciones y menú interactivos, entre otras funcionalidades.

 

Envío de APDU por medio de AT+CSIM

La manera más simple de poner en práctica el material expuesto hasta ahora consiste en utilizar un modem GSM para enviar los APDU por medio de un emulador de terminal, como Hyper Terminal o PuTTY. Con el mismo propósito se puede utilizar la librería gratuita CelerCOM para Java.

GSM modems

De esta manera no es necesario utilizar un dispositivo lector de tarjetas y un software especializado para el envío de APDU. La mayoría de los modem GSM soportan el comando AT llamado AT+CSIM, el cual permite encapsular comandos APDU para la SIM. Internamente Android utiliza este mismo comando para ejecutar los APDU que las aplicaciones envían por medio del servicio TelephonyManager.

Por ejemplo, el APDU para seleccionar el directorio raíz MF puede ser enviado de la siguiente manera:

AT+CSIM=14,"00a40000023f00"

El valor 14 es la longitud del APDU en caracteres.

Si el modem responde con un error genérico como +CME ERROR es posible que el modem no soporte el comando AT+CSIM. La mayoría de los modem GSM soportan este comando. Inclusive es posible utilizar un teléfono Android como modem, pero es más práctico usar un modem GSM para puerto USB.

Estos comandos AT+CSIM, enviados por medio de una terminal hacia el modem GSM, sirven para verificar la validez de los comandos. Se recomienda hacer estas pruebas antes de utilizar los mismos APDU en una aplicación Android.

 

Open Mobile API

Si ya instalamos el applet JavaCard en la SIM de pruebas y ya validamos los comandos APDU, el siguiente paso es hacer una aplicación Android para interactuar con la SIM.

Android soporta el envío de APDU por medio del servicio TelephonyManager a partir de la versión 5.1. A partir de Android 9 esta funcionalidad está disponible por medio de SEService. Esta nueva opción se basa en las especificaciones de Open Mobile API v34 de Trusted Connectivity Alliance, una organización integrada por los fabricantes de SIM, anteriormente conocida como SIMAlliance. Todas estas API requieren permisos elevados. Sin embargo, si estamos usando una SIM de pruebas, podemos instalar el hash de nuestra llave de desarrollo dentro de ARA o ARF para obtener privilegios de operador, como se explicó en el artículo anterior.

Existen implementaciones alternas, basadas en Open Mobile API. Una de las más conocidas se llama SEEK (en inglés, Secure Element Evaluation Kit).5 Esta API fue creada por Giesecke & Devrient, uno de los fabricantes de SIMcard.

A continuación veamos un ejemplo que produce el mismo APDU que habíamos probado anteriormente con AT+CSIM, utilizando TelephonyManager:

import android.telephony.TelephonyManager;
import android.telephony.IccOpenLogicalChannelResponse;

   TelephonyManager tm = (TelephonyManager)getSystemService("phone");
   IccOpenLogicalChannelResponse resp =
      tm.iccOpenLogicalChannel(
         "01020304050607", // AID
         0                 // p2
   );
   int ch = resp.getChannel();
   if(ch > 0){
      String sResp =
         tm.iccTransmitApduLogicalChannel(
            ch,
            CLA, INS, P1, P2, P3, DATA
      );
      tm.iccCloseLogicalChannel(ch);
   }
 

Este código intenta seleccionar el applet JavaCard con AID 01020304050607. Luego le envía el APDU correspondiente a los parámetros CLA, INS, P1, P2, P3 y DATA. El parámetro P3 es opcional. Si no aplica, se puede especificar un valor negativo para que el APDU se envíe solamente con los 4 octetos de CLA, INS, P1 y P2.

A veces, la SIMcard responde con SW 61XX. Es decir, el penúltimo octeto de la respuesta tiene el valor hexadecimal 61. Esto significa que el APDU no puede ser procesado por el momento, pero se puede reintentar. Una implementación robusta debería procesar estas respuestas 61XX y generar al menos un reintento de envío del mismo APDU. Es importante limitar los reintentos para no saturar la SIM y evitar un bloqueo indefinido. Un único reintento puede ser suficiente.

No olvide implementar manejo de errores. El anterior código debería quedar encerrado en un bloque try/catch. Además, es importante recordar que estas API de TelephonyManager requieren el permiso MODIFY_PHONE_STATE. Este permiso puede ser obtenidos en tiempo de instalación solamente hasta Android 2.2. A partir de Android 2.3 este permiso se puede obtener únicamente por las aplicaciones del sistema (preinstaladas) o por medio de privilegios de operador. Esta última opción es la más recomendada, como se había explicado más arriba.

A continuación se presenta otro ejemplo, utilizando Open Mobile API:

import android.se.omapi.SEService;
import android.se.omapi.Session;
import android.se.omapi.Channel;
import android.se.omapi.Reader;
import java.util.concurrent.Executors;

   ExecutorService exe =
      Executors.newSingleThreadExecutor();
   SEService se = new SEService(
      this, // context
      exe,  // para procesar los callback
      this  // listener
   );
   Reader[] rdrs = se.getReaders();
   if(rdrs.length > 0){
      Session sess = rdrs[0].openSession();
      Channel ch = sess.openLogicalChannel(
         // AID
         new byte[]{ 1, 2, 3, 4, 5, 6, 7 },
         0 // p2
      );
      byte[] respApdu = ch.transmit(
         new byte[]{ /* APDU */ }
      );
      ch.close();
   }
 

Nótese que en este caso los APDU son codificados como arreglos de bytes, no cadenas de texto hexadecimales. Otra diferencia importante es que la API puede manejar los reintentos de envío de APDU automáticamente, por lo que no es necesario procesar las respuestas con SW 61XX.

En este caso también se recomienda agregar un bloque try/catch para manejo de errores. Uno de los errores posibles es la ausencia de permisos.

Adicionalmente, se puede combinar los ejemplos de TelefonyManager y SEService para implementar una solución compatible con diferentes versiones de Android.

 

Conclusiones

La SIM, como módulo de seguridad, puede ser útil para almacenar datos sensibles, implementar servicios de encripción y desencripción, entre otros usos. La ventaja principal tiene que ver con la seguridad física de la SIM.

Las aplicaciones Android requieren permisos elevados para poder interactuar con la SIM. Para obtener estos permisos se recomienda hacer uso de los privilegios de operador, los cuales pueden ser otorgados por medio de la misma SIM.

Existen diferentes API para interactuar con la SIM en Android. La disponibilidad de estas API depende del fabricante y la versión del sistema operativo. Es posible combinar las API para soportar múltiples versiones de Android.

 

Referencias

  1. «ISO/IEC 7816-4» (en inglés), ISO/IEC JTC 1/SC 17 (2005)
  2. «Global Platform Technology Card Specification v2.3.1» (en inglés), Global Platform (2018)
  3. «Smart Cards; UICC-Terminal interface; Physical and logical characteristics (Release 15)» (en inglés), ETSI (2018)
  4. «Open Mobile API v3.0» (en inglés), Trusted Connectivity Alliance (2016)
  5. Michael Roland, Michael Hölzl (2016). «Open Mobile API: Accessing the UICC on Android Devices» (en inglés), University of Applied Sciences Upper Austria.