Search in sources :

Example 26 with ResponseApdu

use of es.gob.jmulticard.apdu.ResponseApdu in project jmulticard by ctt-gob-es.

the class PaceChannelHelper method openPaceChannel.

/**
 * Abre un canal PACE.
 * @param cla Clase de APDU para los comandos de establecimiento de canal.
 * @param pi Valor de inicialización del canal. Puede ser un CAN
 *           (<i>Card Access Number</i>) o una MRZ (<i>Machine Readable Zone</i>).
 * @param conn Conexi&oacute;n hacia la tarjeta inteligente.
 * @param cryptoHelper Clase para la realizaci&oacute;n de operaciones criptogr&aacute;ficas auxiliares.
 * @return SecureMessaging Objeto para el env&iacute;o de mensajes seguros a trav&eacute;s de canal PACE.
 * @throws ApduConnectionException Si hay problemas de conexi&oacute;n con la tarjeta.
 * @throws PaceException Si hay problemas en la apertura del canal.
 */
public static SecureMessaging openPaceChannel(final byte cla, final PaceInitializer pi, final ApduConnection conn, final CryptoHelper cryptoHelper) throws ApduConnectionException, PaceException {
    if (conn == null) {
        throw new IllegalArgumentException(// $NON-NLS-1$
        "El canal de conexion no puede ser nulo");
    }
    if (pi == null) {
        throw new IllegalArgumentException(// $NON-NLS-1$
        "Es necesario proporcionar un inicializador para abrir canal PACE");
    }
    if (cryptoHelper == null) {
        throw new IllegalArgumentException(// $NON-NLS-1$
        "El CryptoHelper no puede ser nulo");
    }
    if (!conn.isOpen()) {
        conn.open();
    }
    ResponseApdu res;
    CommandApdu comm;
    // 1.3.2 - Establecemos el algoritmo para PACE con el comando MSE Set:
    comm = new MseSetPaceAlgorithmApduCommand(cla, MseSetPaceAlgorithmApduCommand.PaceAlgorithmOid.PACE_ECDH_GM_AES_CBC_CMAC128, pi.getPasswordType(), MseSetPaceAlgorithmApduCommand.PaceAlgorithmParam.BRAINPOOL_256_R1);
    res = conn.transmit(comm);
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error estableciendo el algoritmo del protocolo PACE.");
    }
    // 1.3.3 - Primer comando General Autenticate - Get Nonce
    comm = new GeneralAuthenticateApduCommand((byte) 0x10, new byte[] { (byte) 0x7C, (byte) 0x00 });
    res = conn.transmit(comm);
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error solicitando el aleatorio de calculo PACE (Nonce)");
    }
    // Calcular nonce devuelto por la tarjeta que se empleara en los calculos
    final byte[] nonce;
    try {
        nonce = new Tlv(new Tlv(res.getData()).getValue()).getValue();
    } catch (final TlvException e) {
        throw new PaceException(// $NON-NLS-1$ //$NON-NLS-2$
        "El aleatorio de calculo PACE (Nonce) obtenido (" + HexUtils.hexify(res.getData(), true) + ") no sigue el formato esperado: " + e, // $NON-NLS-1$ //$NON-NLS-2$
        e);
    }
    // Calcular sk = SHA-1( CAN || 00000003 );
    // La clave son los 16 bytes MSB del hash
    final byte[] sk = new byte[16];
    try {
        System.arraycopy(cryptoHelper.digest(CryptoHelper.DigestAlgorithm.SHA1, HexUtils.concatenateByteArrays(pi.getBytes(), CAN_MRZ_PADDING)), 0, sk, 0, 16);
    } catch (final IOException e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo el 'sk' a partir del CAN: " + e, // $NON-NLS-1$
        e);
    }
    // Calcular secret = AES_Dec(nonce,sk);
    final byte[] secret_nonce;
    try {
        secret_nonce = cryptoHelper.aesDecrypt(nonce, new byte[0], sk);
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error descifranco el 'nonce': " + e, // $NON-NLS-1$
        e);
    }
    // 1.3.4 - Segundo comando General Autenticate - Map Nonce
    // Generamos un par de claves efimeras EC para el DH
    // $NON-NLS-1$
    final X9ECParameters ecdhParameters = TeleTrusTNamedCurves.getByName("brainpoolp256r1");
    final ECPoint pointG = ecdhParameters.getG();
    final Fp curve = (org.spongycastle.math.ec.ECCurve.Fp) ecdhParameters.getCurve();
    // La privada del terminal se genera aleatoriamente (PrkIFDDH1)
    // La publica de la tarjeta sera devuelta por ella misma al enviar nuesra publica (pukIFDDH1)
    final Random rnd = new Random();
    rnd.setSeed(rnd.nextLong());
    final byte[] x1 = new byte[curve.getFieldSize() / 8];
    rnd.nextBytes(x1);
    final BigInteger PrkIFDDH1 = new BigInteger(1, x1);
    // Enviamos nuestra clave publica (pukIFDDH1 = G*PrkIFDDH1)
    final ECPoint pukIFDDH1 = pointG.multiply(PrkIFDDH1);
    Tlv tlv = new Tlv(TAG_DYNAMIC_AUTHENTICATION_DATA, new Tlv(TAG_GEN_AUTH_2, pukIFDDH1.getEncoded(false)).getBytes());
    // ... Y la enviamos a la tarjeta
    comm = new GeneralAuthenticateApduCommand((byte) 0x10, tlv.getBytes());
    res = conn.transmit(comm);
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error mapeando el aleatorio de calculo PACE (Nonce)");
    }
    // Se obtiene la clave publica de la tarjeta
    final byte[] pukIccDh1;
    try {
        pukIccDh1 = unwrapEcKey(res.getData());
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo la clave efimera EC publica de la tarjeta: " + e, // $NON-NLS-1$
        e);
    }
    // calcular blinding point H = PrkIFDDH1 * PukICCDH1
    final ECPoint y1FromG = byteArrayToECPoint(pukIccDh1, curve);
    // Calculamos el punto H secreto
    final ECPoint SharedSecret_H = y1FromG.multiply(PrkIFDDH1);
    // Se calcula el nuevo punto G' = nonce*G + H
    final BigInteger ms = new BigInteger(1, secret_nonce);
    final ECPoint g_temp = pointG.multiply(ms);
    final ECPoint newPointG = g_temp.add(SharedSecret_H);
    // 1.3.5 Tercer comando General Authenticate
    // Se calcula la coordenada X de G' y generamos con la tarjeta un nuevo acuerdo de claves
    // La privada del terminal se genera aleatoriamente (PrkIFDDH2)
    // La publica de la tarjeta sera devuelta por ella misma al enviar nuesra publica (pukIFDDH2)
    final byte[] x2 = new byte[curve.getFieldSize() / 8];
    rnd.setSeed(rnd.nextLong());
    rnd.nextBytes(x2);
    final BigInteger PrkIFDDH2 = new BigInteger(1, x2);
    // Enviamos nuestra clave publica (pukIFDDH2 = G'*PrkIFDDH2)
    final ECPoint pukIFDDH2 = newPointG.multiply(PrkIFDDH2);
    // ... La metemos en un TLV de autenticacion ...
    tlv = new Tlv(TAG_DYNAMIC_AUTHENTICATION_DATA, new Tlv(TAG_GEN_AUTH_3, pukIFDDH2.getEncoded(false)).getBytes());
    comm = new GeneralAuthenticateApduCommand((byte) 0x10, tlv.getBytes());
    res = conn.transmit(comm);
    // Se obtiene la clave publica de la tarjeta (pukIccDh2) que es la coordenada Y del nuevo Punto G'
    final byte[] pukIccDh2;
    try {
        pukIccDh2 = unwrapEcKey(res.getData());
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo la clave efimera EC publica de la tarjeta: " + e, // $NON-NLS-1$
        e);
    }
    final ECPoint y2FromNewG = byteArrayToECPoint(pukIccDh2, curve);
    // Se calcula el secreto k = PukICCDH2 * PrkIFDDH2
    final ECPoint.Fp SharedSecret_K = (org.spongycastle.math.ec.ECPoint.Fp) y2FromNewG.multiply(PrkIFDDH2);
    final byte[] secretK = bigIntToByteArray(SharedSecret_K.normalize().getXCoord().toBigInteger());
    // 1.3.6 Cuarto comando General Authenticate
    // Se validan las claves de sesion generadas en el paso anterior,
    // por medio de un MAC que calcula el terminal y comprueba la tarjeta,
    // la cual devolvera un segundo MAC.
    // Calcular kenc = SHA-1( k || 00000001 );
    final byte[] kenc = new byte[16];
    try {
        System.arraycopy(cryptoHelper.digest(CryptoHelper.DigestAlgorithm.SHA1, HexUtils.concatenateByteArrays(secretK, KENC_PADDING)), 0, kenc, 0, 16);
    } catch (final IOException e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo el 'kenc' a partir del CAN: " + e, // $NON-NLS-1$
        e);
    }
    // Calcular kmac = SHA-1( k || 00000002 );
    final byte[] kmac = new byte[16];
    try {
        System.arraycopy(cryptoHelper.digest(CryptoHelper.DigestAlgorithm.SHA1, HexUtils.concatenateByteArrays(secretK, KMAC_PADDING)), 0, kmac, 0, 16);
    } catch (final IOException e) {
        throw new PaceException(// $NON-NLS-1$
        "Error obteniendo el 'kmac' a partir del CAN: " + e, // $NON-NLS-1$
        e);
    }
    // Elimina el byte '04' del inicio que es el indicador de punto descomprimido
    final byte[] pukIccDh2Descompressed = new byte[pukIccDh2.length - 1];
    System.arraycopy(pukIccDh2, 1, pukIccDh2Descompressed, 0, pukIccDh2.length - 1);
    // Se calcula el Mac del terminal: data = '7f494F06' + oid + '864104' + PukICCDH2;
    final byte[] data = HexUtils.concatenateByteArrays(MAC_PADDING, HexUtils.concatenateByteArrays(MseSetPaceAlgorithmApduCommand.PaceAlgorithmOid.PACE_ECDH_GM_AES_CBC_CMAC128.getBytes(), HexUtils.concatenateByteArrays(MAC2_PADDING, pukIccDh2Descompressed)));
    byte[] mac8bytes;
    try {
        mac8bytes = cryptoHelper.doAesCmac(data, kmac);
    } catch (final Exception e) {
        throw new PaceException(// $NON-NLS-1$
        "Error descifrando el 'nonce': " + e, // $NON-NLS-1$
        e);
    }
    // ... La metemos en un TLV de autenticacion ...
    tlv = new Tlv(TAG_DYNAMIC_AUTHENTICATION_DATA, new Tlv(TAG_GEN_AUTH_4, mac8bytes).getBytes());
    // Se envia el comando General Authenticate y se recupera el MAC devuelto por la tarjeta.
    comm = new GeneralAuthenticateApduCommand((byte) 0x00, tlv.getBytes());
    res = conn.transmit(comm);
    // Se obtiene un MAC con respuesta 90-00 indicando que se ha establecido el canal correctamente
    if (!res.isOk()) {
        throw new PaceException(res.getStatusWord(), comm, // $NON-NLS-1$
        "Error estableciendo el algoritmo del protocolo PACE.");
    }
    // Se inicializa el contador de secuencia a ceros
    final byte[] ssc = new byte[16];
    Arrays.fill(ssc, (byte) 0);
    // $NON-NLS-1$
    LOGGER.info("Canal Pace abierto");
    LOGGER.info(// $NON-NLS-1$
    "\nKenc: " + HexUtils.hexify(kenc, true) + "Kmac: " + // $NON-NLS-1$
    HexUtils.hexify(kmac, true) + "Ssc: " + // $NON-NLS-1$
    HexUtils.hexify(ssc, true));
    final AmCryptoProvider crypto = new AmAESCrypto();
    return new SecureMessaging(crypto, kenc, kmac, new byte[crypto.getBlockSize()]);
}
Also used : CommandApdu(es.gob.jmulticard.apdu.CommandApdu) SecureMessaging(es.gob.jmulticard.de.tsenger.androsmex.iso7816.SecureMessaging) AmAESCrypto(es.gob.jmulticard.de.tsenger.androsmex.crypto.AmAESCrypto) X9ECParameters(org.spongycastle.asn1.x9.X9ECParameters) ResponseApdu(es.gob.jmulticard.apdu.ResponseApdu) Fp(org.spongycastle.math.ec.ECCurve.Fp) IOException(java.io.IOException) ECPoint(org.spongycastle.math.ec.ECPoint) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException) IOException(java.io.IOException) TlvException(es.gob.jmulticard.asn1.TlvException) AmCryptoProvider(es.gob.jmulticard.de.tsenger.androsmex.crypto.AmCryptoProvider) TlvException(es.gob.jmulticard.asn1.TlvException) Random(java.util.Random) MseSetPaceAlgorithmApduCommand(es.gob.jmulticard.apdu.iso7816four.pace.MseSetPaceAlgorithmApduCommand) GeneralAuthenticateApduCommand(es.gob.jmulticard.apdu.iso7816four.GeneralAuthenticateApduCommand) BigInteger(java.math.BigInteger) Tlv(es.gob.jmulticard.asn1.Tlv)

