Search in sources :

Example 26 with ApduConnectionException

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

the class CardOS method connect.

/**
 * Conecta con el lector del sistema que tenga una CardOS insertada.
 * @param conn Conexión hacia la tarjeta.
 * @throws IOException Cuando hay errores de entrada / salida.
 */
private void connect(final ApduConnection conn) throws IOException {
    if (conn == null) {
        // $NON-NLS-1$
        throw new IllegalArgumentException("La conexion no puede ser nula");
    }
    // Siemens CardOS son T=1
    conn.setProtocol(ApduConnectionProtocol.T1);
    final long[] terminals = conn.getTerminals(false);
    if (terminals.length < 1) {
        throw new NoReadersFoundException();
    }
    byte[] responseAtr;
    Atr actualAtr;
    InvalidCardException invalidCardException = null;
    CardNotPresentException cardNotPresentException = null;
    ApduConnectionException apduConnectionException = null;
    for (final long terminal : terminals) {
        conn.setTerminal((int) terminal);
        try {
            responseAtr = conn.reset();
        } catch (final CardNotPresentException e) {
            cardNotPresentException = e;
            continue;
        } catch (final ApduConnectionException e) {
            apduConnectionException = e;
            continue;
        }
        actualAtr = new Atr(responseAtr, ATR_MASK);
        if (!ATR.equals(actualAtr)) {
            // La tarjeta encontrada no es una CardOS
            invalidCardException = new InvalidCardException(getCardName(), ATR, responseAtr);
            continue;
        }
        return;
    }
    if (invalidCardException != null) {
        throw invalidCardException;
    }
    if (cardNotPresentException != null) {
        throw cardNotPresentException;
    }
    if (apduConnectionException != null) {
        throw apduConnectionException;
    }
    // $NON-NLS-1$
    throw new ApduConnectionException("No se ha podido conectar con ningun lector de tarjetas");
}
Also used : CardNotPresentException(es.gob.jmulticard.apdu.connection.CardNotPresentException) NoReadersFoundException(es.gob.jmulticard.apdu.connection.NoReadersFoundException) Atr(es.gob.jmulticard.card.Atr) InvalidCardException(es.gob.jmulticard.card.InvalidCardException) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException)

Example 27 with ApduConnectionException

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

the class Dnie method getIccCertEncoded.

/**
 * {@inheritDoc}
 */
@Override
public byte[] getIccCertEncoded() throws IOException {
    byte[] iccCertEncoded;
    try {
        selectMasterFile();
        iccCertEncoded = selectFileByIdAndRead(CERT_ICC_FILE_ID);
    } catch (final ApduConnectionException e) {
        throw new IOException(// $NON-NLS-1$
        "Error en el envio de APDU para la seleccion del certificado de componente de la tarjeta: " + e, // $NON-NLS-1$
        e);
    } catch (final Iso7816FourCardException e) {
        // $NON-NLS-1$
        throw new IOException("Error en la seleccion del certificado de componente de la tarjeta: " + e, e);
    }
    return iccCertEncoded;
}
Also used : Iso7816FourCardException(es.gob.jmulticard.card.iso7816four.Iso7816FourCardException) IOException(java.io.IOException) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException)

Example 28 with ApduConnectionException

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

the class Cwa14890OneV1Connection method internalAuthentication.

/**
 * Lleva a cabo el proceso de autenticaci&oacute;n interna de la tarjeta mediante el
 * cual el controlador comprueba la tarjeta.
 * @param randomIfd Array de 8 bytes aleatorios.
 * @param iccPublicKey Clava p&uacute;blica del certificado de componente.
 * @return Semilla de 32 [KICC_LENGTH] bits, generada por la tarjeta, para la derivaci&oacute;n de
 *         claves del canal seguro.
 * @throws SecureChannelException Cuando ocurre un error en el establecimiento de claves.
 * @throws ApduConnectionException Cuando ocurre un error en la comunicaci&oacute;n con la tarjeta.
 * @throws IOException Cuando ocurre un error en el cifrado/descifrado de los mensajes.
 */
