Buenas.
Sigo con mis cacharreos con el DNI. El tema de la autenticación lo tengo bastante avanzado y ahora me he metido tambien con el acceso a los datos públicos del DNI via APDU mediante javax.smartcardio que viene en Java 1.6. y siguiendo los pasos de este post.
El código java que tengo hecho hasta el momento es el siguiente:
import javax.smartcardio.*;
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.util.*;
public class Lector {
public void Test(){
String hex = "00A40000025015";
byte[] primer_msg = new BigInteger(hex, 16).toByteArray();
hex = "00A40000026004";
byte[] segundo_msg = new BigInteger(hex, 16).toByteArray();
String SW1;
String SW2;
// show the list of available terminals
TerminalFactory factory = TerminalFactory.getDefault();
List terminals;
try {
terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);
// get the first terminal
CardTerminal terminal = terminals.get(0);
// establish a connection with the card
Card tarjeta = terminal.connect("T=0");
System.out.println("card: " + tarjeta);
CardChannel channel = tarjeta.getBasicChannel();
ResponseAPDU r = channel.transmit(new CommandAPDU(primer_msg));
System.out.println("response mensaje 1: " + getHexString(r.getBytes()));
SW1=getHexString(r.getBytes()).substring(0, 2);
SW2=getHexString(r.getBytes()).substring(2);
r = channel.transmit(new CommandAPDU(segundo_msg));
System.out.println("response mensaje 2: " + getHexString(r.getBytes()));
hex = "00C00000" + getHexString(r.getBytes()).substring(14,18); System.out.println(getHexString(r.getBytes()).substring(14,18));
System.out.println(hex);
byte[] tercer_msg = new BigInteger(hex, 16).toByteArray();
r = channel.transmit(new CommandAPDU(tercer_msg));
System.out.println("response mensaje 3: " + getHexString(r.getBytes()));
// disconnect
tarjeta.disconnect(false);
} catch (CardException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String getHexString(byte[] b) throws Exception {
String result = "";
//System.out.println("BYTES DE RESPUESTA: " +b.length);
for (int i=0; i < b.length; i++) {
result +=
Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
}
De momento este código me debería permitir llegar al paso 3 del otro post es decir "Envias 00C00000LE LE es el valor dado por SW2 en el segundo paso."
El problema es que en vez de dos bytes en los pasos 1 y 2 recibo largas cadenas de bytes. Esto tambíen se explica en el otro post y es debido a que hay una lectura semi automatica de los datos en cada paso.
¿Hay alguna forma de conseguir evitar esa automatización con el código java de tal forma que al recibir la respuesta de cada paso no haya lecturas automaticas de datos?
En caso de que no la haya, tambien lei en el otro post que con la respuesta del paso 2 puedo sacar el LE para el paso 3, en mi caso la respuesta del paso 2 es 6f0c850a01600405100080ffffff9000. He marcado en negrita lso 4 bytes que se marcan en el otro post de los cuales 6004 sería el ID del fichero y 0510 la longitud.
¿Que le tendría que pasar al siguiente comando 00C00000LE como LE, 51? Si le paso 0510 (qué es lo que hago en el código con getHexString(r.getBytes()).substring(14,18)) obtengo un error de lóngitud "java.lang.IllegalArgumentException: Invalid APDU: length=6, b1=5" al enviar el mensaje que quedaría 00C000000510.
Gracias como siempre por las posibles respuestas.
Bien esto avanza.
_dargor_30 Marzo 2010 - 12:11pm
Gracias a la línea que akas84 me dijo que pusiera en el código he conseguido desactivar la autolectura de datos y consigo el churro de datos en Hexadecimal. Si paso el churro de datos a ASCII obtengo cosas legibles pero mezcladas con otras cosas que no lo son (entiendo que son direcciones de memoria de la tarjeta y otra información que no ha de ser convertidad en ASCII). Ahora para sacar el nombre y el dni lo estoy haciendo a ojo.
¿Hay alguna manera de identificar los campos (por ejemplo algún codigo de separador, o información de la longitud de cada campo y donde comienza)?
Un saludo y gracias por las respuestas sobre todo por la de la autorespuesta porque me ha desatascado bastante.
Mirate la códificación ASN.1
akas842 Abril 2010 - 6:44pm
Mirate la códificación ASN.1 y el estándar PKCS#15 de RSA referido al CDF (Certificate Directory File).
Un saludo
comportamiento normal del DNIe
akas8429 Marzo 2010 - 11:52am
Hola arivero,
El comportamiento que defines es completamente normal, los certificados y claves públicas en los DNIe actuales están protegidos por PIN.
Un saludo
pero metes el pin o no?
arivero25 Marzo 2010 - 7:03pm
Os enseño lo que me pasa a mi:
En resumen. Empiezo igual que en el java, y cuando hago la autolectura y transformacion asn1 del fichero que dice en las FAQ, obtengo la lista de certificados. Voy a uno que me interese, y cuando intento sacarlo no puedo. Meto la clave, vuelvo a intentar la misma instruccion, y milagro ahi esta, con todos los datos Nombre Apellidos etc.
Anular auto-getResponse
akas8417 Marzo 2010 - 9:39am
Hola,
Para anular el autoGetResponse que realiza automáticamente java debes utilizar el siguiente código:
System.setProperty("sun.security.smartcardio.t0GetResponse", "false");
Un saludo,
--
Servicio técnico de C3PO
http://www.c3po.es
¿Que lector usas?
garkones7 Marzo 2010 - 11:01am
Hola dargor, ¿me podrías decir que lector usas? Yo tengo un Gemplus GemPC USB y smartcardio no encuentra ningún terminal. Gracias.
Un Saludo.
Un SCM SCR3310 USB
_dargor_7 Marzo 2010 - 1:01pm
Un SCM SCR3310 USB. El que regalaba Tractis pagando los gastos de envío.