Example 27 with ResponseApdu

use of es.gob.jmulticard.apdu.ResponseApdu in project jmulticard by ctt-gob-es.

the class Iso7816FourCard method readBinaryComplete.

/**
 * Lee por completo el contenido binario del fichero actualmente seleccionado.
 * @param len Longitud del fichero a leer.
 * @return APDU de respuesta.
 * @throws ApduConnectionException Si hay problemas en el env&iacute;o de la APDU.
 * @throws IOException Si hay problemas en el <i>buffer</i> de lectura.
 */
public byte[] readBinaryComplete(final int len) throws IOException {
    int off = 0;
    ResponseApdu readedResponse = null;
    final ByteArrayOutputStream out = new ByteArrayOutputStream();
    // Leemos en iteraciones de MAX_READ_CHUNK bytes
    while (off < len) {
        final byte msbOffset = (byte) (off >> 8);
        final byte lsbOffset = (byte) (off & 0xFF);
        final int left = len - off;
        try {
            if (left < MAX_READ_CHUNK) {
                // Si es menor que el maximo que podemos leer por iteracion
                readedResponse = readBinary(msbOffset, lsbOffset, (byte) left);
            } else {
                readedResponse = readBinary(msbOffset, lsbOffset, (byte) MAX_READ_CHUNK);
            }
        } catch (final Exception e) {
            LOGGER.warning(// $NON-NLS-1$
            "Se ha intentado una lectura fuera de los limites del fichero, se devolvera lo leido hasta ahora: " + e);
            return out.toByteArray();
        }
        final boolean eofReached = EOF_REACHED.equals(readedResponse.getStatusWord());
        if (!readedResponse.isOk() && !eofReached) {
            // $NON-NLS-1$ //$NON-NLS-2$
            throw new IOException("Error leyendo el binario (" + readedResponse.getStatusWord() + ")");
        }
        out.write(readedResponse.getData());
        off += MAX_READ_CHUNK;
        // Si hemos llegado al final no seguimos leyendo
        if (eofReached) {
            break;
        }
    }
    return out.toByteArray();
}
Also used : ResponseApdu(es.gob.jmulticard.apdu.ResponseApdu) ByteArrayOutputStream(java.io.ByteArrayOutputStream) IOException(java.io.IOException) SecureChannelException(es.gob.jmulticard.apdu.connection.cwa14890.SecureChannelException) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException) IOException(java.io.IOException) PinException(es.gob.jmulticard.card.PinException)