private byte[] internalAuthentication(final byte[] randomIfd, final RSAPublicKey iccPublicKey) throws SecureChannelException, ApduConnectionException, IOException {
    // este certificado de Terminal
    try {
        this.card.setKeysToAuthentication(this.card.getChrCCvIfd(this.pubConsts), this.card.getRefIccPrivateKey(this.pubConsts));
    } catch (final Exception e) {
        throw new SecureChannelException(// $NON-NLS-1$
        "Error durante el establecimiento de la clave " + // $NON-NLS-1$
        "publica de Terminal y la privada de componente para su atenticacion", // $NON-NLS-1$
        e);
    }
    // Iniciamos la autenticacion interna de la clave privada del certificado de componente
    final byte[] sigMinCiphered = this.card.getInternalAuthenticateMessage(randomIfd, this.card.getChrCCvIfd(this.pubConsts));
    // Esta respuesta de la tarjeta es un mensaje:
    // - Cifrado con la clave privada de componente de la tarjeta
    // - Al que se le ha aplicado la funcion SIGMIN
    // - Y que se ha cifrado con la clave publica del Terminal
    // Para obtener el mensaje original deberemos deshacer cada una de estas operaciones en
    // sentido inverso.
    // El resultado sera correcto si empieza por el byte 0x6a [ISO_9796_2_PADDING_START] (ISO 9796-2, DS scheme 1) y
    // termina con el byte 0xbc [ISO_9796_2_PADDING_END] (ISO-9796-2, Option 1).
    // -- Descifrado con la clave privada del Terminal
    final byte[] sigMin = this.cryptoHelper.rsaDecrypt(sigMinCiphered, this.card.getIfdPrivateKey(this.privConsts));
    // Este resultado es el resultado de la funcion SIGMIN que es minimo de SIG (los
    // datos sobre los que se ejecuto la funcion) y N.ICC-SIG.
    // Debemos averiguar cual de los dos es. Empezamos por comprobar si es SIG con lo que no
    // habra que deshacer la funcion y podemos descifrar directamente con la clave publica del
    // certificado de componente de la tarjeta.
    final byte[] sig = sigMin;
    byte[] desMsg = this.cryptoHelper.rsaEncrypt(sig, iccPublicKey);
    // Comprobamos que empiece por 0x6a [ISO_9796_2_PADDING_START] y termine con 0xbc [ISO_9796_2_PADDING_END]
    if (desMsg[0] != ISO_9796_2_PADDING_START || desMsg[desMsg.length - 1] != ISO_9796_2_PADDING_END) {
        // Calculamos N.ICC-SIG
        final byte[] sub = iccPublicKey.getModulus().subtract(new BigInteger(sigMin)).toByteArray();
        final byte[] niccMinusSig = new byte[this.card.getIfdKeyLength(this.pubConsts)];
        // Ignoramos los ceros de la izquierda
        if (sub.length > this.card.getIfdKeyLength(this.pubConsts) && sub[0] == (byte) 0x00) {
            System.arraycopy(sub, 1, niccMinusSig, 0, sub.length - 1);
        } else {
            System.arraycopy(sub, 0, niccMinusSig, 0, sub.length);
        }
        // Desciframos el mensaje con N.ICC-SIG
        desMsg = this.cryptoHelper.rsaDecrypt(niccMinusSig, iccPublicKey);
        // la autenticacion interna habra fallado
        if (desMsg[0] != ISO_9796_2_PADDING_START || desMsg[desMsg.length - 1] != ISO_9796_2_PADDING_END) {
            throw new SecureChannelException(// $NON-NLS-1$
            "Error en la autenticacion interna para el establecimiento del canal seguro. " + "El mensaje descifrado es:\n" + // $NON-NLS-1$
            HexUtils.hexify(desMsg, true));
        }
    }
    // -- Descomponemos el resultado anterior en sus partes:
    // Byte 0: Relleno segun ISO 9796-2 (DS scheme 1)
    // Bytes [PRND1] Bytes de relleno aleatorios para completar la longitud de la clave RSA
    // Bytes [Kicc] Semilla de 32 [KICC_LENGTH] bytes generada por la tarjeta para la derivacion de claves
    // Bytes [h: PRND1||Kicc||RND.IFD||SN.IFD] Hash SHA1
    // Ultimo Byte: Relleno segun ISO-9796-2 (option 1)
    final byte[] prnd1 = new byte[this.card.getIfdKeyLength(this.pubConsts) - KICC_LENGTH - SHA1_LENGTH - 2];
    System.arraycopy(desMsg, 1, prnd1, 0, prnd1.length);
    final byte[] kicc = new byte[KICC_LENGTH];
    System.arraycopy(desMsg, prnd1.length + 1, kicc, 0, kicc.length);
    final byte[] hash = new byte[SHA1_LENGTH];
    System.arraycopy(desMsg, prnd1.length + kicc.length + 1, hash, 0, hash.length);
    // -- Calculamos el hash para la comprobacion de la autenticacion, si coincide con el hash
    // extraido en el paso anterior, se confirma que se ha realizado correctamente
    // El hash se calcula a partir de la concatenacion de:
    // - PRND1: Extraido del paso anterior
    // - Kicc: Extraido del paso anterior
    // - RND.IFD: Numero aleatorio generado en pasos anteriores
    // - SN.IFD: CHR del IFD
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    baos.write(prnd1);
    baos.write(kicc);
    baos.write(randomIfd);
    baos.write(this.card.getChrCCvIfd(this.pubConsts));
    final byte[] calculatedHash = this.cryptoHelper.digest(CryptoHelper.DigestAlgorithm.SHA1, baos.toByteArray());
    if (!HexUtils.arrayEquals(hash, calculatedHash)) {
        throw new SecureChannelException(// $NON-NLS-1$
        "Error en la comprobacion de la clave de autenticacion interna. Se obtuvo el hash '" + HexUtils.hexify(calculatedHash, false) + "' cuando se esperaba: '" + HexUtils.hexify(hash, false) + // $NON-NLS-1$ //$NON-NLS-2$
        "'");
    }
    return kicc;
}
Also used : BigInteger(java.math.BigInteger) ByteArrayOutputStream(java.io.ByteArrayOutputStream) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException) IOException(java.io.IOException) CertificateException(java.security.cert.CertificateException)

