use of es.gob.jmulticard.apdu.CommandApdu in project jmulticard by ctt-gob-es.
the class StCard method verifyPin.
@Override
public void verifyPin(final PasswordCallback pinPc) throws ApduConnectionException, PinException {
if (pinPc == null) {
// $NON-NLS-1$
throw new BadPinException("No se ha establecido un PasswordCallback");
}
final CommandApdu chv = new VerifyApduCommand(CLA, pinPc);
final ResponseApdu verifyResponse = sendArbitraryApdu(chv);
if (!verifyResponse.isOk()) {
if (verifyResponse.getStatusWord().getMsb() == ERROR_PIN_SW1) {
throw new BadPinException(verifyResponse.getStatusWord().getLsb() - (byte) 0xC0);
}
throw new ApduConnectionException(// $NON-NLS-1$
"Error en el envio de la verificacion de PIN con respuesta: " + verifyResponse.getStatusWord());
}
}
use of es.gob.jmulticard.apdu.CommandApdu in project jmulticard by ctt-gob-es.
the class CeresSc method signOperation.
@Override
protected byte[] signOperation(final byte[] data, final String algorithm, final PrivateKeyReference privateKeyReference) throws CryptoCardException, PinException {
openSecureChannelIfNotAlreadyOpened();
ResponseApdu res;
try {
CommandApdu apdu = new MseSetComputationApduCommand((byte) 0x00, ((DniePrivateKeyReference) privateKeyReference).getKeyPath().getLastFilePath(), null);
res = getConnection().transmit(apdu);
if (!res.isOk()) {
throw new DnieCardException(// $NON-NLS-1$
"Error en el establecimiento de las clave de firma con respuesta: " + res.getStatusWord(), // $NON-NLS-1$
res.getStatusWord());
}
final byte[] digestInfo;
try {
digestInfo = DigestInfo.encode(algorithm, data, this.cryptoHelper);
} catch (final IOException e) {
// $NON-NLS-1$
throw new DnieCardException("Error en el calculo del hash para firmar: " + e, e);
}
apdu = new PsoSignHashApduCommand((byte) 0x00, digestInfo);
res = getConnection().transmit(apdu);
if (!res.isOk()) {
throw new DnieCardException(// $NON-NLS-1$
"Error durante la operacion de firma con respuesta: " + res.getStatusWord(), // $NON-NLS-1$
res.getStatusWord());
}
} catch (final LostChannelException e) {
try {
getConnection().close();
if (getConnection() instanceof Cwa14890Connection) {
setConnection(((Cwa14890Connection) getConnection()).getSubConnection());
}
} catch (final Exception ex) {
// $NON-NLS-1$
throw new DnieCardException("No se pudo recuperar el canal seguro para firmar: " + ex, ex);
}
return signOperation(data, algorithm, privateKeyReference);
} catch (final ApduConnectionException e) {
// $NON-NLS-1$
throw new DnieCardException("Error en la transmision de comandos a la tarjeta: " + e, e);
}
return res.getData();
}
use of es.gob.jmulticard.apdu.CommandApdu in project jmulticard by ctt-gob-es.
the class CardOS method preloadCertificates.
private void preloadCertificates() throws FileNotFoundException, Iso7816FourCardException, IOException, Asn1Exception, TlvException {
// Entramos en el directorio PKCS#15
selectFileByName(PKCS15_NAME);
// Seleccionamos el ODF, no nos devuelve FCI ni nada
selectFileById(new byte[] { (byte) 0x50, (byte) 0x31 });
// Leemos el ODF, que tiene esta estructura en cada uno de sus registros:
// PKCS15Objects ::= CHOICE {
// privateKeys [0] PrivateKeys,
// publicKeys [1] PublicKeys,
// trustedPublicKeys [2] PublicKeys,
// secretKeys [3] SecretKeys,
// certificates [4] Certificates,
// trustedCertificates [5] Certificates,
// usefulCertificates [6] Certificates,
// dataObjects [7] DataObjects,
// authObjects [8] AuthObjects,
// ... -- For future extensions
// }
// A2
final byte[] odfBytes = readBinaryComplete(162);
final Odf odf = new Odf();
odf.setDerValue(odfBytes);
// Sacamos del ODF la ruta del CDF
final Path cdfPath = odf.getCdfPath();
// Seleccionamos el CDF
selectFileById(cdfPath.getPathBytes());
// Leemos el CDF mediante registros
final List<byte[]> cdfRecords = readAllRecords();
final CertificateFactory cf;
try {
// $NON-NLS-1$
cf = CertificateFactory.getInstance("X.509");
} catch (final CertificateException e1) {
throw new IllegalStateException(// $NON-NLS-1$
"No se ha podido obtener la factoria de certificados X.509: " + e1, // $NON-NLS-1$
e1);
}
CertificateObject co;
for (final byte[] b : cdfRecords) {
try {
co = new CertificateObject();
co.setDerValue(HexUtils.subArray(b, 2, b.length - 2));
} catch (final Exception e) {
// $NON-NLS-1$
LOGGER.warning("Omitido registro de certificado por no ser un CertificateObject de PKCS#15: " + e);
continue;
}
final byte[] certPath = co.getPathBytes();
if (certPath == null || certPath.length != 4) {
// $NON-NLS-1$
LOGGER.warning("Se omite una posicion de certificado porque su ruta no es de cuatro octetos: " + co.getAlias());
continue;
}
final byte[] MASTER_FILE = new byte[] { (byte) 0x50, (byte) 0x15 };
sendArbitraryApdu(new CommandApdu(// CLA
getCla(), // INS
(byte) 0xA4, // P1
(byte) 0x08, // P2
(byte) 0x0C, new byte[] { MASTER_FILE[0], MASTER_FILE[1], certPath[0], certPath[1], certPath[2], certPath[3] }, null));
final byte[] certBytes = readBinaryComplete(9999);
final X509Certificate cert;
try {
cert = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certBytes));
} catch (final CertificateException e) {
LOGGER.severe(// $NON-NLS-1$ //$NON-NLS-2$
"No ha sido posible generar el certificado para el alias " + co.getAlias() + ": " + e);
continue;
}
certificatesByAlias.put(co.getAlias(), cert);
}
}
use of es.gob.jmulticard.apdu.CommandApdu in project jmulticard by ctt-gob-es.
the class Dnie method setKeysToAuthentication.
/**
* {@inheritDoc}
*/
@Override
public void setKeysToAuthentication(final byte[] refPublicKey, final byte[] refPrivateKey) throws ApduConnectionException {
final CommandApdu apdu = new MseSetAuthenticationKeyApduCommand((byte) 0x00, refPublicKey, refPrivateKey);
final ResponseApdu res = getConnection().transmit(apdu);
if (!res.isOk()) {
throw new SecureChannelException(// $NON-NLS-1$
"Error durante el establecimiento de las claves publica y privada " + "para atenticacion (error: " + HexUtils.hexify(res.getBytes(), true) + // $NON-NLS-1$ //$NON-NLS-2$
")");
}
}
use of es.gob.jmulticard.apdu.CommandApdu 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ón hacia la tarjeta inteligente.
* @param cryptoHelper Clase para la realización de operaciones criptográficas auxiliares.
* @return SecureMessaging Objeto para el envío de mensajes seguros a través de canal PACE.
* @throws ApduConnectionException Si hay problemas de conexió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()]);
}
Aggregations