Example 28 with ResponseApdu

use of es.gob.jmulticard.apdu.ResponseApdu in project jmulticard by ctt-gob-es.

the class Iso7816FourCard method selectFileByName.

/**
 * Selecciona un fichero por nombre.
 * @param name Nombre del fichero en hexadecimal
 * @throws FileNotFoundException Si el fichero no existe
 * @throws ApduConnectionException Si ocurre alg&uacute;n problema durante la selecci&oacute;n
 * @throws Iso7816FourCardException Si el fichero no se puede seleccionar por cualquier otra causa
 */
public void selectFileByName(final byte[] name) throws ApduConnectionException, FileNotFoundException, Iso7816FourCardException {
    final CommandApdu selectCommand = new SelectDfByNameApduCommand(getCla(), name);
    final ResponseApdu response = sendArbitraryApdu(selectCommand);
    if (response.isOk()) {
        return;
    }
    final StatusWord sw = response.getStatusWord();
    if (sw.equals(new StatusWord((byte) 0x6A, (byte) 0x82))) {
        throw new FileNotFoundException(name);
    }
    throw new Iso7816FourCardException(sw, selectCommand);
}
Also used : SelectDfByNameApduCommand(es.gob.jmulticard.apdu.iso7816four.SelectDfByNameApduCommand) CommandApdu(es.gob.jmulticard.apdu.CommandApdu) StatusWord(es.gob.jmulticard.apdu.StatusWord) ResponseApdu(es.gob.jmulticard.apdu.ResponseApdu)