Example 29 with ApduConnectionException

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

the class Cwa14890OneV1Connection method open.

/**
 * Abre el canal seguro con la tarjeta. La conexi&oacute;n se reiniciar&aacute; previamente
 * a la apertura del canal.
 */
@Override
public void open() throws ApduConnectionException {
    final ApduConnection conn = this.subConnection;
    conn.open();
    // Obtenemos el numero de serie de la tarjeta.
    // IMPORTANTE: Esta operacion debe realizarse antes del inicio del proceso de autenticacion
    final byte[] serial = getPaddedSerial();
    try {
        this.card.verifyCaIntermediateIcc();
        this.card.verifyIcc();
    } catch (final SecurityException e) {
        conn.close();
        throw new IllegalStateException(// $NON-NLS-1$
        "Condicion de seguridad no satisfecha en la validacion de los certificados CWA-14890: " + e);
    } catch (final CertificateException e) {
        conn.close();
        throw new IllegalStateException(// $NON-NLS-1$
        "No se han podido tratar los certificados CWA-14890: " + e);
    } catch (final IOException e) {
        conn.close();
        throw new IllegalStateException(// $NON-NLS-1$
        "No se han podido validar los certificados CWA-14890: " + e);
    }
    // Clave publica del certificado de componente de la tarjeta. Necesario para autenticacion interna
    // y externa
    final RSAPublicKey iccPublicKey;
    try {
        iccPublicKey = (RSAPublicKey) this.cryptoHelper.generateCertificate(this.card.getIccCertEncoded()).getPublicKey();
    } catch (final CertificateException e) {
        conn.close();
        throw new ApduConnectionException(// $NON-NLS-1$
        "No se pudo obtener la clave publica del certificado de componente: " + e, // $NON-NLS-1$
        e);
    } catch (final IOException e) {
        conn.close();
        throw new ApduConnectionException(// $NON-NLS-1$
        "No se pudo leer certificado de componente: " + e, // $NON-NLS-1$
        e);
    }
    // ---------------
    try {
        this.card.verifyIfdCertificateChain(this.pubConsts);
    } catch (final Exception e) {
        conn.close();
        throw new ApduConnectionException(// $NON-NLS-1$
        "Error al verificar la cadena de certificados del controlador: " + e, // $NON-NLS-1$
        e);
    }
    // --- STAGE 3 ---
    // Autenticacion interna (El driver comprueba la tarjeta)
    // ---------------
    final byte[] randomIfd;
    try {
        randomIfd = this.cryptoHelper.generateRandomBytes(8);
    } catch (final IOException e1) {
        conn.close();
        throw new SecureChannelException(// $NON-NLS-1$
        "No se pudo generar el array de aleatorios: " + e1, // $NON-NLS-1$
        e1);
    }
    final byte[] kicc;
    try {
        kicc = this.internalAuthentication(randomIfd, iccPublicKey);
    } catch (final Exception e) {
        conn.close();
        throw new ApduConnectionException(// $NON-NLS-1$
        "Error durante el proceso de autenticacion interna de la tarjeta: " + e, // $NON-NLS-1$
        e);
    }
    // --- STAGE 4 ---
    // Autenticacion externa (La tarjeta comprueba el driver)
    // ---------------
    final byte[] randomIcc = this.card.getChallenge();
    final byte[] kifd;
    try {
        kifd = this.externalAuthentication(serial, randomIcc, iccPublicKey);
    } catch (final Exception e) {
        conn.close();
        throw new ApduConnectionException(// $NON-NLS-1$
        "Error durante el proceso de autenticacion externa de la tarjeta", // $NON-NLS-1$
        e);
    }
    // --- STAGE 5 ---
    // Esta fase no pertenece al procedimiento de apertura del canal seguro (ya esta
    // establecido), sino a la obtencion de las claves necesarias para su control. Estas
    // son:
    // - Kenc: Clave TripleDES (TDES o DESEDE) para encriptar y desencriptar criptogramas.
    // - Kmac: Clave TripleDES (TDES o DESEDE) para calcular y verificar checksums.
    // - SSC: Contador de secuencia.
    // ---------------
    // Calculamos Kifdicc como el XOR de los valores Kifd y Kicc
    final byte[] kidficc = HexUtils.xor(kicc, kifd);
    try {
        this.kenc = generateKenc(kidficc);
    } catch (final IOException e) {
        conn.close();
        throw new ApduConnectionException(// $NON-NLS-1$
        "Error al generar la clave Kenc para el tratamiento del canal seguro", // $NON-NLS-1$
        e);
    }
    try {
        this.kmac = generateKmac(kidficc);
    } catch (final IOException e) {
        conn.close();
        throw new ApduConnectionException(// $NON-NLS-1$
        "Error al generar la clave Kmac para el tratamiento del canal seguro", // $NON-NLS-1$
        e);
    }
    this.ssc = generateSsc(randomIfd, randomIcc);
    this.openState = true;
}
Also used : RSAPublicKey(java.security.interfaces.RSAPublicKey) CertificateException(java.security.cert.CertificateException) IOException(java.io.IOException) ApduConnection(es.gob.jmulticard.apdu.connection.ApduConnection) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException) ApduConnectionException(es.gob.jmulticard.apdu.connection.ApduConnectionException) IOException(java.io.IOException) CertificateException(java.security.cert.CertificateException)