Example 29 with ResponseApdu

use of es.gob.jmulticard.apdu.ResponseApdu in project jmulticard by ctt-gob-es.

the class SmartCafePkcs15Applet method sign.

@Override
public byte[] sign(final byte[] data, final String algorithm, final PrivateKeyReference keyRef) throws CryptoCardException, PinException {
    if (data == null) {
        // $NON-NLS-1$
        throw new CryptoCardException("Los datos a firmar no pueden ser nulos");
    }
    if (keyRef == null) {
        // $NON-NLS-1$
        throw new IllegalArgumentException("La clave privada no puede ser nula");
    }
    if (!(keyRef instanceof SmartCafePrivateKeyReference)) {
        throw new IllegalArgumentException(// $NON-NLS-1$
        "La clave proporcionada debe ser de tipo " + SmartCafePrivateKeyReference.class.getName() + // $NON-NLS-1$
        ", pero se ha recibido de tipo " + keyRef.getClass().getName());
    }
    final SmartCafePrivateKeyReference scPrivateKey = (SmartCafePrivateKeyReference) keyRef;
    // Pedimos el PIN si no se ha pedido antes
    if (!this.authenticated) {
        try {
            verifyPin(getInternalPasswordCallback());
            this.authenticated = true;
        } catch (final ApduConnectionException e1) {
            // $NON-NLS-1$
            throw new CryptoCardException("Error en la verificacion de PIN: " + e1, e1);
        }
    }
    // Enviamos el MSE SET for Computation
    ResponseApdu res = null;
    try {
        res = sendArbitraryApdu(new MseSetComputationApduCommand(// CLA
        (byte) 0x01, new byte[] { (byte) scPrivateKey.getKeyOrdinal() }, // RSA
        new byte[] { (byte) 0x02 }));
    } catch (final ApduConnectionException e) {
        throw new CryptoCardException(// $NON-NLS-1$ //$NON-NLS-2$
        "Error estableciendo la clave y el algoritmo de firma (repuesta=" + res + "): " + e, // $NON-NLS-1$ //$NON-NLS-2$
        e);
    }
    if (res == null || !res.isOk()) {
        throw new CryptoCardException(// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        "No se ha podido establecer la clave y el algoritmo de firma" + (res != null ? " (repuesta=" + res + ")" : ""));
    }
    // Creamos el DigestInfo
    final byte[] digestInfo;
    try {
        digestInfo = DigestInfo.encode(algorithm, data, this.cryptoHelper);
    } catch (final IOException e) {
        // $NON-NLS-1$
        throw new CryptoCardException("Error en el calculo de la huella para firmar: " + e, e);
    }
    // Y lo enviamos a firmar
    try {
        res = sendArbitraryApdu(new PsoSignHashApduCommand((byte) 0x01, digestInfo));
    } catch (final ApduConnectionException e) {
        throw new CryptoCardException(// $NON-NLS-1$ //$NON-NLS-2$
        "Error firmando (repuesta=" + res + "): " + e, // $NON-NLS-1$ //$NON-NLS-2$
        e);
    }
    if (res == null || !res.isOk()) {
        throw new CryptoCardException(// $NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
        "No se ha podido firmar el DigestInfo" + (res != null ? " (repuesta=" + res + ")" : ""));
    }
    return res.getData();
}
Also used : MseSetComputationApduCommand(es.gob.jmulticard.apdu.iso7816four.MseSetComputationApduCommand) PsoSignHashApduCommand(es.gob.jmulticard.apdu.iso7816eight.PsoSignHashApduCommand) ResponseApdu(es.gob.jmulticard.apdu.ResponseApdu) IOException(java.io.IOException) CryptoCardException(es.gob.jmulticard.card.CryptoCardException) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException)