Example 30 with ApduConnectionException

use of es.gob.jmulticard.apdu.connection.ApduConnectionException 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&oacute;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)

Aggregations

ApduConnectionException (es.gob.jmulticard.apdu.connection.ApduConnectionException)38 ResponseApdu (es.gob.jmulticard.apdu.ResponseApdu)21 IOException (java.io.IOException)16 CommandApdu (es.gob.jmulticard.apdu.CommandApdu)14 PinException (es.gob.jmulticard.card.PinException)14 BadPinException (es.gob.jmulticard.card.BadPinException)13 CryptoCardException (es.gob.jmulticard.card.CryptoCardException)13 Iso7816FourCardException (es.gob.jmulticard.card.iso7816four.Iso7816FourCardException)12 CertificateException (java.security.cert.CertificateException)10 AuthenticationModeLockedException (es.gob.jmulticard.card.AuthenticationModeLockedException)9 CardNotPresentException (es.gob.jmulticard.apdu.connection.CardNotPresentException)7 LostChannelException (es.gob.jmulticard.apdu.connection.LostChannelException)7 InvalidCardException (es.gob.jmulticard.card.InvalidCardException)7 NoReadersFoundException (es.gob.jmulticard.apdu.connection.NoReadersFoundException)6 UnsupportedCallbackException (javax.security.auth.callback.UnsupportedCallbackException)6 ApduConnection (es.gob.jmulticard.apdu.connection.ApduConnection)5 Cwa14890Connection (es.gob.jmulticard.apdu.connection.cwa14890.Cwa14890Connection)5 TlvException (es.gob.jmulticard.asn1.TlvException)5 SecureChannelException (es.gob.jmulticard.apdu.connection.cwa14890.SecureChannelException)4 Asn1Exception (es.gob.jmulticard.asn1.Asn1Exception)4