Example 30 with ResponseApdu

use of es.gob.jmulticard.apdu.ResponseApdu in project jmulticard by ctt-gob-es.

the class SmartCafePkcs15Applet method getPinRetriesLeft.

private int getPinRetriesLeft() throws PinException {
    final CommandApdu verifyCommandApdu = new RetriesLeftApduCommand();
    final ResponseApdu verifyResponse;
    try {
        verifyResponse = getConnection().transmit(verifyCommandApdu);
    } catch (final ApduConnectionException e) {
        throw new PinException(// $NON-NLS-1$
        "Error obteniendo el PIN del CallbackHandler: " + e, // $NON-NLS-1$
        e);
    }
    if (verifyResponse.isOk() || verifyResponse.getBytes().length > 2) {
        return verifyResponse.getBytes()[1];
    }
    throw new PinException(// $NON-NLS-1$
    "Error comprobando los intentos restantes de PIN con respuesta: " + HexUtils.hexify(verifyResponse.getBytes(), true));
}
Also used : CommandApdu(es.gob.jmulticard.apdu.CommandApdu) ResponseApdu(es.gob.jmulticard.apdu.ResponseApdu) BadPinException(es.gob.jmulticard.card.BadPinException) PinException(es.gob.jmulticard.card.PinException) RetriesLeftApduCommand(es.gob.jmulticard.apdu.gide.RetriesLeftApduCommand) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException)

Aggregations

ResponseApdu (es.gob.jmulticard.apdu.ResponseApdu)32 ApduConnectionException (es.gob.jmulticard.apdu.connection.ApduConnectionException)23 CommandApdu (es.gob.jmulticard.apdu.CommandApdu)20 BadPinException (es.gob.jmulticard.card.BadPinException)13 IOException (java.io.IOException)12 PinException (es.gob.jmulticard.card.PinException)10 Iso7816FourCardException (es.gob.jmulticard.card.iso7816four.Iso7816FourCardException)10 AuthenticationModeLockedException (es.gob.jmulticard.card.AuthenticationModeLockedException)7 CryptoCardException (es.gob.jmulticard.card.CryptoCardException)7 CertificateException (java.security.cert.CertificateException)7 SecureChannelException (es.gob.jmulticard.apdu.connection.cwa14890.SecureChannelException)6 StatusWord (es.gob.jmulticard.apdu.StatusWord)5 LostChannelException (es.gob.jmulticard.apdu.connection.LostChannelException)4 TlvException (es.gob.jmulticard.asn1.TlvException)4 InvalidCardException (es.gob.jmulticard.card.InvalidCardException)4 FileNotFoundException (es.gob.jmulticard.card.iso7816four.FileNotFoundException)4 CardNotPresentException (es.gob.jmulticard.apdu.connection.CardNotPresentException)3 Cwa14890Connection (es.gob.jmulticard.apdu.connection.cwa14890.Cwa14890Connection)3 PsoSignHashApduCommand (es.gob.jmulticard.apdu.iso7816eight.PsoSignHashApduCommand)3 GetResponseApduCommand (es.gob.jmulticard.apdu.iso7816four.GetResponseApduCommand)3